summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-09-13 13:33:54 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-09-13 13:33:54 +0200
commit343fd4ff64150920f14de07c66385f5bb3fff9ed (patch)
tree00cf12cabe0545acec7d9f457d8cdd30ffd2888f /gui/src
parent8c7653b4f16d48d39154b149f9c49a0be5209caa (diff)
parent6ab3a737364bfa5e593581d968081c5b86bdb372 (diff)
downloadmullvadvpn-343fd4ff64150920f14de07c66385f5bb3fff9ed.tar.xz
mullvadvpn-343fd4ff64150920f14de07c66385f5bb3fff9ed.zip
Merge branch 'detect-macos-scrollbar-visibility'
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/main/index.ts47
-rw-r--r--gui/src/main/window-controller.ts2
-rw-r--r--gui/src/renderer/app.tsx16
-rw-r--r--gui/src/renderer/components/CustomScrollbars.tsx42
-rw-r--r--gui/src/renderer/components/MacOsScrollbarDetection.tsx41
-rw-r--r--gui/src/renderer/components/NavigationBar.tsx6
-rw-r--r--gui/src/renderer/components/SelectLanguage.tsx4
-rw-r--r--gui/src/renderer/components/SelectLocation.tsx4
-rw-r--r--gui/src/renderer/components/SplitTunnelingSettings.tsx4
-rw-r--r--gui/src/renderer/redux/userinterface/actions.ts19
-rw-r--r--gui/src/renderer/redux/userinterface/reducers.ts6
-rw-r--r--gui/src/shared/ipc-schema.ts16
12 files changed, 173 insertions, 34 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index 8fa09576c7..ff7e9e64a7 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -1,4 +1,4 @@
-import { execFile } from 'child_process';
+import { exec, execFile } from 'child_process';
import {
app,
BrowserWindow,
@@ -8,11 +8,13 @@ import {
screen,
session,
shell,
+ systemPreferences,
Tray,
} from 'electron';
import os from 'os';
import * as path from 'path';
import { sprintf } from 'sprintf-js';
+import util from 'util';
import * as uuid from 'uuid';
import config from '../config.json';
import { closeToExpiry, hasExpired } from '../shared/account-expiry';
@@ -72,7 +74,9 @@ import { resolveBin } from './proc';
import ReconnectionBackoff from './reconnection-backoff';
import TrayIconController, { TrayIconType } from './tray-icon-controller';
import WindowController from './window-controller';
-import { ITranslations } from '../shared/ipc-schema';
+import { ITranslations, MacOsScrollbarVisibility } from '../shared/ipc-schema';
+
+const execAsync = util.promisify(exec);
// Only import split tunneling library on correct OS.
const linuxSplitTunneling = process.platform === 'linux' && require('./linux-split-tunneling');
@@ -235,6 +239,8 @@ class ApplicationMain {
private windowsSplitTunnelingApplications?: IApplication[];
+ private macOsScrollbarVisibility?: MacOsScrollbarVisibility;
+
public run() {
// Remove window animations to combat window flickering when opening window. Can be removed when
// this issue has been resolved: https://github.com/electron/electron/issues/12130
@@ -437,6 +443,13 @@ class ApplicationMain {
);
this.connectToDaemon();
+ if (process.platform === 'darwin') {
+ await this.updateMacOsScrollbarVisibility();
+ systemPreferences.subscribeNotification('AppleShowScrollBarsSettingChanged', async () => {
+ await this.updateMacOsScrollbarVisibility();
+ });
+ }
+
const window = await this.createWindow();
const tray = this.createTray();
@@ -1032,7 +1045,7 @@ class ApplicationMain {
private registerWindowListener(windowController: WindowController) {
windowController.window?.on('focus', () => {
- IpcMainEventChannel.windowFocus.notify(windowController.webContents, true);
+ IpcMainEventChannel.window.notifyFocus(windowController.webContents, true);
this.blurNavigationResetScheduler.cancel();
@@ -1049,7 +1062,7 @@ class ApplicationMain {
});
windowController.window?.on('blur', () => {
- IpcMainEventChannel.windowFocus.notify(windowController.webContents, false);
+ IpcMainEventChannel.window.notifyFocus(windowController.webContents, false);
// ensure notification guard is reset
this.notificationController.resetTunnelStateAnnouncements();
@@ -1087,6 +1100,7 @@ class ApplicationMain {
wireguardPublicKey: this.wireguardPublicKey,
translations: this.translations,
windowsSplitTunnelingApplications: this.windowsSplitTunnelingApplications,
+ macOsScrollbarVisibility: this.macOsScrollbarVisibility,
}));
IpcMainEventChannel.settings.handleSetAllowLan((allowLan: boolean) =>
@@ -1994,6 +2008,31 @@ class ApplicationMain {
private getProblemReportPath(id: string): string {
return path.join(app.getPath('temp'), `${id}.log`);
}
+
+ private async updateMacOsScrollbarVisibility(): Promise<void> {
+ const command =
+ 'defaults read kCFPreferencesAnyApplication AppleShowScrollBars || echo Automatic';
+ const { stdout } = await execAsync(command);
+ switch (stdout.trim()) {
+ case 'WhenScrolling':
+ this.macOsScrollbarVisibility = MacOsScrollbarVisibility.whenScrolling;
+ break;
+ case 'Always':
+ this.macOsScrollbarVisibility = MacOsScrollbarVisibility.always;
+ break;
+ case 'Automatic':
+ default:
+ this.macOsScrollbarVisibility = MacOsScrollbarVisibility.automatic;
+ break;
+ }
+
+ if (this.windowController?.webContents) {
+ IpcMainEventChannel.window.notifyMacOsScrollbarVisibility(
+ this.windowController.webContents,
+ this.macOsScrollbarVisibility,
+ );
+ }
+ }
}
const applicationMain = new ApplicationMain();
diff --git a/gui/src/main/window-controller.ts b/gui/src/main/window-controller.ts
index 50ceab01e4..298f767fb5 100644
--- a/gui/src/main/window-controller.ts
+++ b/gui/src/main/window-controller.ts
@@ -230,7 +230,7 @@ export default class WindowController {
if (this.window) {
const shapeParameters = this.windowPositioning.getWindowShapeParameters(this.window);
- IpcMainEventChannel.windowShape.notify(this.webContentsValue, shapeParameters);
+ IpcMainEventChannel.window.notifyShape(this.webContentsValue, shapeParameters);
}
}
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index 3f65002340..cf7a354694 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -4,6 +4,7 @@ import { Router } from 'react-router';
import { bindActionCreators } from 'redux';
import AppRouter from './components/AppRouter';
+import MacOsScrollbarDetection from './components/MacOsScrollbarDetection';
import ErrorBoundary from './components/ErrorBoundary';
import { AppContext } from './context';
@@ -132,7 +133,7 @@ export default class AppRenderer {
log.addOutput(new ConsoleOutput(LogLevel.debug));
log.addOutput(new IpcOutput(LogLevel.debug));
- IpcRendererEventChannel.windowShape.listen((windowShapeParams) => {
+ IpcRendererEventChannel.window.listenShape((windowShapeParams) => {
if (typeof windowShapeParams.arrowPosition === 'number') {
this.reduxActions.userInterface.updateWindowArrowPosition(windowShapeParams.arrowPosition);
}
@@ -199,10 +200,14 @@ export default class AppRenderer {
this.reduxActions.settings.setSplitTunnelingApplications(applications);
});
- IpcRendererEventChannel.windowFocus.listen((focus: boolean) => {
+ IpcRendererEventChannel.window.listenFocus((focus: boolean) => {
this.reduxActions.userInterface.setWindowFocused(focus);
});
+ IpcRendererEventChannel.window.listenMacOsScrollbarVisibility((visibility) => {
+ this.reduxActions.userInterface.setMacOsScrollbarVisibility(visibility);
+ });
+
IpcRendererEventChannel.navigation.listenReset(() => this.history.dismiss(true));
// Request the initial state from the main process
@@ -237,6 +242,12 @@ export default class AppRenderer {
this.storeAutoStart(initialState.autoStart);
this.setWireguardPublicKey(initialState.wireguardPublicKey);
+ if (initialState.macOsScrollbarVisibility !== undefined) {
+ this.reduxActions.userInterface.setMacOsScrollbarVisibility(
+ initialState.macOsScrollbarVisibility,
+ );
+ }
+
if (initialState.isConnected) {
void this.onDaemonConnected();
}
@@ -265,6 +276,7 @@ export default class AppRenderer {
<Router history={this.history.asHistory}>
<ErrorBoundary>
<AppRouter />
+ {window.env.platform === 'darwin' && <MacOsScrollbarDetection />}
</ErrorBoundary>
</Router>
</Provider>
diff --git a/gui/src/renderer/components/CustomScrollbars.tsx b/gui/src/renderer/components/CustomScrollbars.tsx
index 3dacd26626..139c4381de 100644
--- a/gui/src/renderer/components/CustomScrollbars.tsx
+++ b/gui/src/renderer/components/CustomScrollbars.tsx
@@ -1,6 +1,8 @@
import * as React from 'react';
import styled from 'styled-components';
+import { MacOsScrollbarVisibility } from '../../shared/ipc-schema';
import { Scheduler } from '../../shared/scheduler';
+import { useSelector } from '../redux/store';
const ScrollableContent = styled.div({
display: 'flex',
@@ -12,8 +14,8 @@ const ScrollableContent = styled.div({
const AUTOHIDE_TIMEOUT = 1000;
interface IProps {
- autoHide: boolean;
- trackPadding: { x: number; y: number };
+ autoHide?: boolean;
+ trackPadding?: { x: number; y: number };
onScroll?: (value: IScrollEvent) => void;
className?: string;
fillContainer?: boolean;
@@ -44,10 +46,26 @@ interface IScrollbarUpdateContext {
position: boolean;
}
-export default class CustomScrollbars extends React.Component<IProps, IState> {
- public static defaultProps: IProps = {
- // auto-hide on macOS by default
- autoHide: window.env.platform === 'darwin',
+export default React.forwardRef(function CustomScrollbarsContainer(
+ props: IProps,
+ forwardRef: React.Ref<CustomScrollbars>,
+) {
+ const macOsScrollbarVisibility = useSelector(
+ (state) => state.userInterface.macOsScrollbarVisibility,
+ );
+ const autoHide =
+ props.autoHide ??
+ (window.env.platform === 'darwin' &&
+ (macOsScrollbarVisibility === undefined ||
+ macOsScrollbarVisibility === MacOsScrollbarVisibility.whenScrolling));
+
+ return <CustomScrollbars {...props} autoHide={autoHide} ref={forwardRef} />;
+});
+
+export type CustomScrollbarsRef = CustomScrollbars;
+
+class CustomScrollbars extends React.Component<IProps, IState> {
+ public static defaultProps: Partial<IProps> = {
trackPadding: { x: 2, y: 2 },
};
@@ -161,8 +179,8 @@ export default class CustomScrollbars extends React.Component<IProps, IState> {
return (
prevProps.children !== nextProps.children ||
prevProps.autoHide !== nextProps.autoHide ||
- prevProps.trackPadding.x !== nextProps.trackPadding.x ||
- prevProps.trackPadding.y !== nextProps.trackPadding.y ||
+ prevProps.trackPadding?.x !== nextProps.trackPadding?.x ||
+ prevProps.trackPadding?.y !== nextProps.trackPadding?.y ||
prevState.canScroll !== nextState.canScroll ||
prevState.showScrollIndicators !== nextState.showScrollIndicators ||
prevState.showTrack !== nextState.showTrack ||
@@ -350,7 +368,7 @@ export default class CustomScrollbars extends React.Component<IProps, IState> {
// a thumb at the lowest point matches the bottom of scrollable view
const thumbBoundary = this.computeTrackLength(scrollable) - thumb.clientHeight;
const thumbTop =
- pointInScrollContainer.y - this.state.dragStart.y - this.props.trackPadding.y;
+ pointInScrollContainer.y - this.state.dragStart.y - (this.props.trackPadding?.y ?? 0);
const newScrollTop = (thumbTop / thumbBoundary) * maxScrollTop;
scrollable.scrollTop = newScrollTop;
@@ -410,7 +428,7 @@ export default class CustomScrollbars extends React.Component<IProps, IState> {
}
private computeTrackLength(scrollable: HTMLElement) {
- return scrollable.offsetHeight - this.props.trackPadding.y * 2;
+ return scrollable.offsetHeight - (this.props.trackPadding?.y ?? 0) * 2;
}
// Computes the position of child element within scrollable container
@@ -471,10 +489,10 @@ export default class CustomScrollbars extends React.Component<IProps, IState> {
// calculate thumb position based on scroll progress and thumb boundary
// adding vertical inset to adjust the thumb's appearance
- const thumbPosition = thumbBoundary * scrollPosition + this.props.trackPadding.y;
+ const thumbPosition = thumbBoundary * scrollPosition + (this.props.trackPadding?.y ?? 0);
return {
- x: -this.props.trackPadding.x,
+ x: -(this.props.trackPadding?.x ?? 0),
y: thumbPosition,
};
}
diff --git a/gui/src/renderer/components/MacOsScrollbarDetection.tsx b/gui/src/renderer/components/MacOsScrollbarDetection.tsx
new file mode 100644
index 0000000000..69de63cc6a
--- /dev/null
+++ b/gui/src/renderer/components/MacOsScrollbarDetection.tsx
@@ -0,0 +1,41 @@
+import React, { useEffect, useRef } from 'react';
+import styled from 'styled-components';
+import useActions from '../lib/actionsHook';
+import userInterface from '../redux/userinterface/actions';
+import { useSelector } from '../redux/store';
+import { MacOsScrollbarVisibility } from '../../shared/ipc-schema';
+
+const StyledContainer = styled.div({
+ position: 'absolute',
+ visibility: 'hidden',
+ overflowY: 'scroll',
+ overflowX: 'hidden',
+ width: '1px',
+ height: '0px',
+});
+
+// This component is used to determine wheter scrollbars should be always visible or only visible
+// while scrolling when the system setting for this is set to "Automatic". This is detected by
+// testing if any space is taken by a scrollbar.
+export default function MacOsScrollbarDetection() {
+ const visibility = useSelector((state) => state.userInterface.macOsScrollbarVisibility);
+ const { setMacOsScrollbarVisibility } = useActions(userInterface);
+ const ref = useRef() as React.RefObject<HTMLDivElement>;
+
+ useEffect(() => {
+ if (visibility === MacOsScrollbarVisibility.automatic) {
+ // If the width is 0 then the 1 px width of the parent has been used by the scrollbar.
+ const newVisibility =
+ ref.current?.offsetWidth === 0
+ ? MacOsScrollbarVisibility.always
+ : MacOsScrollbarVisibility.whenScrolling;
+ setMacOsScrollbarVisibility(newVisibility);
+ }
+ }, [visibility]);
+
+ return (
+ <StyledContainer>
+ <div ref={ref} />
+ </StyledContainer>
+ );
+}
diff --git a/gui/src/renderer/components/NavigationBar.tsx b/gui/src/renderer/components/NavigationBar.tsx
index 9af5a4b615..e02ae99387 100644
--- a/gui/src/renderer/components/NavigationBar.tsx
+++ b/gui/src/renderer/components/NavigationBar.tsx
@@ -6,7 +6,7 @@ import { useHistory } from '../lib/history';
import { useCombinedRefs } from '../lib/utilityHooks';
import { useSelector } from '../redux/store';
import userInterface from '../redux/userinterface/actions';
-import CustomScrollbars, { IScrollEvent } from './CustomScrollbars';
+import CustomScrollbars, { CustomScrollbarsRef, IScrollEvent } from './CustomScrollbars';
import {
StyledBackBarItemButton,
StyledBackBarItemIcon,
@@ -112,12 +112,12 @@ interface INavigationScrollbarsProps {
export const NavigationScrollbars = React.forwardRef(function NavigationScrollbarsT(
props: INavigationScrollbarsProps,
- forwardedRef?: React.Ref<CustomScrollbars>,
+ forwardedRef?: React.Ref<CustomScrollbarsRef>,
) {
const history = useHistory();
const { onScroll } = useContext(NavigationScrollContext);
- const ref = useRef<CustomScrollbars>();
+ const ref = useRef<CustomScrollbarsRef>();
const combinedRefs = useCombinedRefs(forwardedRef, ref);
const { addScrollPosition, removeScrollPosition } = useActions(userInterface);
diff --git a/gui/src/renderer/components/SelectLanguage.tsx b/gui/src/renderer/components/SelectLanguage.tsx
index 7c67927182..38d20b09e3 100644
--- a/gui/src/renderer/components/SelectLanguage.tsx
+++ b/gui/src/renderer/components/SelectLanguage.tsx
@@ -3,7 +3,7 @@ import styled from 'styled-components';
import { colors } from '../../config.json';
import { messages } from '../../shared/gettext';
import { AriaInputGroup } from './AriaGroup';
-import CustomScrollbars from './CustomScrollbars';
+import { CustomScrollbarsRef } from './CustomScrollbars';
import { Container, Layout } from './Layout';
import {
BackBarItem,
@@ -40,7 +40,7 @@ const StyledSelector = (styled(Selector)({
}) as unknown) as new <T>() => Selector<T>;
export default class SelectLanguage extends React.Component<IProps, IState> {
- private scrollView = React.createRef<CustomScrollbars>();
+ private scrollView = React.createRef<CustomScrollbarsRef>();
private selectedCellRef = React.createRef<HTMLButtonElement>();
constructor(props: IProps) {
diff --git a/gui/src/renderer/components/SelectLocation.tsx b/gui/src/renderer/components/SelectLocation.tsx
index 2867ddaf45..528e8129ef 100644
--- a/gui/src/renderer/components/SelectLocation.tsx
+++ b/gui/src/renderer/components/SelectLocation.tsx
@@ -6,7 +6,7 @@ import { messages } from '../../shared/gettext';
import { IRelayLocationRedux } from '../redux/settings/reducers';
import { LocationScope } from '../redux/userinterface/reducers';
import BridgeLocations, { SpecialBridgeLocationType } from './BridgeLocations';
-import CustomScrollbars from './CustomScrollbars';
+import { CustomScrollbarsRef } from './CustomScrollbars';
import ExitLocations from './ExitLocations';
import ImageView from './ImageView';
import { Layout } from './Layout';
@@ -66,7 +66,7 @@ interface ISelectLocationSnapshot {
export default class SelectLocation extends React.Component<IProps, IState> {
public state = { showFilterMenu: false, headingHeight: 0 };
- private scrollView = React.createRef<CustomScrollbars>();
+ private scrollView = React.createRef<CustomScrollbarsRef>();
private spacePreAllocationViewRef = React.createRef<SpacePreAllocationView>();
private selectedExitLocationRef = React.createRef<React.ReactInstance>();
private selectedBridgeLocationRef = React.createRef<React.ReactInstance>();
diff --git a/gui/src/renderer/components/SplitTunnelingSettings.tsx b/gui/src/renderer/components/SplitTunnelingSettings.tsx
index 64faf178f2..97a4e5189c 100644
--- a/gui/src/renderer/components/SplitTunnelingSettings.tsx
+++ b/gui/src/renderer/components/SplitTunnelingSettings.tsx
@@ -11,7 +11,7 @@ import { IReduxState } from '../redux/store';
import Accordion from './Accordion';
import * as AppButton from './AppButton';
import * as Cell from './cell';
-import CustomScrollbars from './CustomScrollbars';
+import { CustomScrollbarsRef } from './CustomScrollbars';
import ImageView from './ImageView';
import { Layout } from './Layout';
import { ModalContainer, ModalAlert, ModalAlertType } from './Modal';
@@ -50,7 +50,7 @@ import {
export default function SplitTunneling() {
const { pop } = useHistory();
const [browsing, setBrowsing] = useState(false);
- const scrollbarsRef = useRef() as React.RefObject<CustomScrollbars>;
+ const scrollbarsRef = useRef() as React.RefObject<CustomScrollbarsRef>;
const scrollToTop = useCallback(() => scrollbarsRef.current?.scrollToTop(true), [scrollbarsRef]);
diff --git a/gui/src/renderer/redux/userinterface/actions.ts b/gui/src/renderer/redux/userinterface/actions.ts
index d0d1378a88..fd08dccd54 100644
--- a/gui/src/renderer/redux/userinterface/actions.ts
+++ b/gui/src/renderer/redux/userinterface/actions.ts
@@ -1,3 +1,4 @@
+import { MacOsScrollbarVisibility } from '../../../shared/ipc-schema';
import { LocationScope } from './reducers';
export interface IUpdateLocaleAction {
@@ -35,6 +36,11 @@ export interface IRemoveScrollPosition {
path: string;
}
+export interface ISetMacOsScrollbarVisibility {
+ type: 'SET_MACOS_SCROLLBAR_VISIBILITY';
+ visibility: MacOsScrollbarVisibility;
+}
+
export type UserInterfaceAction =
| IUpdateLocaleAction
| IUpdateWindowArrowPositionAction
@@ -42,7 +48,8 @@ export type UserInterfaceAction =
| ISetLocationScopeAction
| ISetWindowFocusedAction
| IAddScrollPosition
- | IRemoveScrollPosition;
+ | IRemoveScrollPosition
+ | ISetMacOsScrollbarVisibility;
function updateLocale(locale: string): IUpdateLocaleAction {
return {
@@ -93,6 +100,15 @@ function removeScrollPosition(path: string): IRemoveScrollPosition {
};
}
+function setMacOsScrollbarVisibility(
+ visibility: MacOsScrollbarVisibility,
+): ISetMacOsScrollbarVisibility {
+ return {
+ type: 'SET_MACOS_SCROLLBAR_VISIBILITY',
+ visibility,
+ };
+}
+
export default {
updateLocale,
updateWindowArrowPosition,
@@ -101,4 +117,5 @@ export default {
setWindowFocused,
addScrollPosition,
removeScrollPosition,
+ setMacOsScrollbarVisibility,
};
diff --git a/gui/src/renderer/redux/userinterface/reducers.ts b/gui/src/renderer/redux/userinterface/reducers.ts
index 05e091797e..846007f20a 100644
--- a/gui/src/renderer/redux/userinterface/reducers.ts
+++ b/gui/src/renderer/redux/userinterface/reducers.ts
@@ -1,3 +1,4 @@
+import { MacOsScrollbarVisibility } from '../../../shared/ipc-schema';
import { ReduxAction } from '../store';
export enum LocationScope {
@@ -12,6 +13,7 @@ export interface IUserInterfaceReduxState {
locationScope: LocationScope;
windowFocused: boolean;
scrollPosition: Record<string, [number, number]>;
+ macOsScrollbarVisibility?: MacOsScrollbarVisibility;
}
const initialState: IUserInterfaceReduxState = {
@@ -20,6 +22,7 @@ const initialState: IUserInterfaceReduxState = {
locationScope: LocationScope.relay,
windowFocused: false,
scrollPosition: {},
+ macOsScrollbarVisibility: undefined,
};
export default function (
@@ -54,6 +57,9 @@ export default function (
return { ...state, scrollPosition };
}
+ case 'SET_MACOS_SCROLLBAR_VISIBILITY':
+ return { ...state, macOsScrollbarVisibility: action.visibility };
+
default:
return state;
}
diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts
index a20213f424..cd39ac8c8a 100644
--- a/gui/src/shared/ipc-schema.ts
+++ b/gui/src/shared/ipc-schema.ts
@@ -39,6 +39,12 @@ export interface IRelayListPair {
export type LaunchApplicationResult = { success: true } | { error: string };
+export enum MacOsScrollbarVisibility {
+ always,
+ whenScrolling,
+ automatic,
+}
+
export interface IAppStateSnapshot {
isConnected: boolean;
autoStart: boolean;
@@ -53,6 +59,7 @@ export interface IAppStateSnapshot {
wireguardPublicKey?: IWireguardPublicKey;
translations: ITranslations;
windowsSplitTunnelingApplications?: IApplication[];
+ macOsScrollbarVisibility?: MacOsScrollbarVisibility;
}
// The different types of requests are:
@@ -98,11 +105,10 @@ export const ipcSchema = {
state: {
get: invokeSync<void, IAppStateSnapshot>(),
},
- windowShape: {
- '': notifyRenderer<IWindowShapeParameters>(),
- },
- windowFocus: {
- '': notifyRenderer<boolean>(),
+ window: {
+ shape: notifyRenderer<IWindowShapeParameters>(),
+ focus: notifyRenderer<boolean>(),
+ macOsScrollbarVisibility: notifyRenderer<MacOsScrollbarVisibility>(),
},
navigation: {
reset: notifyRenderer<void>(),