Titlebar fixes

This commit is contained in:
Fedor Indutny 2022-07-05 09:44:53 -07:00 committed by GitHub
parent f273333046
commit f92be05b15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 225 additions and 154 deletions

View file

@ -9,6 +9,9 @@
type="text/css"
/>
<script>
// eslint-disable-next-line
const noop = () => {};
window.SignalWindow = window.SignalWindow || {};
window.SignalWindow.log = {
fatal: console.error.bind(console),
@ -19,19 +22,27 @@
trace: console.trace.bind(console),
};
window.SignalContext = {
activeWindowService: {
isActive: () => true;
registerForActive: noop,
unregisterForActive: noop,
registerForChange: noop,
unregisterForChange: noop,
},
nativeThemeListener: {
getSystemValue: async () => 'light',
subscribe: () => {},
unsubscribe: () => {},
subscribe: noop,
unsubscribe: noop,
},
Settings: {
themeSetting: {
getValue: async () => 'light',
},
waitForChange: () => {},
waitForChange: noop,
},
OS: {
isWindows11: () => false,
hasCustomTitleBar: () => false,
},
};
</script>

View file

@ -34,6 +34,7 @@ if (getEnvironment() === Environment.Production) {
process.env.SUPPRESS_NO_CONFIG_WARNING = '';
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '';
process.env.SIGNAL_ENABLE_HTTP = '';
process.env.CUSTOM_TITLEBAR = '';
}
// We load config after we've made our modifications to NODE_ENV

View file

@ -432,6 +432,7 @@ async function prepareUrl(
// Only used by the main window
isMainWindowFullScreen: Boolean(mainWindow?.isFullScreen()),
isMainWindowMaximized: Boolean(mainWindow?.isMaximized()),
// Only for tests
argv: JSON.stringify(process.argv),
@ -499,6 +500,17 @@ function handleCommonWindowEvents(
activeWindows.add(window);
window.on('closed', () => activeWindows.delete(window));
const setWindowFocus = () => {
window.webContents.send('set-window-focus', window.isFocused());
};
window.on('focus', setWindowFocus);
window.on('blur', setWindowFocus);
window.once('ready-to-show', setWindowFocus);
// This is a fallback in case we drop an event for some reason.
const focusInterval = setInterval(setWindowFocus, 10000);
window.on('closed', () => clearInterval(focusInterval));
// Works only for mainWindow because it has `enablePreferredSizeMode`
let lastZoomFactor = window.webContents.getZoomFactor();
const onZoomChanged = () => {
@ -600,12 +612,12 @@ const mainTitleBarStyle =
? ('default' as const)
: ('hidden' as const);
const nonMainTitleBarStyle = OS.isWindows()
const nonMainTitleBarStyle = OS.hasCustomTitleBar()
? ('hidden' as const)
: ('default' as const);
async function getTitleBarOverlay(): Promise<TitleBarOverlayOptions | false> {
if (!OS.isWindows()) {
if (!OS.hasCustomTitleBar()) {
return false;
}
@ -782,18 +794,6 @@ async function createWindow() {
mainWindow.on('resize', captureWindowStats);
mainWindow.on('move', captureWindowStats);
const setWindowFocus = () => {
if (!mainWindow) {
return;
}
mainWindow.webContents.send('set-window-focus', mainWindow.isFocused());
};
mainWindow.on('focus', setWindowFocus);
mainWindow.on('blur', setWindowFocus);
mainWindow.once('ready-to-show', setWindowFocus);
// This is a fallback in case we drop an event for some reason.
setInterval(setWindowFocus, 10000);
if (getEnvironment() === Environment.Test) {
mainWindow.loadURL(await prepareFileUrl([__dirname, '../test/index.html']));
} else {

View file

@ -16,15 +16,13 @@ import type { ExecuteMenuRoleType } from '../../ts/components/TitleBarContainer'
import { useTheme } from '../../ts/hooks/useTheme';
export type AppPropsType = Readonly<{
platform: string;
executeMenuRole: ExecuteMenuRoleType;
isWindows11: boolean;
hasCustomTitleBar: boolean;
}>;
export const App = ({
platform,
executeMenuRole,
isWindows11,
hasCustomTitleBar,
}: AppPropsType): JSX.Element => {
const i18n = useI18n();
const theme = useTheme();
@ -32,8 +30,7 @@ export const App = ({
return (
<TitleBarContainer
iconSrc="../../images/icon_32.png"
platform={platform}
isWindows11={isWindows11}
hasCustomTitleBar={hasCustomTitleBar}
theme={theme}
executeMenuRole={executeMenuRole}
>

View file

@ -3,12 +3,12 @@
.facade {
background: rgba(0, 0, 0, 0.33);
width: 100vw;
width: var(--window-width);
height: var(--window-height);
display: flex;
justify-content: center;
align-items: center;
position: fixed;
left: 0;
top: 0;
left: var(--window-border);
top: var(--titlebar-height);
}

View file

@ -18,8 +18,7 @@ const ColdRoot = () => (
<I18n messages={localeMessages} locale={SignalContext.config.locale}>
<App
executeMenuRole={SignalContext.executeMenuRole}
platform={SignalContext.OS.platform}
isWindows11={SignalContext.OS.isWindows11()}
hasCustomTitleBar={SignalContext.OS.hasCustomTitleBar()}
/>
</I18n>
</Router>

View file

@ -672,11 +672,11 @@
@mixin install-screen {
align-items: center;
display: flex;
width: var(--window-width);
height: var(--window-height);
justify-content: center;
line-height: 30px;
user-select: none;
width: 100vw;
@include light-theme {
background: $color-gray-02;

View file

@ -4167,12 +4167,12 @@ button.module-image__border-overlay:focus {
&__overlay {
display: flex;
width: var(--window-width);
height: var(--window-height);
justify-content: flex-end;
left: 0;
position: absolute;
top: 0;
width: 100vw;
z-index: $z-index-popup;
}
@ -5857,7 +5857,7 @@ button.module-image__border-overlay:focus {
position: fixed;
left: 0;
top: 0;
width: 100vw;
width: var(--window-width);
height: var(--window-height);
display: flex;
justify-content: center;
@ -7457,25 +7457,25 @@ button.module-image__border-overlay:focus {
.module-modal-host__overlay {
background: $color-black-alpha-40;
width: var(--window-width);
height: var(--window-height);
left: 0;
position: absolute;
top: 0;
width: 100vw;
left: var(--window-border);
top: var(--titlebar-height);
position: fixed;
z-index: $z-index-popup-overlay;
}
.module-modal-host__overlay-container {
display: flex;
flex-direction: column;
width: var(--window-width);
height: var(--window-height);
left: var(--window-border);
top: var(--titlebar-height);
justify-content: center;
left: 0;
overflow: hidden;
padding: 20px;
position: absolute;
top: 0;
width: 100vw;
position: fixed;
z-index: $z-index-popup-overlay;
}
@ -7612,9 +7612,9 @@ button.module-image__border-overlay:focus {
.module-progress-dialog__overlay {
background: $color-black-alpha-40;
position: fixed;
left: 0;
top: 0;
width: 100vw;
left: var(--window-border);
top: var(--titlebar-height);
width: var(--window-width);
height: var(--window-height);
display: flex;
justify-content: center;

View file

@ -17,10 +17,20 @@ body {
}
--window-height: 100vh;
--window-width: 100vw;
--unscaled-window-border: 0px;
--window-border: calc(var(--unscaled-window-border) / var(--zoom-factor));
--titlebar-height: 0px;
&.os-windows:not(.full-screen) {
&.os-has-custom-titlebar:not(.full-screen) {
&:not(.maximized) {
--unscaled-window-border: 1px;
}
--titlebar-height: calc(28px / var(--zoom-factor));
--window-height: calc(100vh - var(--titlebar-height));
--window-width: calc(100vw - 2 * var(--window-border));
--window-height: calc(
100vh - var(--titlebar-height) - 2 * var(--window-border)
);
}
}

View file

@ -7,12 +7,12 @@
background: $color-gray-95;
display: flex;
flex-direction: column;
width: var(--window-width);
height: var(--window-height);
left: 0;
position: absolute;
top: var(--titlebar-height);
position: absolute;
user-select: none;
width: 100vw;
z-index: $z-index-popup-overlay;
&__container {

View file

@ -19,7 +19,7 @@
flex-direction: column;
height: 100%;
width: 380px;
padding-top: 42px;
padding-top: calc(14px + var(--title-bar-drag-area-height));
&__header {
align-items: center;

View file

@ -11,12 +11,12 @@
background: $color-gray-95;
display: flex;
flex-direction: column;
width: var(--window-width);
height: 100vh;
left: 0;
position: absolute;
top: 0;
user-select: none;
width: 100vw;
z-index: $z-index-popup-overlay;
&__container {

View file

@ -6,14 +6,41 @@
flex-direction: column;
height: 100vh;
&__title {
--border-color: transparent;
&--active {
--border-color: transparent;
}
border: var(--window-border) solid var(--border-color);
@mixin titlebar-position {
position: fixed;
top: 0;
left: 0;
width: calc(100vw * var(--zoom-factor));
z-index: $z-index-window-controls;
transform: scale(calc(1 / var(--zoom-factor)));
transform-origin: 0 0;
}
// Draw bottom-less border frame around titlebar to prevent border-bottom
// color from leaking to corners.
&:after {
content: '';
@include titlebar-position;
height: calc(var(--titlebar-height) * var(--zoom-factor));
border: var(--unscaled-window-border) solid var(--border-color);
border-bottom: none;
}
&__title {
@include titlebar-position;
border: var(--unscaled-window-border) solid transparent;
// This matches the inline styles of frameless-titlebar
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
@ -23,16 +50,13 @@
& button {
font-family: inherit;
}
// Shift titlebar down 1px on Windows 11 because otherwise window border
// will cover it.
&--extra-padding {
padding-top: 1px;
}
&__padding {
height: calc(var(--titlebar-height) - var(--window-border));
}
&__content {
margin-top: var(--titlebar-height);
height: var(--window-height);
position: relative;
}

View file

@ -16,7 +16,7 @@ export const isWindows = (minVersion?: string): boolean => {
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');
};
// Windows 10 and above
export const hasCustomTitleBar = (): boolean =>
isWindows('10.0.0') || Boolean(process.env.CUSTOM_TITLEBAR);

View file

@ -1835,7 +1835,9 @@ export async function startApp(): Promise<void> {
window.reduxActions.app.openInstaller();
}
window.registerForActive(() => notificationService.clear());
const { activeWindowService } = window.SignalContext;
activeWindowService.registerForActive(() => notificationService.clear());
window.addEventListener('unload', () => notificationService.fastClear());
notificationService.on('click', (id, messageId) => {
@ -1848,7 +1850,7 @@ export async function startApp(): Promise<void> {
});
// Maybe refresh remote configuration when we become active
window.registerForActive(async () => {
activeWindowService.registerForActive(async () => {
strictAssert(server !== undefined, 'WebAPI not ready');
try {

View file

@ -14,8 +14,7 @@ export type PropsType = {
environment: string;
i18n: LocalizerType;
version: string;
platform: string;
isWindows11: boolean;
hasCustomTitleBar: boolean;
executeMenuRole: ExecuteMenuRoleType;
};
@ -24,8 +23,7 @@ export const About = ({
i18n,
environment,
version,
platform,
isWindows11,
hasCustomTitleBar,
executeMenuRole,
}: PropsType): JSX.Element => {
useEscapeHandling(closeAbout);
@ -34,8 +32,7 @@ export const About = ({
return (
<TitleBarContainer
platform={platform}
isWindows11={isWindows11}
hasCustomTitleBar={hasCustomTitleBar}
theme={theme}
executeMenuRole={executeMenuRole}
>

View file

@ -36,8 +36,7 @@ type PropsType = {
isMaximized: boolean;
isFullScreen: boolean;
menuOptions: MenuOptionsType;
platform: string;
isWindows11: boolean;
hasCustomTitleBar: boolean;
hideMenuBar: boolean;
executeMenuRole: ExecuteMenuRoleType;
@ -59,11 +58,10 @@ export const App = ({
isFullScreen,
isMaximized,
isShowingStoriesView,
isWindows11,
hasCustomTitleBar,
localeMessages,
menuOptions,
openInbox,
platform,
registerSingleDevice,
renderCallManager,
renderCustomizingPreferredReactionsModal,
@ -152,8 +150,7 @@ export const App = ({
theme={theme}
isMaximized={isMaximized}
isFullScreen={isFullScreen}
platform={platform}
isWindows11={isWindows11}
hasCustomTitleBar={hasCustomTitleBar}
executeMenuRole={executeMenuRole}
titleBarDoubleClick={titleBarDoubleClick}
hasMenu

View file

@ -26,8 +26,7 @@ const createProps = (): PropsType => ({
return 'https://picsum.photos/1800/900';
},
executeMenuRole: action('executeMenuRole'),
platform: 'win32',
isWindows11: false,
hasCustomTitleBar: true,
});
export default {

View file

@ -31,8 +31,7 @@ export type PropsType = {
i18n: LocalizerType;
fetchLogs: () => Promise<string>;
uploadLogs: (logs: string) => Promise<string>;
platform: string;
isWindows11: boolean;
hasCustomTitleBar: boolean;
executeMenuRole: ExecuteMenuRoleType;
};
@ -48,8 +47,7 @@ export const DebugLogWindow = ({
i18n,
fetchLogs,
uploadLogs,
platform,
isWindows11,
hasCustomTitleBar,
executeMenuRole,
}: PropsType): JSX.Element => {
const [loadState, setLoadState] = useState<LoadState>(LoadState.NotStarted);
@ -147,8 +145,7 @@ export const DebugLogWindow = ({
return (
<TitleBarContainer
platform={platform}
isWindows11={isWindows11}
hasCustomTitleBar={hasCustomTitleBar}
theme={theme}
executeMenuRole={executeMenuRole}
>
@ -191,8 +188,7 @@ export const DebugLogWindow = ({
return (
<TitleBarContainer
platform={platform}
isWindows11={isWindows11}
hasCustomTitleBar={hasCustomTitleBar}
theme={theme}
executeMenuRole={executeMenuRole}
>

View file

@ -158,8 +158,7 @@ const createProps = (): PropsType => ({
i18n,
executeMenuRole: action('executeMenuRole'),
platform: 'win32',
isWindows11: false,
hasCustomTitleBar: true,
});
export default {

View file

@ -102,8 +102,7 @@ export type PropsType = {
value: CustomColorType;
}
) => unknown;
platform: string;
isWindows11: boolean;
hasCustomTitleBar: boolean;
executeMenuRole: ExecuteMenuRoleType;
// Limited support features
@ -230,7 +229,7 @@ export const Preferences = ({
isNotificationAttentionSupported,
isSyncSupported,
isSystemTraySupported,
isWindows11,
hasCustomTitleBar,
lastSyncTime,
makeSyncRequest,
notificationContent,
@ -258,7 +257,6 @@ export const Preferences = ({
onThemeChange,
onUniversalExpireTimerChange,
onZoomFactorChange,
platform,
removeCustomColor,
removeCustomColorOnConversations,
resetAllChatColors,
@ -1028,8 +1026,7 @@ export const Preferences = ({
return (
<TitleBarContainer
platform={platform}
isWindows11={isWindows11}
hasCustomTitleBar={hasCustomTitleBar}
theme={theme}
executeMenuRole={executeMenuRole}
>

View file

@ -12,6 +12,7 @@ import { createTemplate } from '../../app/menu';
import { ThemeType } from '../types/Util';
import type { LocaleMessagesType } from '../types/I18N';
import type { MenuOptionsType, MenuActionType } from '../types/menu';
import { useIsWindowActive } from '../hooks/useIsWindowActive';
export type MenuPropsType = Readonly<{
hasMenu: true;
@ -28,9 +29,8 @@ export type PropsType = Readonly<{
theme: ThemeType;
isMaximized?: boolean;
isFullScreen?: boolean;
isWindows11: boolean;
hasCustomTitleBar: boolean;
hideMenuBar?: boolean;
platform: string;
executeMenuRole: ExecuteMenuRoleType;
titleBarDoubleClick?: () => void;
children: ReactNode;
@ -116,16 +116,17 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
theme,
isMaximized,
isFullScreen,
isWindows11,
hasCustomTitleBar,
hideMenuBar,
executeMenuRole,
titleBarDoubleClick,
children,
hasMenu,
platform,
iconSrc = 'images/icon_32.png',
} = props;
const isWindowActive = useIsWindowActive();
const titleBarTheme = useMemo(
() => ({
bar: {
@ -201,7 +202,7 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
[theme, hideMenuBar]
);
if (platform !== 'win32' || isFullScreen) {
if (!hasCustomTitleBar || isFullScreen) {
return <>{children}</>;
}
@ -236,17 +237,18 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
}
return (
<div className="TitleBarContainer">
<TitleBar
<div
className={classNames(
'TitleBarContainer__title',
// Add a pixel of padding on non-maximized Windows 11 titlebar.
isWindows11 && !isMaximized
? 'TitleBarContainer__title--extra-padding'
: null
'TitleBarContainer',
isWindowActive ? 'TitleBarContainer--active' : null
)}
platform={platform}
>
<div className="TitleBarContainer__padding" />
<div className="TitleBarContainer__content">{children}</div>
<TitleBar
className="TitleBarContainer__title"
platform="win32"
iconSrc={iconSrc}
theme={titleBarTheme}
maximized={isMaximized}
@ -254,8 +256,6 @@ export const TitleBarContainer = (props: PropsType): JSX.Element => {
onDoubleClick={titleBarDoubleClick}
hideControls
/>
<div className="TitleBarContainer__content">{children}</div>
</div>
);
};

View file

@ -36,11 +36,6 @@ export default {
// eslint-disable-next-line
const noop = () => {};
Object.assign(window, {
registerForActive: noop,
unregisterForActive: noop,
});
const items: Record<string, TimelineItemType> = {
'id-1': {
type: 'message',

View file

@ -573,7 +573,9 @@ export class Timeline extends React.Component<
this.updateIntersectionObserver();
window.registerForActive(this.markNewestBottomVisibleMessageRead);
window.SignalContext.activeWindowService.registerForActive(
this.markNewestBottomVisibleMessageRead
);
this.delayedPeekTimeout = setTimeout(() => {
const { id, peekGroupCallForTheFirstTime } = this.props;
@ -590,7 +592,9 @@ export class Timeline extends React.Component<
public override componentWillUnmount(): void {
const { delayedPeekTimeout, peekInterval } = this;
window.unregisterForActive(this.markNewestBottomVisibleMessageRead);
window.SignalContext.activeWindowService.unregisterForActive(
this.markNewestBottomVisibleMessageRead
);
this.intersectionObserver?.disconnect();

View file

@ -0,0 +1,23 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { useEffect, useState } from 'react';
export function useIsWindowActive(): boolean {
const { activeWindowService } = window.SignalContext;
const [isActive, setIsActive] = useState(activeWindowService.isActive());
useEffect(() => {
const update = (newIsActive: boolean): void => {
setIsActive(newIsActive);
};
activeWindowService.registerForChange(update);
return () => {
activeWindowService.unregisterForChange(update);
};
}, [activeWindowService]);
return isActive;
}

View file

@ -1,10 +1,14 @@
// Copyright 2021 Signal Messenger, LLC
// Copyright 2021-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
{
const updateFullScreenClass = (isFullScreen: boolean) => {
const updateFullScreenClass = (
isFullScreen: boolean,
isMaximized: boolean
) => {
document.body.classList.toggle('full-screen', isFullScreen);
document.body.classList.toggle('maximized', isMaximized);
};
updateFullScreenClass(window.isFullScreen());
updateFullScreenClass(window.isFullScreen(), window.isMaximized());
window.onFullScreenChange = updateFullScreenClass;
}

View file

@ -1417,7 +1417,7 @@ export class ConversationModel extends window.Backbone
messagesAdded({
conversationId,
messages: [{ ...message.attributes }],
isActive: window.isActive(),
isActive: window.SignalContext.activeWindowService.isActive(),
isJustSent,
isNewMessage: true,
});
@ -1567,7 +1567,7 @@ export class ConversationModel extends window.Backbone
messages: cleaned.map((messageModel: MessageModel) => ({
...messageModel.attributes,
})),
isActive: window.isActive(),
isActive: window.SignalContext.activeWindowService.isActive(),
isJustSent: false,
isNewMessage: false,
});
@ -1620,7 +1620,7 @@ export class ConversationModel extends window.Backbone
messages: cleaned.map((messageModel: MessageModel) => ({
...messageModel.attributes,
})),
isActive: window.isActive(),
isActive: window.SignalContext.activeWindowService.isActive(),
isJustSent: false,
isNewMessage: false,
});

View file

@ -25,6 +25,8 @@ export class ActiveWindowService {
private activeCallbacks: Array<() => void> = [];
private changeCallbacks: Array<(isActive: boolean) => void> = [];
private lastActiveEventAt = -Infinity;
private callActiveCallbacks: () => void;
@ -73,6 +75,16 @@ export class ActiveWindowService {
);
}
registerForChange(callback: (isActive: boolean) => void): void {
this.changeCallbacks.push(callback);
}
unregisterForChange(callback: (isActive: boolean) => void): void {
this.changeCallbacks = this.changeCallbacks.filter(
item => item !== callback
);
}
private onActiveEvent(): void {
this.updateState(() => {
this.lastActiveEventAt = Date.now();
@ -93,5 +105,11 @@ export class ActiveWindowService {
if (!wasActiveBefore && isActiveNow) {
this.callActiveCallbacks();
}
if (wasActiveBefore !== isActiveNow) {
for (const callback of this.changeCallbacks) {
callback(isActiveNow);
}
}
}
}

View file

@ -228,7 +228,7 @@ class NotificationService extends EventEmitter {
}
const { notificationData } = this;
const isAppFocused = window.isActive();
const isAppFocused = window.SignalContext.activeWindowService.isActive();
const userSetting = this.getNotificationSetting();
// This isn't a boolean because TypeScript isn't smart enough to know that, if

View file

@ -14,4 +14,8 @@
}
document.body.classList.add(className);
if (window.SignalContext.OS.hasCustomTitleBar()) {
document.body.classList.add('os-has-custom-titlebar');
}
}

View file

@ -22,7 +22,6 @@ import {
getIsMainWindowMaximized,
getIsMainWindowFullScreen,
getMenuOptions,
getPlatform,
} from '../selectors/user';
import { shouldShowStoriesView } from '../selectors/stories';
import { getHideMenuBar } from '../selectors/items';
@ -42,8 +41,7 @@ const mapStateToProps = (state: StateType) => {
isMaximized: getIsMainWindowMaximized(state),
isFullScreen: getIsMainWindowFullScreen(state),
menuOptions: getMenuOptions(state),
platform: getPlatform(state),
isWindows11: window.SignalContext.OS.isWindows11(),
hasCustomTitleBar: window.SignalContext.OS.hasCustomTitleBar(),
hideMenuBar: getHideMenuBar(state),
renderCallManager: () => <SmartCallManager />,
renderCustomizingPreferredReactionsModal: () => (

View file

@ -53,7 +53,8 @@ async function notifyForCall(
isVideoCall: boolean
): Promise<void> {
const shouldNotify =
!window.isActive() && window.Events.getCallSystemNotification();
!window.SignalContext.activeWindowService.isActive() &&
window.Events.getCallSystemNotification();
if (!shouldNotify) {
return;
}

View file

@ -92,6 +92,7 @@ export const rendererConfigSchema = z.object({
// Only used by main window
isMainWindowFullScreen: z.boolean(),
isMainWindowMaximized: z.boolean(),
// Only for tests
argv: configOptionalStringSchema,

View file

@ -450,7 +450,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
};
const markMessageRead = async (messageId: string) => {
if (!window.isActive()) {
if (!window.SignalContext.activeWindowService.isActive()) {
return;
}

6
ts/window.d.ts vendored
View file

@ -291,10 +291,10 @@ declare global {
waitForEmptyEventQueue: () => Promise<void>;
getVersion: () => string;
i18n: LocalizerType;
isActive: () => boolean;
isAfterVersion: (version: string, anotherVersion: string) => boolean;
isBeforeVersion: (version: string, anotherVersion: string) => boolean;
isFullScreen: () => boolean;
isMaximized: () => boolean;
initialTheme?: ThemeType;
libphonenumberInstance: {
parse: (number: string) => PhoneNumber;
@ -303,12 +303,11 @@ declare global {
};
libphonenumberFormat: typeof PhoneNumberFormat;
nodeSetImmediate: typeof setImmediate;
onFullScreenChange: (fullScreen: boolean) => void;
onFullScreenChange: (fullScreen: boolean, maximized: boolean) => void;
platform: string;
preloadedImages: Array<WhatIsThis>;
reduxActions: ReduxActions;
reduxStore: Store<StateType>;
registerForActive: (handler: () => void) => void;
restart: () => void;
setImmediate: typeof setImmediate;
showWindow: () => void;
@ -326,7 +325,6 @@ declare global {
systemTheme: WhatIsThis;
textsecure: typeof textsecure;
titleBarDoubleClick: () => void;
unregisterForActive: (handler: () => void) => void;
updateTrayIcon: (count: number) => void;
Backbone: typeof Backbone;
CI?: CI;

View file

@ -36,8 +36,7 @@ contextBridge.exposeInMainWorld('SignalContext', {
environment: `${environmentText.join(' - ')}${platform}`,
i18n: SignalContext.i18n,
version: SignalContext.getVersion(),
platform: process.platform,
isWindows11: SignalContext.OS.isWindows11(),
hasCustomTitleBar: SignalContext.OS.hasCustomTitleBar(),
executeMenuRole: SignalContext.executeMenuRole,
}),
document.getElementById('app')

View file

@ -12,6 +12,7 @@ import type { LocaleMessagesType } from '../types/I18N';
import type { NativeThemeType } from '../context/createNativeThemeListener';
import type { SettingType } from '../util/preload';
import type { RendererConfigType } from '../types/RendererConfig';
import { ActiveWindowService } from '../services/ActiveWindowService';
import { Bytes } from '../context/Bytes';
import { Crypto } from '../context/Crypto';
@ -28,7 +29,10 @@ import { createSetting } from '../util/preload';
import { initialize as initializeLogging } from '../logging/set_up_renderer_logging';
import { waitForSettingsChange } from './waitForSettingsChange';
import { createNativeThemeListener } from '../context/createNativeThemeListener';
import { isWindows, isWindows11, isLinux, isMacOS } from '../OS';
import { isWindows, isLinux, isMacOS, hasCustomTitleBar } from '../OS';
const activeWindowService = new ActiveWindowService();
activeWindowService.initialize(window.document, ipcRenderer);
const params = new URLSearchParams(document.location.search);
const configParam = params.get('config');
@ -58,6 +62,7 @@ export type SignalContextType = {
nativeThemeListener: NativeThemeType;
setIsCallActive: (isCallActive: boolean) => unknown;
activeWindowService: typeof activeWindowService;
Settings: {
themeSetting: SettingType<IPCEventsValuesType['themeSetting']>;
waitForChange: () => Promise<void>;
@ -65,9 +70,9 @@ export type SignalContextType = {
OS: {
platform: string;
isWindows: typeof isWindows;
isWindows11: typeof isWindows11;
isLinux: typeof isLinux;
isMacOS: typeof isMacOS;
hasCustomTitleBar: typeof hasCustomTitleBar;
};
config: RendererConfigType;
getAppInstance: () => string | undefined;
@ -86,6 +91,7 @@ export type SignalContextType = {
};
export const SignalContext: SignalContextType = {
activeWindowService,
Settings: {
themeSetting: createSetting('themeSetting', { setter: false }),
waitForChange: waitForSettingsChange,
@ -93,9 +99,9 @@ export const SignalContext: SignalContextType = {
OS: {
platform: process.platform,
isWindows,
isWindows11,
isLinux,
isMacOS,
hasCustomTitleBar,
},
bytes: new Bytes(),
config,

View file

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

View file

@ -254,14 +254,17 @@ window.sendChallengeRequest = request => ipc.send('challenge:request', request);
{
let isFullScreen = Boolean(config.isMainWindowFullScreen);
let isMaximized = Boolean(config.isMainWindowMaximized);
window.isFullScreen = () => isFullScreen;
window.isMaximized = () => isMaximized;
// This is later overwritten.
window.onFullScreenChange = noop;
ipc.on('full-screen-change', (_event, isFull) => {
isFullScreen = Boolean(isFull);
window.onFullScreenChange(isFullScreen);
ipc.on('window:set-window-stats', (_event, stats) => {
isFullScreen = Boolean(stats.isFullScreen);
isMaximized = Boolean(stats.isMaximized);
window.onFullScreenChange(isFullScreen, isMaximized);
});
}

View file

@ -1,7 +1,6 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { ipcRenderer as ipc } from 'electron';
import Backbone from 'backbone';
import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber';
import * as React from 'react';
@ -12,7 +11,6 @@ import PQueue from 'p-queue';
import { textsecure } from '../../textsecure';
import { imageToBlurHash } from '../../util/imageToBlurHash';
import { ActiveWindowService } from '../../services/ActiveWindowService';
import * as Attachments from '../attachments';
import { setup } from '../../signal';
import { addSensitivePath } from '../../util/privacy';
@ -44,14 +42,6 @@ window.imageToBlurHash = imageToBlurHash;
window.libphonenumberInstance = PhoneNumberUtil.getInstance();
window.libphonenumberFormat = PhoneNumberFormat;
const activeWindowService = new ActiveWindowService();
activeWindowService.initialize(window.document, ipc);
window.isActive = activeWindowService.isActive.bind(activeWindowService);
window.registerForActive =
activeWindowService.registerForActive.bind(activeWindowService);
window.unregisterForActive =
activeWindowService.unregisterForActive.bind(activeWindowService);
window.React = React;
window.ReactDOM = ReactDOM;
window.PQueue = PQueue;

View file

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