From 8ff64d285ae4c01a53c7abac662d5474f08e4007 Mon Sep 17 00:00:00 2001
From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>
Date: Wed, 31 Jul 2024 14:58:33 -0400
Subject: [PATCH] [MM-59841] Migrate to `titleBarOverlay` for Windows (#3111)
---
src/assets/titlebar/chrome-close.svg | 3 -
src/assets/titlebar/chrome-maximize.svg | 3 -
src/assets/titlebar/chrome-minimize.svg | 3 -
src/assets/titlebar/chrome-restore.svg | 3 -
src/common/communication.ts | 5 +-
src/common/config/index.test.js | 4 --
src/common/config/index.ts | 10 +--
src/main/app/initialize.ts | 12 ----
src/main/app/windows.ts | 14 ----
src/main/preload/internalAPI.js | 10 +--
src/main/windows/mainWindow.ts | 35 +++-------
src/renderer/components/MainPage.tsx | 90 +++++--------------------
src/renderer/css/index.css | 28 +-------
src/renderer/index.tsx | 1 -
src/types/config.ts | 1 -
src/types/window.ts | 5 +-
16 files changed, 33 insertions(+), 194 deletions(-)
delete mode 100644 src/assets/titlebar/chrome-close.svg
delete mode 100644 src/assets/titlebar/chrome-maximize.svg
delete mode 100644 src/assets/titlebar/chrome-minimize.svg
delete mode 100644 src/assets/titlebar/chrome-restore.svg
diff --git a/src/assets/titlebar/chrome-close.svg b/src/assets/titlebar/chrome-close.svg
deleted file mode 100644
index cb148f5a..00000000
--- a/src/assets/titlebar/chrome-close.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/titlebar/chrome-maximize.svg b/src/assets/titlebar/chrome-maximize.svg
deleted file mode 100644
index 0d991756..00000000
--- a/src/assets/titlebar/chrome-maximize.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/titlebar/chrome-minimize.svg b/src/assets/titlebar/chrome-minimize.svg
deleted file mode 100644
index 62f72c70..00000000
--- a/src/assets/titlebar/chrome-minimize.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/titlebar/chrome-restore.svg b/src/assets/titlebar/chrome-restore.svg
deleted file mode 100644
index 7dc8f55b..00000000
--- a/src/assets/titlebar/chrome-restore.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/common/communication.ts b/src/common/communication.ts
index 841d7b92..d1cc0a8b 100644
--- a/src/common/communication.ts
+++ b/src/common/communication.ts
@@ -45,10 +45,7 @@ export const MODAL_RESULT = 'modal-result';
export const MODAL_OPEN = 'modal-open';
export const MODAL_CLOSE = 'modal-close';
export const NOTIFY_MENTION = 'notify_mention';
-export const WINDOW_CLOSE = 'window_close';
-export const WINDOW_MINIMIZE = 'window_minimize';
-export const WINDOW_MAXIMIZE = 'window_maximize';
-export const WINDOW_RESTORE = 'window_restore';
+export const EXIT_FULLSCREEN = 'exit-fullscreen';
export const GET_FULL_SCREEN_STATUS = 'get-full-screen-status';
export const UPDATE_TARGET_URL = 'update_target_url';
diff --git a/src/common/config/index.test.js b/src/common/config/index.test.js
index 7f106682..8caaaf50 100644
--- a/src/common/config/index.test.js
+++ b/src/common/config/index.test.js
@@ -319,7 +319,6 @@ describe('common/config', () => {
const config = new Config();
config.reload = jest.fn();
config.init(configPath, appName, appPath);
- config.useNativeWindow = false;
config.defaultConfigData = {defaultSetting: 'default', otherDefaultSetting: 'default'};
config.localConfigData = {otherDefaultSetting: 'local', localSetting: 'local', otherLocalSetting: 'local'};
config.buildConfigData = {otherLocalSetting: 'build', buildSetting: 'build', otherBuildSetting: 'build'};
@@ -329,7 +328,6 @@ describe('common/config', () => {
config.combinedData.darkMode = false;
expect(config.combinedData).toStrictEqual({
appName: 'app-name',
- useNativeWindow: false,
darkMode: false,
otherBuildSetting: 'registry',
registrySetting: 'registry',
@@ -350,7 +348,6 @@ describe('common/config', () => {
config.buildConfigData = {enableServerManagement: true};
config.registryConfigData = {};
config.predefinedServers.push(server, server);
- config.useNativeWindow = false;
config.localConfigData = {teams: [
server,
{
@@ -370,7 +367,6 @@ describe('common/config', () => {
config.combinedData.darkMode = false;
expect(config.combinedData).toStrictEqual({
appName: 'app-name',
- useNativeWindow: false,
darkMode: false,
enableServerManagement: true,
});
diff --git a/src/common/config/index.ts b/src/common/config/index.ts
index 5baa4f0c..07ee14eb 100644
--- a/src/common/config/index.ts
+++ b/src/common/config/index.ts
@@ -2,13 +2,12 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import fs from 'fs';
-import os from 'os';
import path from 'path';
import {EventEmitter} from 'events';
import {Logger} from 'common/log';
-import Utils, {copy} from 'common/utils/util';
+import {copy} from 'common/utils/util';
import * as Validator from 'common/Validator';
import {getDefaultViewsForConfigServer} from 'common/views/View';
@@ -36,7 +35,6 @@ export class Config extends EventEmitter {
private registryConfig: RegistryConfig;
private _predefinedServers: ConfigServer[];
- private useNativeWindow: boolean;
private combinedData?: CombinedConfig;
private localConfigData?: ConfigType;
@@ -52,11 +50,6 @@ export class Config extends EventEmitter {
if (buildConfig.defaultServers) {
this._predefinedServers.push(...buildConfig.defaultServers.map((server, index) => getDefaultViewsForConfigServer({...server, order: index})));
}
- try {
- this.useNativeWindow = os.platform() === 'win32' && !Utils.isVersionGreaterThanOrEqualTo(os.release(), '6.2');
- } catch {
- this.useNativeWindow = false;
- }
}
init = (configFilePath: string, appName: string, appPath: string) => {
@@ -370,7 +363,6 @@ export class Config extends EventEmitter {
this.localConfigData,
this.buildConfigData,
this.registryConfigData,
- {useNativeWindow: this.useNativeWindow},
);
// We don't want to include the servers in the combined config, they should only be accesible via the ServerManager
diff --git a/src/main/app/initialize.ts b/src/main/app/initialize.ts
index 387df0d8..637bbb48 100644
--- a/src/main/app/initialize.ts
+++ b/src/main/app/initialize.ts
@@ -25,10 +25,6 @@ import {
UPDATE_PATHS,
SERVERS_URL_MODIFIED,
GET_DARK_MODE,
- WINDOW_CLOSE,
- WINDOW_MAXIMIZE,
- WINDOW_MINIMIZE,
- WINDOW_RESTORE,
DOUBLE_CLICK_ON_WINDOW,
TOGGLE_SECURE_INPUT,
GET_APP_INFO,
@@ -97,12 +93,8 @@ import {
flushCookiesStore,
} from './utils';
import {
- handleClose,
handleDoubleClick,
handleGetDarkMode,
- handleMaximize,
- handleMinimize,
- handleRestore,
} from './windows';
import {protocols} from '../../../electron-builder.json';
@@ -283,10 +275,6 @@ function initializeInterCommunicationEventListeners() {
ipcMain.on(UPDATE_CONFIGURATION, updateConfiguration);
ipcMain.handle(GET_DARK_MODE, handleGetDarkMode);
- ipcMain.on(WINDOW_CLOSE, handleClose);
- ipcMain.on(WINDOW_MAXIMIZE, handleMaximize);
- ipcMain.on(WINDOW_MINIMIZE, handleMinimize);
- ipcMain.on(WINDOW_RESTORE, handleRestore);
ipcMain.on(DOUBLE_CLICK_ON_WINDOW, handleDoubleClick);
ipcMain.on(TOGGLE_SECURE_INPUT, handleToggleSecureInput);
diff --git a/src/main/app/windows.ts b/src/main/app/windows.ts
index 246f4e6d..57cfdd69 100644
--- a/src/main/app/windows.ts
+++ b/src/main/app/windows.ts
@@ -13,20 +13,6 @@ export const handleGetDarkMode = () => {
return Config.darkMode;
};
-export const handleClose = (event: IpcMainEvent) => BrowserWindow.fromWebContents(event.sender)?.close();
-export const handleMaximize = (event: IpcMainEvent) => BrowserWindow.fromWebContents(event.sender)?.maximize();
-export const handleMinimize = (event: IpcMainEvent) => BrowserWindow.fromWebContents(event.sender)?.minimize();
-export const handleRestore = (event: IpcMainEvent) => {
- const window = BrowserWindow.fromWebContents(event.sender);
- if (!window) {
- return;
- }
- window.restore();
- if (window.isFullScreen()) {
- window.setFullScreen(false);
- }
-};
-
export const handleDoubleClick = (event: IpcMainEvent, windowType?: string) => {
log.debug('handleDoubleClick', windowType);
diff --git a/src/main/preload/internalAPI.js b/src/main/preload/internalAPI.js
index 72cb2d7d..161f3b59 100644
--- a/src/main/preload/internalAPI.js
+++ b/src/main/preload/internalAPI.js
@@ -14,10 +14,7 @@ import {
OPEN_SERVERS_DROPDOWN,
SWITCH_TAB,
CLOSE_VIEW,
- WINDOW_CLOSE,
- WINDOW_MINIMIZE,
- WINDOW_MAXIMIZE,
- WINDOW_RESTORE,
+ EXIT_FULLSCREEN,
DOUBLE_CLICK_ON_WINDOW,
FOCUS_BROWSERVIEW,
RELOAD_CURRENT_VIEW,
@@ -117,10 +114,7 @@ contextBridge.exposeInMainWorld('desktop', {
openServersDropdown: () => ipcRenderer.send(OPEN_SERVERS_DROPDOWN),
switchTab: (viewId) => ipcRenderer.send(SWITCH_TAB, viewId),
closeView: (viewId) => ipcRenderer.send(CLOSE_VIEW, viewId),
- closeWindow: () => ipcRenderer.send(WINDOW_CLOSE),
- minimizeWindow: () => ipcRenderer.send(WINDOW_MINIMIZE),
- maximizeWindow: () => ipcRenderer.send(WINDOW_MAXIMIZE),
- restoreWindow: () => ipcRenderer.send(WINDOW_RESTORE),
+ exitFullScreen: () => ipcRenderer.send(EXIT_FULLSCREEN),
doubleClickOnWindow: (windowName) => ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW, windowName),
focusCurrentView: () => ipcRenderer.send(FOCUS_BROWSERVIEW),
reloadCurrentView: () => ipcRenderer.send(RELOAD_CURRENT_VIEW),
diff --git a/src/main/windows/mainWindow.ts b/src/main/windows/mainWindow.ts
index b88ca94e..074036ef 100644
--- a/src/main/windows/mainWindow.ts
+++ b/src/main/windows/mainWindow.ts
@@ -18,13 +18,13 @@ import {
SERVERS_UPDATE,
UPDATE_APPSTATE_FOR_VIEW_ID,
UPDATE_MENTIONS,
- MAXIMIZE_CHANGE,
MAIN_WINDOW_CREATED,
MAIN_WINDOW_RESIZED,
MAIN_WINDOW_FOCUSED,
VIEW_FINISHED_RESIZING,
TOGGLE_SECURE_INPUT,
EMIT_CONFIGURATION,
+ EXIT_FULLSCREEN,
} from 'common/communication';
import Config from 'common/config';
import {Logger} from 'common/log';
@@ -50,7 +50,6 @@ export class MainWindow extends EventEmitter {
private ready: boolean;
private isResizing: boolean;
private lastEmittedBounds?: Electron.Rectangle;
- private isMaximized: boolean;
constructor() {
super();
@@ -58,11 +57,11 @@ export class MainWindow extends EventEmitter {
// Create the browser window.
this.ready = false;
this.isResizing = false;
- this.isMaximized = false;
ipcMain.handle(GET_FULL_SCREEN_STATUS, () => this.win?.isFullScreen());
ipcMain.on(VIEW_FINISHED_RESIZING, this.handleViewFinishedResizing);
ipcMain.on(EMIT_CONFIGURATION, this.handleUpdateTitleBarOverlay);
+ ipcMain.on(EXIT_FULLSCREEN, this.handleExitFullScreen);
ServerManager.on(SERVERS_UPDATE, this.handleUpdateConfig);
@@ -83,7 +82,7 @@ export class MainWindow extends EventEmitter {
frame: !this.isFramelessWindow(),
fullscreen: this.shouldStartFullScreen(),
titleBarStyle: 'hidden' as const,
- titleBarOverlay: process.platform === 'linux' ? this.getTitleBarOverlay() : false,
+ titleBarOverlay: this.getTitleBarOverlay(),
trafficLightPosition: {x: 12, y: 12},
backgroundColor: '#fff', // prevents blurry text: https://electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
webPreferences: {
@@ -129,9 +128,6 @@ export class MainWindow extends EventEmitter {
this.win.on('focus', this.onFocus);
this.win.on('blur', this.onBlur);
this.win.on('unresponsive', this.onUnresponsive);
- this.win.on('maximize', this.onMaximize);
- this.win.on('unmaximize', this.onUnmaximize);
- this.win.on('restore', this.onRestore);
this.win.on('enter-full-screen', this.onEnterFullScreen);
this.win.on('leave-full-screen', this.onLeaveFullScreen);
this.win.on('will-resize', this.onWillResize);
@@ -252,6 +248,7 @@ export class MainWindow extends EventEmitter {
private getTitleBarOverlay = () => {
return {
color: Config.darkMode ? '#2e2e2e' : '#efefef',
+ symbolColor: Config.darkMode ? '#c1c1c1' : '#474747',
height: TAB_BAR_HEIGHT,
};
};
@@ -465,24 +462,6 @@ export class MainWindow extends EventEmitter {
}, 10);
};
- private onMaximize = () => {
- this.isMaximized = true;
- this.win?.webContents.send(MAXIMIZE_CHANGE, true);
- this.emitBounds();
- };
-
- private onUnmaximize = () => {
- this.isMaximized = false;
- this.win?.webContents.send(MAXIMIZE_CHANGE, false);
- this.emitBounds();
- };
-
- private onRestore = () => {
- if (this.isMaximized && !this.win?.isMaximized()) {
- this.win?.maximize();
- }
- };
-
private onEnterFullScreen = () => {
this.win?.webContents.send('enter-full-screen');
this.emitBounds();
@@ -544,6 +523,12 @@ export class MainWindow extends EventEmitter {
this.isResizing = false;
};
+ private handleExitFullScreen = () => {
+ if (this.win?.isFullScreen()) {
+ this.win.setFullScreen(false);
+ }
+ };
+
/**
* Server Manager update handler
*/
diff --git a/src/renderer/components/MainPage.tsx b/src/renderer/components/MainPage.tsx
index 2bafaa70..536b9727 100644
--- a/src/renderer/components/MainPage.tsx
+++ b/src/renderer/components/MainPage.tsx
@@ -18,10 +18,6 @@ import ExtraBar from './ExtraBar';
import ServerDropdownButton from './ServerDropdownButton';
import TabBar from './TabBar';
-import closeButton from '../../assets/titlebar/chrome-close.svg';
-import maximizeButton from '../../assets/titlebar/chrome-maximize.svg';
-import minimizeButton from '../../assets/titlebar/chrome-minimize.svg';
-import restoreButton from '../../assets/titlebar/chrome-restore.svg';
import {playSound} from '../notificationSounds';
import '../css/components/UpgradeButton.scss';
@@ -38,7 +34,6 @@ type Props = {
openMenu: () => void;
darkMode: boolean;
appName: string;
- useNativeWindow: boolean;
intl: IntlShape;
};
@@ -326,23 +321,13 @@ class MainPage extends React.PureComponent {
this.handleSelectTab(tab[0].id!);
};
- handleClose = (e: React.MouseEvent) => {
+ handleExitFullScreen = (e: React.MouseEvent) => {
e.stopPropagation(); // since it is our button, the event goes into MainPage's onclick event, getting focus back.
- window.desktop.closeWindow();
- };
- handleMinimize = (e: React.MouseEvent) => {
- e.stopPropagation();
- window.desktop.minimizeWindow();
- };
-
- handleMaximize = (e: React.MouseEvent) => {
- e.stopPropagation();
- window.desktop.maximizeWindow();
- };
-
- handleRestore = () => {
- window.desktop.restoreWindow();
+ if (!this.state.fullScreen) {
+ return;
+ }
+ window.desktop.exitFullScreen();
};
openMenu = () => {
@@ -430,60 +415,6 @@ class MainPage extends React.PureComponent {
/>
) : null;
- let maxButton;
- if (this.state.maximized || this.state.fullScreen) {
- maxButton = (
-
-
-
- );
- } else {
- maxButton = (
-
-
-
- );
- }
-
- let titleBarButtons;
- if (window.process.platform === 'win32' && !this.props.useNativeWindow) {
- titleBarButtons = (
-
-
-
-
- {maxButton}
-
-
-
-
- );
- }
-
const totalMentionCount = Object.keys(this.state.mentionCounts).reduce((sum, key) => {
// Strip out current server from unread and mention counts
if (this.state.tabs.get(this.state.activeServerId!)?.map((tab) => tab.id).includes(key)) {
@@ -541,7 +472,16 @@ class MainPage extends React.PureComponent {
)}
{tabsRow}
{downloadsDropdownButton}
- {titleBarButtons}
+ {window.process.platform !== 'darwin' && this.state.fullScreen &&
+
+
+
+
+
+ }
);
diff --git a/src/renderer/css/index.css b/src/renderer/css/index.css
index 3605a68a..24a2286a 100644
--- a/src/renderer/css/index.css
+++ b/src/renderer/css/index.css
@@ -176,23 +176,8 @@ body {
background: rgba(0,0,0,0.2);
}
-.topBar .title-bar-btns>.close-button:hover {
- background: #E81123 !important;
-}
-
-.topBar .title-bar-btns>.close-button:hover>img {
- filter: invert(100%);
- -webkit-filter: invert(100%);
- opacity: 1;
-}
-
-.topBar .title-bar-btns>.close-button:active {
- background: #f1707a !important;
-}
-
-.topBar .title-bar-btns>.close-button:active>img {
- filter: invert(100%);
- -webkit-filter: invert(100%);
+.topBar .title-bar-btns>.full-screen-button {
+ font-size: 18px;
}
.topBar .title-bar-btns img {
@@ -204,14 +189,7 @@ body {
-webkit-filter: invert(100%);
}
-.topBar .title-bar-btns>.min-button {
- grid-column: 1;
-}
-.topBar .title-bar-btns>.max-button, .topBar .title-bar-btns>.restore-button {
- grid-column: 2;
-}
-
-.topBar .title-bar-btns>.close-button {
+.topBar .title-bar-btns>.close-button, .topBar .title-bar-btns>.full-screen-button {
grid-column: 3;
}
diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx
index 5ca646af..abe3f25d 100644
--- a/src/renderer/index.tsx
+++ b/src/renderer/index.tsx
@@ -81,7 +81,6 @@ class Root extends React.PureComponent, State> {
openMenu={this.openMenu}
darkMode={config.darkMode}
appName={config.appName}
- useNativeWindow={config.useNativeWindow}
/>
);
diff --git a/src/types/config.ts b/src/types/config.ts
index 7cefe22d..cbd12e94 100644
--- a/src/types/config.ts
+++ b/src/types/config.ts
@@ -119,7 +119,6 @@ export type RegistryConfig = {
export type CombinedConfig = Omit & Omit & {
appName: string;
- useNativeWindow: boolean;
}
export type LocalConfiguration = Config & {
diff --git a/src/types/window.ts b/src/types/window.ts
index cb8f7785..583f2fa8 100644
--- a/src/types/window.ts
+++ b/src/types/window.ts
@@ -34,10 +34,7 @@ declare global {
openServersDropdown: () => void;
switchTab: (viewId: string) => void;
closeView: (viewId: string) => void;
- closeWindow: () => void;
- minimizeWindow: () => void;
- maximizeWindow: () => void;
- restoreWindow: () => void;
+ exitFullScreen: () => void;
doubleClickOnWindow: (windowName?: string) => void;
focusCurrentView: () => void;
reloadCurrentView: () => void;