Skip to content

Commit 568d091

Browse files
authored
alt+tab in desktop fix: drops menu focus now (#9644)
Signed-off-by: Denis Gladkiy <[email protected]>
1 parent dbdd989 commit 568d091

File tree

5 files changed

+64
-33
lines changed

5 files changed

+64
-33
lines changed

desktop/src/main/start.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,10 @@ const createWindow = async (): Promise<void> => {
273273
mainWindow?.webContents.send('window-state-changed', maximized ? 'maximized' : 'unmaximized')
274274
}
275275

276+
mainWindow.on('blur', () => {
277+
mainWindow?.webContents.send('window-focus-loss')
278+
});
279+
276280
mainWindow.on('maximize', () => {
277281
sendWindowMaximizedMessage(true)
278282
});
@@ -309,8 +313,18 @@ function sendCommand(cmd: string, ...args: any[]): void {
309313
mainWindow?.webContents.send(cmd, ...args)
310314
}
311315

316+
function activateWindow (): void {
317+
if (mainWindow) {
318+
if (mainWindow.isMinimized()) {
319+
mainWindow.restore()
320+
}
321+
mainWindow.show()
322+
mainWindow.focus()
323+
}
324+
}
325+
312326
if (isWindows) {
313-
setupWindowsSpecific(sendCommand)
327+
setupWindowsSpecific(activateWindow, sendCommand)
314328
} else {
315329
addMenus(sendCommand)
316330
}

desktop/src/main/windowsSpecificSetup.ts

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type JumpCommand = typeof JUMP_COMMANDS[keyof typeof JUMP_COMMANDS]
2727
const JUMP_TO_APP_COMMAND_PREFIX = '--jump-to-app='
2828

2929
function getIconPath(iconName: string): string {
30-
return path.join(process.resourcesPath, 'icons', iconName);
30+
return path.join(process.resourcesPath, 'icons', iconName)
3131
}
3232

3333
function addFixedFunctionJumpListItems(spares: JumpListSpares, tasks: JumpListItem[]): void {
@@ -61,55 +61,59 @@ export function rebuildJumpList(spares: JumpListSpares): void {
6161
}
6262

6363
for (const application of spares.applications) {
64+
const iconFileName = application.id.replaceAll(":", "_") + '.ico'
65+
const cliArguments = `${JUMP_TO_APP_COMMAND_PREFIX}${application.alias}`
6466
tasks.push({
6567
type: 'task',
6668
program: process.execPath,
67-
args: `${JUMP_TO_APP_COMMAND_PREFIX}${application.alias}`,
68-
iconPath: getIconPath(application.id.replaceAll(":", "_") + '.ico'),
69+
args: cliArguments,
70+
iconPath: getIconPath(iconFileName),
6971
title: application.title,
7072
iconIndex: 0,
71-
});
73+
})
7274
}
7375

7476
const category: JumpListCategory = {
7577
type: 'tasks',
7678
items: tasks,
7779
}
7880

79-
app.setJumpList([category]);
81+
app.setJumpList([category])
8082
}
8183

82-
export function setupWindowsSpecific(sendCommand: (cmd: Command, ...args: any[]) => void): void {
84+
export function setupWindowsSpecific(activateWindow: () => void, sendCommand: (cmd: Command, ...args: any[]) => void): void {
8385

84-
app.setAppUserModelId(app.getName());
86+
app.setAppUserModelId(app.getName())
8587

8688
app.on('second-instance', (_event: any, commandLine: any, _workingDirectory: any) => {
87-
const commandArgument = commandLine[1] as string;
89+
const commandArgument = commandLine[1] as string
8890
if (typeof commandArgument === 'string' && commandArgument.startsWith(JUMP_TO_APP_COMMAND_PREFIX)) {
89-
const applicationId = commandArgument.replace(JUMP_TO_APP_COMMAND_PREFIX, '');
90-
sendCommand(CommandOpenApplication, [applicationId]);
91-
return;
92-
}
93-
94-
const jumpCommandCode = commandArgument as JumpCommand;
95-
let command: Command | undefined;
96-
switch (jumpCommandCode) {
97-
case JUMP_COMMANDS.INBOX:
98-
command = CommandOpenInbox;
99-
break;
100-
case JUMP_COMMANDS.SETTINGS:
101-
command = CommandOpenSettings;
102-
break;
103-
default: {
104-
// compile-time check: if jumpCommand is not a known value, this line errors
105-
const _exhaustive: never = jumpCommandCode;
106-
return; // or handle error
91+
const applicationId = commandArgument.replace(JUMP_TO_APP_COMMAND_PREFIX, '')
92+
sendCommand(CommandOpenApplication, [applicationId])
93+
94+
} else {
95+
const jumpCommandCode = commandArgument as JumpCommand
96+
let command: Command | undefined
97+
switch (jumpCommandCode) {
98+
case JUMP_COMMANDS.INBOX:
99+
command = CommandOpenInbox
100+
break;
101+
case JUMP_COMMANDS.SETTINGS:
102+
command = CommandOpenSettings
103+
break;
104+
default: {
105+
// compile-time check: if jumpCommand is not a known value, this line errors
106+
const _exhaustive: never = jumpCommandCode
107+
return; // or handle error
108+
}
109+
}
110+
111+
if (command) {
112+
sendCommand(command)
107113
}
108114
}
109-
110-
if (command) {
111-
sendCommand(command);
112-
}
115+
116+
activateWindow()
113117
})
114118

115119
}

desktop/src/ui/preload.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ const expose: IPCMainExposed = {
7878
ipcRenderer.on('window-state-changed', callback)
7979
},
8080

81+
onWindowFocusLoss: (callback) => {
82+
ipcRenderer.on('window-focus-loss', callback)
83+
},
84+
8185
isOsUsingDarkTheme: async () => {
8286
return await ipcRenderer.invoke('get-is-os-using-dark-theme')
8387
},

desktop/src/ui/titleBarMenu.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { TitleBarMenuState } from './titleBarMenuState'
1919

2020
export function setupTitleBarMenu(ipcMain: IPCMainExposed, root: HTMLElement): MenuBar {
2121
const themeManager = new ThemeManager('light')
22-
const menuManager = new MenuBarManager(ipcMain, root)
22+
const menuManager = new MenuBarManager(root)
2323

2424
const menuBar = menuManager.getView();
2525

@@ -282,7 +282,7 @@ class MenuBarManager {
282282
private readonly StateStyleKeyboardSelected = 'desktop-app-keyboard-selected'
283283
private readonly StateStyleAltModeActive = 'desktop-app-alt-active'
284284

285-
constructor(ipcMain: IPCMainExposed, private readonly root: HTMLElement) {
285+
constructor(private readonly root: HTMLElement) {
286286
this.state = new TitleBarMenuState(
287287
() => this.topLevelMenus().length,
288288
(topLevelMenuIndex: number) => {
@@ -334,6 +334,13 @@ class MenuBarManager {
334334
document.querySelectorAll<HTMLButtonElement>(this.DropdownItemStyle + '[data-action]').forEach(item => {
335335
item.addEventListener('click', async () => this.handleMenuButtonClick(ipcMain, item))
336336
})
337+
338+
ipcMain.onWindowFocusLoss(() => {
339+
this.state.exitAltMode()
340+
this.altPressed = false
341+
this.controlKeysActivated = false
342+
this.renderState()
343+
})
337344
}
338345

339346
private renderState() {

desktop/src/ui/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ export interface IPCMainExposed {
142142
maximizeWindow: () => void
143143
closeWindow: () => void
144144
onWindowStateChange: (callback: (event: IpcRendererEvent, newState: string) => void) => void
145+
onWindowFocusLoss: (callback: () => void) => void
146+
145147
isOsUsingDarkTheme: () => Promise<boolean>
146148
executeMenuBarAction: (action: MenuBarAction) => void
147149

0 commit comments

Comments
 (0)