From 8a7db19e7339eda7a883fafa59f8b9cde4dbe80b Mon Sep 17 00:00:00 2001
From: fullex <106392080+0xfullex@users.noreply.github.com>
Date: Mon, 31 Mar 2025 21:07:16 +0800
Subject: [PATCH] fix: Resolve a series of miniWindow display issues and
improve app behavior across platforms (#3072)
---
src/main/services/ShortcutService.ts | 13 +-
src/main/services/WindowService.ts | 133 ++++++++++++++----
src/renderer/src/i18n/locales/en-us.json | 2 +-
src/renderer/src/i18n/locales/ja-jp.json | 2 +-
src/renderer/src/i18n/locales/ru-ru.json | 2 +-
src/renderer/src/i18n/locales/zh-cn.json | 2 +-
src/renderer/src/i18n/locales/zh-tw.json | 2 +-
.../src/pages/settings/GeneralSettings.tsx | 2 +-
8 files changed, 112 insertions(+), 46 deletions(-)
diff --git a/src/main/services/ShortcutService.ts b/src/main/services/ShortcutService.ts
index c4bad34d..03caa02d 100644
--- a/src/main/services/ShortcutService.ts
+++ b/src/main/services/ShortcutService.ts
@@ -23,17 +23,8 @@ function getShortcutHandler(shortcut: Shortcut) {
configManager.setZoomFactor(1)
}
case 'show_app':
- return (window: BrowserWindow) => {
- if (window.isVisible()) {
- if (window.isFocused()) {
- window.hide()
- } else {
- window.focus()
- }
- } else {
- window.show()
- window.focus()
- }
+ return () => {
+ windowService.toggleMainWindow()
}
case 'mini_window':
return () => {
diff --git a/src/main/services/WindowService.ts b/src/main/services/WindowService.ts
index f510f814..f72c5b1b 100644
--- a/src/main/services/WindowService.ts
+++ b/src/main/services/WindowService.ts
@@ -16,6 +16,9 @@ export class WindowService {
private mainWindow: BrowserWindow | null = null
private miniWindow: BrowserWindow | null = null
private wasFullScreen: boolean = false
+ //hacky-fix: store the focused status of mainWindow before miniWindow shows
+ //to restore the focus status when miniWindow hides
+ private wasMainWindowFocused: boolean = false
private selectionMenuWindow: BrowserWindow | null = null
private lastSelectedText: string = ''
private contextMenu: Menu | null = null
@@ -30,6 +33,7 @@ export class WindowService {
public createMainWindow(): BrowserWindow {
if (this.mainWindow && !this.mainWindow.isDestroyed()) {
this.mainWindow.show()
+ this.mainWindow.focus()
return this.mainWindow
}
@@ -56,7 +60,7 @@ export class WindowService {
titleBarOverlay: theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight,
backgroundColor: isMac ? undefined : theme === 'dark' ? '#181818' : '#FFFFFF',
trafficLightPosition: { x: 8, y: 12 },
- ...(process.platform === 'linux' ? { icon } : {}),
+ ...(isLinux ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
@@ -68,6 +72,12 @@ export class WindowService {
this.setupMainWindow(this.mainWindow, mainWindowState)
+ //preload miniWindow to resolve series of issues about miniWindow in Mac
+ const enableQuickAssistant = configManager.getEnableQuickAssistant()
+ if (enableQuickAssistant && !this.miniWindow) {
+ this.miniWindow = this.createMiniWindow(true)
+ }
+
return this.mainWindow
}
@@ -148,6 +158,8 @@ export class WindowService {
// show window only when laucn to tray not set
const isLaunchToTray = configManager.getLaunchToTray()
if (!isLaunchToTray) {
+ //[mac]hacky-fix: miniWindow set visibleOnFullScreen:true will cause dock icon disappeared
+ app.dock?.show()
mainWindow.show()
}
})
@@ -305,9 +317,8 @@ export class WindowService {
event.preventDefault()
mainWindow.hide()
- if (isMac && isTrayOnClose) {
- app.dock?.hide() //for mac to hide to tray
- }
+ //for mac users, should hide dock icon if close to tray
+ app.dock?.hide()
})
mainWindow.on('closed', () => {
@@ -328,44 +339,48 @@ export class WindowService {
if (this.mainWindow && !this.mainWindow.isDestroyed()) {
if (this.mainWindow.isMinimized()) {
- return this.mainWindow.restore()
+ this.mainWindow.restore()
+ return
}
+ //[macOS] Known Issue
+ // setVisibleOnAllWorkspaces true/false will NOT bring window to current desktop in Mac (works fine with Windows)
+ // AppleScript may be a solution, but it's not worth
+ this.mainWindow.setVisibleOnAllWorkspaces(true)
this.mainWindow.show()
this.mainWindow.focus()
+ this.mainWindow.setVisibleOnAllWorkspaces(false)
} else {
this.mainWindow = this.createMainWindow()
- this.mainWindow.focus()
}
-
- //for mac users, when window is shown, should show dock icon (dock may be set to hide when launch)
- app.dock?.show()
}
- public showMiniWindow() {
- const enableQuickAssistant = configManager.getEnableQuickAssistant()
-
- if (!enableQuickAssistant) {
+ public toggleMainWindow() {
+ // should not toggle main window when in full screen
+ if (this.wasFullScreen) {
return
}
- if (this.selectionMenuWindow && !this.selectionMenuWindow.isDestroyed()) {
- this.selectionMenuWindow.hide()
- }
-
- if (this.miniWindow && !this.miniWindow.isDestroyed()) {
- if (this.miniWindow.isMinimized()) {
- this.miniWindow.restore()
+ if (this.mainWindow && !this.mainWindow.isDestroyed() && this.mainWindow.isVisible()) {
+ if (this.mainWindow.isFocused()) {
+ // if tray is enabled, hide the main window, else do nothing
+ if (configManager.getTray()) {
+ this.mainWindow.hide()
+ app.dock?.hide()
+ }
+ } else {
+ this.mainWindow.focus()
}
- this.miniWindow.show()
- this.miniWindow.center()
- this.miniWindow.focus()
return
}
+ this.showMainWindow()
+ }
+
+ public createMiniWindow(isPreload: boolean = false): BrowserWindow {
this.miniWindow = new BrowserWindow({
width: 500,
height: 520,
- show: true,
+ show: false,
autoHideMenuBar: true,
transparent: isMac,
vibrancy: 'under-window',
@@ -375,6 +390,11 @@ export class WindowService {
alwaysOnTop: true,
resizable: false,
useContentSize: true,
+ ...(isMac ? { type: 'panel' } : {}),
+ skipTaskbar: true,
+ minimizable: false,
+ maximizable: false,
+ fullscreenable: false,
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
@@ -383,8 +403,23 @@ export class WindowService {
}
})
+ //miniWindow should show in current desktop
+ this.miniWindow?.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true })
+ //make miniWindow always on top of fullscreen apps with level set
+ this.miniWindow.setAlwaysOnTop(true, 'screen-saver', 1)
+
+ this.miniWindow.on('ready-to-show', () => {
+ if (isPreload) {
+ return
+ }
+
+ this.wasMainWindowFocused = this.mainWindow?.isFocused() || false
+ this.miniWindow?.center()
+ this.miniWindow?.show()
+ })
+
this.miniWindow.on('blur', () => {
- this.miniWindow?.hide()
+ this.hideMiniWindow()
})
this.miniWindow.on('closed', () => {
@@ -410,9 +445,48 @@ export class WindowService {
hash: '#/mini'
})
}
+
+ return this.miniWindow
+ }
+
+ public showMiniWindow() {
+ const enableQuickAssistant = configManager.getEnableQuickAssistant()
+
+ if (!enableQuickAssistant) {
+ return
+ }
+
+ if (this.selectionMenuWindow && !this.selectionMenuWindow.isDestroyed()) {
+ this.selectionMenuWindow.hide()
+ }
+
+ if (this.miniWindow && !this.miniWindow.isDestroyed()) {
+ this.wasMainWindowFocused = this.mainWindow?.isFocused() || false
+
+ if (this.miniWindow.isMinimized()) {
+ this.miniWindow.restore()
+ }
+ this.miniWindow.show()
+ return
+ }
+
+ this.miniWindow = this.createMiniWindow()
}
public hideMiniWindow() {
+ //hacky-fix:[mac/win] previous window(not self-app) should be focused again after miniWindow hide
+ if (isWin) {
+ this.miniWindow?.minimize()
+ this.miniWindow?.hide()
+ return
+ } else if (isMac) {
+ this.miniWindow?.hide()
+ if (!this.wasMainWindowFocused) {
+ app.hide()
+ }
+ return
+ }
+
this.miniWindow?.hide()
}
@@ -421,11 +495,12 @@ export class WindowService {
}
public toggleMiniWindow() {
- if (this.miniWindow) {
- this.miniWindow.isVisible() ? this.miniWindow.hide() : this.miniWindow.show()
- } else {
- this.showMiniWindow()
+ if (this.miniWindow && !this.miniWindow.isDestroyed() && this.miniWindow.isVisible()) {
+ this.hideMiniWindow()
+ return
}
+
+ this.showMiniWindow()
}
public showSelectionMenu(bounds: { x: number; y: number }) {
diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json
index a2054b9f..8a5e85f4 100644
--- a/src/renderer/src/i18n/locales/en-us.json
+++ b/src/renderer/src/i18n/locales/en-us.json
@@ -1190,7 +1190,7 @@
"reset_defaults_confirm": "Are you sure you want to reset all shortcuts?",
"reset_to_default": "Reset to Default",
"search_message": "Search Message",
- "show_app": "Show App",
+ "show_app": "Show/Hide App",
"show_settings": "Open Settings",
"title": "Keyboard Shortcuts",
"toggle_new_context": "Clear Context",
diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json
index 442b4c0a..d775707a 100644
--- a/src/renderer/src/i18n/locales/ja-jp.json
+++ b/src/renderer/src/i18n/locales/ja-jp.json
@@ -1189,7 +1189,7 @@
"reset_defaults_confirm": "すべてのショートカットをリセットしてもよろしいですか?",
"reset_to_default": "デフォルトにリセット",
"search_message": "メッセージを検索",
- "show_app": "アプリを表示",
+ "show_app": "アプリを表示/非表示",
"show_settings": "設定を開く",
"title": "ショートカット",
"toggle_new_context": "コンテキストをクリア",
diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json
index 636317d1..de4f0a66 100644
--- a/src/renderer/src/i18n/locales/ru-ru.json
+++ b/src/renderer/src/i18n/locales/ru-ru.json
@@ -1189,7 +1189,7 @@
"reset_defaults_confirm": "Вы уверены, что хотите сбросить все горячие клавиши?",
"reset_to_default": "Сбросить настройки по умолчанию",
"search_message": "Поиск сообщения",
- "show_app": "Показать приложение",
+ "show_app": "Показать/скрыть приложение",
"show_settings": "Открыть настройки",
"title": "Горячие клавиши",
"toggle_new_context": "Очистить контекст",
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index c7f6eb53..3ff6a79d 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -1190,7 +1190,7 @@
"reset_defaults_confirm": "确定要重置所有快捷键吗?",
"reset_to_default": "重置为默认",
"search_message": "搜索消息",
- "show_app": "显示应用",
+ "show_app": "显示/隐藏应用",
"show_settings": "打开设置",
"title": "快捷方式",
"toggle_new_context": "清除上下文",
diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json
index 222b1f0d..14027805 100644
--- a/src/renderer/src/i18n/locales/zh-tw.json
+++ b/src/renderer/src/i18n/locales/zh-tw.json
@@ -1189,7 +1189,7 @@
"reset_defaults_confirm": "確定要重設所有快捷鍵嗎?",
"reset_to_default": "重設為預設",
"search_message": "搜尋訊息",
- "show_app": "顯示應用程式",
+ "show_app": "顯示/隱藏應用程式",
"show_settings": "開啟設定",
"title": "快速方式",
"toggle_new_context": "清除上下文",
diff --git a/src/renderer/src/pages/settings/GeneralSettings.tsx b/src/renderer/src/pages/settings/GeneralSettings.tsx
index 65ef1102..34dfd062 100644
--- a/src/renderer/src/pages/settings/GeneralSettings.tsx
+++ b/src/renderer/src/pages/settings/GeneralSettings.tsx
@@ -175,7 +175,7 @@ const GeneralSettings: FC = () => {
{t('settings.tray.onclose')}
- updateTrayOnClose(checked)} disabled={!tray} />
+ updateTrayOnClose(checked)} />