Add extra pixel to titlebar on Windows 11

This commit is contained in:
Fedor Indutny 2022-06-15 11:21:03 -07:00 committed by GitHub
parent 4b8cb9f040
commit 8b32811440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 139 additions and 53 deletions

View File

@ -30,5 +30,8 @@
}, },
waitForChange: () => {}, waitForChange: () => {},
}, },
OS: {
isWindows11: () => false,
},
}; };
</script> </script>

View File

@ -626,7 +626,7 @@ async function getTitleBarOverlay(): Promise<TitleBarOverlayOptions | false> {
// Should match stylesheets/components/TitleBarContainer.scss minus the // Should match stylesheets/components/TitleBarContainer.scss minus the
// border // border
height: 28 - 1, height: (OS.isWindows11() ? 29 : 28) - 1,
}; };
} }
@ -1261,7 +1261,8 @@ async function showStickerCreator() {
const { x = 0, y = 0 } = windowConfig || {}; const { x = 0, y = 0 } = windowConfig || {};
// TODO: DESKTOP-3670 const titleBarOverlay = await getTitleBarOverlay();
const options = { const options = {
x: x + 100, x: x + 100,
y: y + 100, y: y + 100,
@ -1269,6 +1270,8 @@ async function showStickerCreator() {
minWidth: 800, minWidth: 800,
height: 650, height: 650,
title: getLocale().i18n('signalDesktopStickerCreator'), title: getLocale().i18n('signalDesktopStickerCreator'),
titleBarStyle: nonMainTitleBarStyle,
titleBarOverlay,
autoHideMenuBar: true, autoHideMenuBar: true,
backgroundColor: await getBackgroundColor(), backgroundColor: await getBackgroundColor(),
show: false, show: false,
@ -1286,7 +1289,7 @@ async function showStickerCreator() {
stickerCreatorWindow = new BrowserWindow(options); stickerCreatorWindow = new BrowserWindow(options);
setupSpellChecker(stickerCreatorWindow, getLocale()); setupSpellChecker(stickerCreatorWindow, getLocale());
handleCommonWindowEvents(stickerCreatorWindow); handleCommonWindowEvents(stickerCreatorWindow, titleBarOverlay);
const appUrl = process.env.SIGNAL_ENABLE_HTTP const appUrl = process.env.SIGNAL_ENABLE_HTTP
? prepareUrl( ? prepareUrl(

View File

@ -80,6 +80,6 @@ esbuild.build({
esbuild.build({ esbuild.build({
...bundleDefaults, ...bundleDefaults,
mainFields: ['browser', 'main'], mainFields: ['browser', 'main'],
entryPoints: [path.join(ROOT_DIR, 'ts/windows/main/preload.ts')], entryPoints: [path.join(ROOT_DIR, 'ts', 'windows', 'main', 'preload.ts')],
outfile: path.join(ROOT_DIR, 'preload.bundle.js'), outfile: path.join(ROOT_DIR, 'preload.bundle.js'),
}); });

View File

@ -6,8 +6,8 @@
.container { .container {
display: grid; display: grid;
height: 100vh; height: var(--window-height);
grid-template-rows: 47px calc(100vh - 47px - 68px) 68px; grid-template-rows: 47px calc(var(--window-height) - 47px - 68px) 68px;
@include light-theme() { @include light-theme() {
background-color: $color-white; background-color: $color-white;

View File

@ -11,31 +11,53 @@ import { ShareStage } from './stages/ShareStage';
import * as styles from './index.scss'; import * as styles from './index.scss';
import { PageHeader } from '../elements/PageHeader'; import { PageHeader } from '../elements/PageHeader';
import { useI18n } from '../util/i18n'; import { useI18n } from '../util/i18n';
import { TitleBarContainer } from '../../ts/components/TitleBarContainer';
import type { ExecuteMenuRoleType } from '../../ts/components/TitleBarContainer';
import { useTheme } from '../../ts/hooks/useTheme';
export const App: React.ComponentType = () => { export type AppPropsType = Readonly<{
platform: string;
executeMenuRole: ExecuteMenuRoleType;
isWindows11: boolean;
}>;
export const App = ({
platform,
executeMenuRole,
isWindows11,
}: AppPropsType): JSX.Element => {
const i18n = useI18n(); const i18n = useI18n();
const theme = useTheme();
return ( return (
<div className={styles.container}> <TitleBarContainer
<PageHeader>{i18n('StickerCreator--title')}</PageHeader> iconSrc="../../images/icon_32.png"
<Switch> platform={platform}
<Route path="/drop"> isWindows11={isWindows11}
<DropStage /> theme={theme}
</Route> executeMenuRole={executeMenuRole}
<Route path="/add-emojis"> >
<EmojiStage /> <div className={styles.container}>
</Route> <PageHeader>{i18n('StickerCreator--title')}</PageHeader>
<Route path="/add-meta"> <Switch>
<MetaStage /> <Route path="/drop">
</Route> <DropStage />
<Route path="/upload"> </Route>
<UploadStage /> <Route path="/add-emojis">
</Route> <EmojiStage />
<Route path="/share"> </Route>
<ShareStage /> <Route path="/add-meta">
</Route> <MetaStage />
<Redirect to="/drop" /> </Route>
</Switch> <Route path="/upload">
</div> <UploadStage />
</Route>
<Route path="/share">
<ShareStage />
</Route>
<Redirect to="/drop" />
</Switch>
</div>
</TitleBarContainer>
); );
}; };

View File

@ -4,7 +4,7 @@
.facade { .facade {
background: rgba(0, 0, 0, 0.33); background: rgba(0, 0, 0, 0.33);
width: 100vw; width: 100vw;
height: 100vh; height: var(--window-height);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;

View File

@ -5,7 +5,7 @@
<html> <html>
<head> <head>
<link <link
href="../../node_modules/@indutny/frameless-titlebar/src/title-bar/style.css" href="../../node_modules/@indutny/frameless-titlebar/dist/styles.css"
rel="stylesheet" rel="stylesheet"
type="text/css" type="text/css"
/> />
@ -14,6 +14,7 @@
<body> <body>
<div id="root"></div> <div id="root"></div>
<script type="text/javascript" src="../../js/components.js"></script> <script type="text/javascript" src="../../js/components.js"></script>
<script type="text/javascript" src="../../ts/set_os_class.js"></script>
<script <script
type="text/javascript" type="text/javascript"
src="../../ts/backbone/backbonejQuery.js" src="../../ts/backbone/backbonejQuery.js"

View File

@ -16,7 +16,11 @@ const ColdRoot = () => (
<ReduxProvider store={store}> <ReduxProvider store={store}>
<Router history={history}> <Router history={history}>
<I18n messages={localeMessages} locale={SignalContext.config.locale}> <I18n messages={localeMessages} locale={SignalContext.config.locale}>
<App /> <App
executeMenuRole={SignalContext.executeMenuRole}
platform={SignalContext.OS.platform}
isWindows11={SignalContext.OS.isWindows11()}
/>
</I18n> </I18n>
</Router> </Router>
</ReduxProvider> </ReduxProvider>

View File

@ -16,25 +16,6 @@ body {
@include font-body-1; @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()`.
--draggable-app-region: initial;
&.os-macos:not(.full-screen) {
--title-bar-drag-area-height: 28px;
--draggable-app-region: drag;
}
--window-height: 100vh;
--titlebar-height: 0px;
&.os-windows:not(.full-screen) {
--titlebar-height: 28px;
--window-height: calc(100vh - var(--titlebar-height));
}
&.light-theme { &.light-theme {
background-color: $color-white; background-color: $color-white;
color: $color-gray-90; color: $color-gray-90;

View File

@ -0,0 +1,30 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
body {
// 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()`.
--draggable-app-region: initial;
&.os-macos:not(.full-screen) {
--title-bar-drag-area-height: 28px;
--draggable-app-region: drag;
}
--window-height: 100vh;
--titlebar-height: 0px;
&.os-windows:not(.full-screen) {
--titlebar-height: 28px;
// Account for border eating one pixel out of the titlebar and making it
// look unbalanced
&.os-windows-11 {
--titlebar-height: calc(28px + 1px);
}
--window-height: calc(100vh - var(--titlebar-height));
}
}

View File

@ -6,6 +6,7 @@
@import 'variables'; @import 'variables';
@import 'mixins'; @import 'mixins';
@import 'global'; @import 'global';
@import 'titlebar';
// Old style: components // Old style: components
@import 'progress'; @import 'progress';

View File

@ -6,3 +6,4 @@
@import 'variables'; @import 'variables';
@import 'mixins'; @import 'mixins';
@import 'modules'; @import 'modules';
@import 'titlebar';

View File

@ -16,3 +16,7 @@ export const isWindows = (minVersion?: string): boolean => {
return is.undefined(minVersion) ? true : semver.gte(osRelease, minVersion); return is.undefined(minVersion) ? true : semver.gte(osRelease, minVersion);
}; };
export const isWindows11 = (): boolean => {
// See https://docs.microsoft.com/en-us/answers/questions/586619/windows-11-build-ver-is-still-10022000194.html
return isWindows('10.0.22000');
};

View File

@ -15,6 +15,7 @@ export type PropsType = {
i18n: LocalizerType; i18n: LocalizerType;
version: string; version: string;
platform: string; platform: string;
isWindows11: boolean;
executeMenuRole: ExecuteMenuRoleType; executeMenuRole: ExecuteMenuRoleType;
}; };
@ -24,6 +25,7 @@ export const About = ({
environment, environment,
version, version,
platform, platform,
isWindows11,
executeMenuRole, executeMenuRole,
}: PropsType): JSX.Element => { }: PropsType): JSX.Element => {
useEscapeHandling(closeAbout); useEscapeHandling(closeAbout);
@ -33,6 +35,7 @@ export const About = ({
return ( return (
<TitleBarContainer <TitleBarContainer
platform={platform} platform={platform}
isWindows11={isWindows11}
theme={theme} theme={theme}
executeMenuRole={executeMenuRole} executeMenuRole={executeMenuRole}
> >

View File

@ -37,6 +37,7 @@ type PropsType = {
isFullScreen: boolean; isFullScreen: boolean;
menuOptions: MenuOptionsType; menuOptions: MenuOptionsType;
platform: string; platform: string;
isWindows11: boolean;
executeMenuRole: ExecuteMenuRoleType; executeMenuRole: ExecuteMenuRoleType;
executeMenuAction: (action: MenuActionType) => void; executeMenuAction: (action: MenuActionType) => void;
@ -54,6 +55,7 @@ export const App = ({
isShowingStoriesView, isShowingStoriesView,
isMaximized, isMaximized,
isFullScreen, isFullScreen,
isWindows11,
menuOptions, menuOptions,
platform, platform,
localeMessages, localeMessages,
@ -139,6 +141,7 @@ export const App = ({
isMaximized={isMaximized} isMaximized={isMaximized}
isFullScreen={isFullScreen} isFullScreen={isFullScreen}
platform={platform} platform={platform}
isWindows11={isWindows11}
hasMenu hasMenu
localeMessages={localeMessages} localeMessages={localeMessages}
menuOptions={menuOptions} menuOptions={menuOptions}

View File

@ -27,6 +27,7 @@ const createProps = (): PropsType => ({
}, },
executeMenuRole: action('executeMenuRole'), executeMenuRole: action('executeMenuRole'),
platform: 'win32', platform: 'win32',
isWindows11: false,
}); });
export default { export default {

View File

@ -32,6 +32,7 @@ export type PropsType = {
fetchLogs: () => Promise<string>; fetchLogs: () => Promise<string>;
uploadLogs: (logs: string) => Promise<string>; uploadLogs: (logs: string) => Promise<string>;
platform: string; platform: string;
isWindows11: boolean;
executeMenuRole: ExecuteMenuRoleType; executeMenuRole: ExecuteMenuRoleType;
}; };
@ -48,6 +49,7 @@ export const DebugLogWindow = ({
fetchLogs, fetchLogs,
uploadLogs, uploadLogs,
platform, platform,
isWindows11,
executeMenuRole, executeMenuRole,
}: PropsType): JSX.Element => { }: PropsType): JSX.Element => {
const [loadState, setLoadState] = useState<LoadState>(LoadState.NotStarted); const [loadState, setLoadState] = useState<LoadState>(LoadState.NotStarted);
@ -146,6 +148,7 @@ export const DebugLogWindow = ({
return ( return (
<TitleBarContainer <TitleBarContainer
platform={platform} platform={platform}
isWindows11={isWindows11}
theme={theme} theme={theme}
executeMenuRole={executeMenuRole} executeMenuRole={executeMenuRole}
> >
@ -189,6 +192,7 @@ export const DebugLogWindow = ({
return ( return (
<TitleBarContainer <TitleBarContainer
platform={platform} platform={platform}
isWindows11={isWindows11}
theme={theme} theme={theme}
executeMenuRole={executeMenuRole} executeMenuRole={executeMenuRole}
> >

View File

@ -159,6 +159,7 @@ const createProps = (): PropsType => ({
executeMenuRole: action('executeMenuRole'), executeMenuRole: action('executeMenuRole'),
platform: 'win32', platform: 'win32',
isWindows11: false,
}); });
export default { export default {

View File

@ -103,6 +103,7 @@ export type PropsType = {
} }
) => unknown; ) => unknown;
platform: string; platform: string;
isWindows11: boolean;
executeMenuRole: ExecuteMenuRoleType; executeMenuRole: ExecuteMenuRoleType;
// Limited support features // Limited support features
@ -229,6 +230,7 @@ export const Preferences = ({
isNotificationAttentionSupported, isNotificationAttentionSupported,
isSyncSupported, isSyncSupported,
isSystemTraySupported, isSystemTraySupported,
isWindows11,
lastSyncTime, lastSyncTime,
makeSyncRequest, makeSyncRequest,
notificationContent, notificationContent,
@ -1027,6 +1029,7 @@ export const Preferences = ({
return ( return (
<TitleBarContainer <TitleBarContainer
platform={platform} platform={platform}
isWindows11={isWindows11}
theme={theme} theme={theme}
executeMenuRole={executeMenuRole} executeMenuRole={executeMenuRole}
> >

View File

@ -27,13 +27,19 @@ export type PropsType = Readonly<{
theme: ThemeType; theme: ThemeType;
isMaximized?: boolean; isMaximized?: boolean;
isFullScreen?: boolean; isFullScreen?: boolean;
isWindows11: boolean;
platform: string; platform: string;
executeMenuRole: ExecuteMenuRoleType; executeMenuRole: ExecuteMenuRoleType;
titleBarDoubleClick?: () => void; titleBarDoubleClick?: () => void;
children: ReactNode; children: ReactNode;
// Needs to be overriden in sticker-creator
iconSrc?: string;
}> & }> &
(MenuPropsType | { hasMenu?: false }); (MenuPropsType | { hasMenu?: false });
const TITLEBAR_HEIGHT = 28;
// Windows only // Windows only
const ROLE_TO_ACCELERATOR = new Map< const ROLE_TO_ACCELERATOR = new Map<
MenuItemConstructorOptions['role'], MenuItemConstructorOptions['role'],
@ -108,11 +114,13 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
theme, theme,
isMaximized, isMaximized,
isFullScreen, isFullScreen,
isWindows11,
executeMenuRole, executeMenuRole,
titleBarDoubleClick, titleBarDoubleClick,
children, children,
platform,
hasMenu, hasMenu,
platform,
iconSrc = 'images/icon_32.png',
} = props; } = props;
if (platform !== 'win32' || isFullScreen) { if (platform !== 'win32' || isFullScreen) {
@ -151,6 +159,8 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
const titleBarTheme = { const titleBarTheme = {
bar: { bar: {
// See stylesheets/_global.scss
height: isWindows11 ? TITLEBAR_HEIGHT + 1 : TITLEBAR_HEIGHT,
palette: palette:
theme === ThemeType.light ? ('light' as const) : ('dark' as const), theme === ThemeType.light ? ('light' as const) : ('dark' as const),
}, },
@ -168,7 +178,7 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
<TitleBar <TitleBar
className="TitleBarContainer__title" className="TitleBarContainer__title"
platform={platform} platform={platform}
iconSrc="images/icon_32.png" iconSrc={iconSrc}
theme={titleBarTheme} theme={titleBarTheme}
maximized={isMaximized} maximized={isMaximized}
menu={maybeMenu} menu={maybeMenu}

View File

@ -5,6 +5,9 @@
let className: string; let className: string;
if (window.SignalContext.OS.isWindows()) { if (window.SignalContext.OS.isWindows()) {
className = 'os-windows'; className = 'os-windows';
if (window.SignalContext.OS.isWindows11()) {
document.body.classList.add('os-windows-11');
}
} else if (window.SignalContext.OS.isMacOS()) { } else if (window.SignalContext.OS.isMacOS()) {
className = 'os-macos'; className = 'os-macos';
} else if (window.SignalContext.OS.isLinux()) { } else if (window.SignalContext.OS.isLinux()) {

View File

@ -41,6 +41,7 @@ const mapStateToProps = (state: StateType) => {
isFullScreen: getIsMainWindowFullScreen(state), isFullScreen: getIsMainWindowFullScreen(state),
menuOptions: getMenuOptions(state), menuOptions: getMenuOptions(state),
platform: getPlatform(state), platform: getPlatform(state),
isWindows11: window.SignalContext.OS.isWindows11(),
renderCallManager: () => <SmartCallManager />, renderCallManager: () => <SmartCallManager />,
renderCustomizingPreferredReactionsModal: () => ( renderCustomizingPreferredReactionsModal: () => (
<SmartCustomizingPreferredReactionsModal /> <SmartCustomizingPreferredReactionsModal />

View File

@ -34,6 +34,7 @@ contextBridge.exposeInMainWorld('SignalContext', {
i18n: SignalContext.i18n, i18n: SignalContext.i18n,
version: SignalContext.getVersion(), version: SignalContext.getVersion(),
platform: process.platform, platform: process.platform,
isWindows11: SignalContext.OS.isWindows11(),
executeMenuRole: SignalContext.executeMenuRole, executeMenuRole: SignalContext.executeMenuRole,
}), }),
document.getElementById('app') document.getElementById('app')

View File

@ -28,7 +28,7 @@ import { createSetting } from '../util/preload';
import { initialize as initializeLogging } from '../logging/set_up_renderer_logging'; import { initialize as initializeLogging } from '../logging/set_up_renderer_logging';
import { waitForSettingsChange } from './waitForSettingsChange'; import { waitForSettingsChange } from './waitForSettingsChange';
import { createNativeThemeListener } from '../context/createNativeThemeListener'; import { createNativeThemeListener } from '../context/createNativeThemeListener';
import { isWindows, isLinux, isMacOS } from '../OS'; import { isWindows, isWindows11, isLinux, isMacOS } from '../OS';
const params = new URLSearchParams(document.location.search); const params = new URLSearchParams(document.location.search);
const configParam = params.get('config'); const configParam = params.get('config');
@ -63,7 +63,9 @@ export type SignalContextType = {
waitForChange: () => Promise<void>; waitForChange: () => Promise<void>;
}; };
OS: { OS: {
platform: string;
isWindows: typeof isWindows; isWindows: typeof isWindows;
isWindows11: typeof isWindows11;
isLinux: typeof isLinux; isLinux: typeof isLinux;
isMacOS: typeof isMacOS; isMacOS: typeof isMacOS;
}; };
@ -89,7 +91,9 @@ export const SignalContext: SignalContextType = {
waitForChange: waitForSettingsChange, waitForChange: waitForSettingsChange,
}, },
OS: { OS: {
platform: process.platform,
isWindows, isWindows,
isWindows11,
isLinux, isLinux,
isMacOS, isMacOS,
}, },

View File

@ -24,6 +24,7 @@ contextBridge.exposeInMainWorld('SignalContext', {
ReactDOM.render( ReactDOM.render(
React.createElement(DebugLogWindow, { React.createElement(DebugLogWindow, {
platform: process.platform, platform: process.platform,
isWindows11: SignalContext.OS.isWindows11(),
executeMenuRole: SignalContext.executeMenuRole, executeMenuRole: SignalContext.executeMenuRole,
closeWindow: () => SignalContext.executeMenuRole('close'), closeWindow: () => SignalContext.executeMenuRole('close'),
downloadLog: (logText: string) => downloadLog: (logText: string) =>

View File

@ -339,6 +339,7 @@ const renderPreferences = async () => {
i18n: SignalContext.i18n, i18n: SignalContext.i18n,
platform: process.platform, platform: process.platform,
isWindows11: SignalContext.OS.isWindows11(),
executeMenuRole: SignalContext.executeMenuRole, executeMenuRole: SignalContext.executeMenuRole,
}; };