diff --git a/background.html b/background.html index bae48040b..f29d0177e 100644 --- a/background.html +++ b/background.html @@ -32,6 +32,8 @@ --> + + @@ -365,6 +373,8 @@
+
+
diff --git a/main.js b/main.js index a14f1bb6f..e1aa5286e 100644 --- a/main.js +++ b/main.js @@ -97,8 +97,16 @@ const { installWebHandler, } = require('./app/protocol_filter'); const { installPermissionsHandler } = require('./app/permissions'); +const OS = require('./ts/OS'); const { isBeta } = require('./ts/util/version'); const { isSgnlHref, parseSgnlHref } = require('./ts/util/sgnlHref'); +const { + toggleMaximizedBrowserWindow, +} = require('./ts/util/toggleMaximizedBrowserWindow'); +const { + getTitleBarVisibility, + TitleBarVisibility, +} = require('./ts/types/Settings'); let appStartInitialSpellcheckSetting = true; @@ -268,11 +276,10 @@ function isVisible(window, bounds) { } let windowIcon; -const OS = process.platform; -if (OS === 'win32') { +if (OS.isWindows()) { windowIcon = path.join(__dirname, 'build', 'icons', 'win', 'icon.ico'); -} else if (OS === 'linux') { +} else if (OS.isLinux()) { windowIcon = path.join(__dirname, 'images', 'signal-logo-desktop-linux.png'); } else { windowIcon = path.join(__dirname, 'build', 'icons', 'png', '512x512.png'); @@ -287,6 +294,10 @@ async function createWindow() { minWidth: MIN_WIDTH, minHeight: MIN_HEIGHT, autoHideMenuBar: false, + titleBarStyle: + getTitleBarVisibility() === TitleBarVisibility.Hidden + ? 'hidden' + : 'default', backgroundColor: config.environment === 'test' || config.environment === 'test-lib' ? '#ffffff' // Tests should always be rendered on a white background @@ -383,14 +394,18 @@ async function createWindow() { // This is a fallback in case we drop an event for some reason. setInterval(setWindowFocus, 10000); + const moreKeys = { + isFullScreen: String(Boolean(mainWindow.isFullScreen())), + }; + if (config.environment === 'test') { - mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html'])); + mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html'], moreKeys)); } else if (config.environment === 'test-lib') { mainWindow.loadURL( - prepareURL([__dirname, 'libtextsecure', 'test', 'index.html']) + prepareURL([__dirname, 'libtextsecure', 'test', 'index.html'], moreKeys) ); } else { - mainWindow.loadURL(prepareURL([__dirname, 'background.html'])); + mainWindow.loadURL(prepareURL([__dirname, 'background.html'], moreKeys)); } if (config.get('openDevTools')) { @@ -440,10 +455,7 @@ async function createWindow() { // On Mac, or on other platforms when the tray icon is in use, the window // should be only hidden, not closed, when the user clicks the close button - if ( - !windowState.shouldQuit() && - (usingTrayIcon || process.platform === 'darwin') - ) { + if (!windowState.shouldQuit() && (usingTrayIcon || OS.isMacOS())) { // toggle the visibility of the show/hide tray icon menu entries if (tray) { tray.updateContextMenu(); @@ -471,12 +483,46 @@ async function createWindow() { // when you should delete the corresponding element. mainWindow = null; }); + + mainWindow.on('enter-full-screen', () => { + mainWindow.webContents.send('full-screen-change', true); + }); + mainWindow.on('leave-full-screen', () => { + mainWindow.webContents.send('full-screen-change', false); + }); } ipc.on('show-window', () => { showWindow(); }); +ipc.on('title-bar-double-click', () => { + if (!mainWindow) { + return; + } + + if (OS.isMacOS()) { + switch ( + systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string') + ) { + case 'Minimize': + mainWindow.minimize(); + break; + case 'Maximize': + toggleMaximizedBrowserWindow(mainWindow); + break; + default: + // If this is disabled, it'll be 'None'. If it's anything else, that's unexpected, + // but we'll just no-op. + break; + } + } else { + // This is currently only supported on macOS. This `else` branch is just here when/if + // we add support for other operating systems. + toggleMaximizedBrowserWindow(mainWindow); + } +}); + let isReadyForUpdates = false; async function readyForUpdates() { if (isReadyForUpdates) { @@ -886,7 +932,7 @@ app.on('ready', async () => { protocol: electronProtocol, userDataPath, installPath, - isWindows: process.platform === 'win32', + isWindows: OS.isWindows(), }); } @@ -1138,7 +1184,7 @@ app.on('window-all-closed', () => { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q const shouldAutoClose = - process.platform !== 'darwin' || + !OS.isMacOS() || config.environment === 'test' || config.environment === 'test-lib'; @@ -1203,7 +1249,7 @@ ipc.on('draw-attention', () => { return; } - if (process.platform === 'win32' || process.platform === 'linux') { + if (OS.isWindows() || OS.isLinux()) { mainWindow.flashFrame(true); } }); @@ -1232,7 +1278,7 @@ ipc.on('close-about', () => { if (aboutWindow) { // Exiting child window when on full screen mode (MacOs only) hides the main window // Fix to issue #4540 - if (mainWindow.isFullScreen() && process.platform === 'darwin') { + if (mainWindow.isFullScreen() && OS.isMacOS()) { mainWindow.setFullScreen(false); mainWindow.show(); mainWindow.setFullScreen(true); diff --git a/preload.js b/preload.js index bbc45422b..e659ba6c5 100644 --- a/preload.js +++ b/preload.js @@ -113,6 +113,10 @@ try { ipc.send('show-window'); }; + window.titleBarDoubleClick = () => { + ipc.send('title-bar-double-click'); + }; + window.setAutoHideMenuBar = autoHide => ipc.send('set-auto-hide-menu-bar', autoHide); @@ -142,6 +146,19 @@ try { Whisper.events.trigger('setupAsStandalone'); }); + { + let isFullScreen = config.isFullScreen === 'true'; + + window.isFullScreen = () => isFullScreen; + // This is later overwritten. + window.onFullScreenChange = _.noop; + + ipc.on('full-screen-change', (_event, isFull) => { + isFullScreen = Boolean(isFull); + window.onFullScreenChange(isFullScreen); + }); + } + // Settings-related events window.showSettings = () => ipc.send('show-settings'); diff --git a/stylesheets/_conversation.scss b/stylesheets/_conversation.scss index fc0b45836..d06d23e12 100644 --- a/stylesheets/_conversation.scss +++ b/stylesheets/_conversation.scss @@ -31,14 +31,13 @@ } .panel { - height: calc(100% - #{$header-height}); + height: calc(100% - #{$header-height} - var(--title-bar-drag-area-height)); overflow-y: scroll; z-index: 1; position: absolute; left: 0; - top: $header-height; + top: calc(#{$header-height} + var(--title-bar-drag-area-height)); width: 100%; - height: calc(100% - $header-height); @include light-theme() { background-color: $color-white; diff --git a/stylesheets/_global.scss b/stylesheets/_global.scss index 8ca6bd336..b8b1fff9d 100644 --- a/stylesheets/_global.scss +++ b/stylesheets/_global.scss @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Signal Messenger, LLC +// Copyright 2015-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only html { @@ -15,6 +15,15 @@ body { color: $color-gray-90; @include font-body-1; + + // These should match the logic in `ts/types/Settings.ts`'s `getTitleBarVisibility`. + // + // It'd be great if we could use the `:fullscreen` selector here, but that does not seem + // to work with Electron, at least on macOS. + --title-bar-drag-area-height: 0px; // Needs to have a unit to work with `calc()`. + &.os-macos:not(.full-screen) { + --title-bar-drag-area-height: 28px; + } } body.light-theme { diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 9a7031aee..6f6d8b178 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -3,6 +3,16 @@ // Using BEM syntax explained here: https://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/ +.module-title-bar-drag-area { + -webkit-app-region: drag; + height: var(--title-bar-drag-area-height); + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index: 999; +} + .module-splash-screen { display: flex; flex-direction: column; @@ -2839,11 +2849,12 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05', .module-conversation-header { padding-left: 16px; padding-right: 16px; + padding-top: var(--title-bar-drag-area-height); display: flex; flex-direction: row; align-items: center; - height: $header-height; + height: calc(#{$header-height} + var(--title-bar-drag-area-height)); @include light-theme { color: $color-gray-90; @@ -4788,11 +4799,12 @@ button.module-conversation-details__action-button { // Module: Main Header .module-main-header { - height: $header-height; + height: calc(#{$header-height} + var(--title-bar-drag-area-height)); width: 100%; padding-left: 16px; padding-right: 16px; + padding-top: var(--title-bar-drag-area-height); display: flex; flex-direction: row; @@ -6470,7 +6482,7 @@ button.module-image__border-overlay:focus { color: #ffffff; font-style: normal; padding-bottom: 24px; - padding-top: 24px; + padding-top: calc(24px + var(--title-bar-drag-area-height)); text-align: center; text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25); width: 100%; @@ -7190,7 +7202,7 @@ button.module-image__border-overlay:focus { display: flex; justify-content: flex-end; position: absolute; - top: 24px; + top: calc(24px + var(--title-bar-drag-area-height)); width: 100%; &__button { @@ -7537,12 +7549,13 @@ button.module-image__border-overlay:focus { } .module-left-pane__archive-header { - height: $header-height; + height: calc(#{$header-height} + var(--title-bar-drag-area-height)); width: 100%; display: inline-flex; flex-direction: row; align-items: center; + padding-top: var(--title-bar-drag-area-height); } .module-left-pane__header-row { diff --git a/test/index.html b/test/index.html index f2b3930ea..a95268288 100644 --- a/test/index.html +++ b/test/index.html @@ -14,6 +14,8 @@