fix(WindowService): miniWindow should show in current screen (#8132)

feat(WindowService): enhance mini window behavior and resizing logic

- Introduced dynamic resizing for the mini window based on user adjustments.
- Implemented positioning logic to ensure the mini window appears centered on the cursor's screen.
- Added opacity handling to improve user experience during window state changes.
- Refactored mini window creation to utilize predefined size constants for better maintainability.
This commit is contained in:
fullex 2025-07-15 18:10:30 +08:00 committed by GitHub
parent 76de357cbf
commit 397965f6e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -5,7 +5,7 @@ import { is } from '@electron-toolkit/utils'
import { isDev, isLinux, isMac, isWin } from '@main/constant'
import { getFilesDir } from '@main/utils/file'
import { IpcChannel } from '@shared/IpcChannel'
import { app, BrowserWindow, nativeTheme, shell } from 'electron'
import { app, BrowserWindow, nativeTheme, screen, shell } from 'electron'
import Logger from 'electron-log'
import windowStateKeeper from 'electron-window-state'
import { join } from 'path'
@ -16,6 +16,9 @@ import { configManager } from './ConfigManager'
import { contextMenu } from './ContextMenu'
import { initSessionUserAgent } from './WebviewService'
const DEFAULT_MINIWINDOW_WIDTH = 550
const DEFAULT_MINIWINDOW_HEIGHT = 400
export class WindowService {
private static instance: WindowService | null = null
private mainWindow: BrowserWindow | null = null
@ -26,6 +29,11 @@ export class WindowService {
private wasMainWindowFocused: boolean = false
private lastRendererProcessCrashTime: number = 0
private miniWindowSize: { width: number; height: number } = {
width: DEFAULT_MINIWINDOW_WIDTH,
height: DEFAULT_MINIWINDOW_HEIGHT
}
public static getInstance(): WindowService {
if (!WindowService.instance) {
WindowService.instance = new WindowService()
@ -426,8 +434,8 @@ export class WindowService {
public createMiniWindow(isPreload: boolean = false): BrowserWindow {
this.miniWindow = new BrowserWindow({
width: 550,
height: 400,
width: this.miniWindowSize.width,
height: this.miniWindowSize.height,
minWidth: 350,
minHeight: 380,
maxWidth: 1024,
@ -437,13 +445,12 @@ export class WindowService {
transparent: isMac,
vibrancy: 'under-window',
visualEffectState: 'followWindow',
center: true,
frame: false,
alwaysOnTop: true,
resizable: true,
useContentSize: true,
...(isMac ? { type: 'panel' } : {}),
skipTaskbar: true,
resizable: true,
minimizable: false,
maximizable: false,
fullscreenable: false,
@ -485,6 +492,13 @@ export class WindowService {
this.miniWindow?.webContents.send(IpcChannel.HideMiniWindow)
})
this.miniWindow.on('resized', () => {
this.miniWindowSize = this.miniWindow?.getBounds() || {
width: DEFAULT_MINIWINDOW_WIDTH,
height: DEFAULT_MINIWINDOW_HEIGHT
}
})
this.miniWindow.on('show', () => {
this.miniWindow?.webContents.send(IpcChannel.ShowMiniWindow)
})
@ -508,10 +522,48 @@ export class WindowService {
if (this.miniWindow && !this.miniWindow.isDestroyed()) {
this.wasMainWindowFocused = this.mainWindow?.isFocused() || false
if (this.miniWindow.isMinimized()) {
this.miniWindow.restore()
// [Windows] hacky fix
// the window is minimized only when in Windows platform
// because it's a workround for Windows, see `hideMiniWindow()`
if (this.miniWindow?.isMinimized()) {
// don't let the window being seen before we finish adusting the position across screens
this.miniWindow?.setOpacity(0)
// DO NOT use `restore()` here, Electron has the bug with screens of different scale factor
// We have to use `show()` here, then set the position and bounds
this.miniWindow?.show()
}
this.miniWindow.show()
const miniWindowBounds = this.miniWindow.getBounds()
// Check if miniWindow is on the same screen as mouse cursor
const cursorDisplay = screen.getDisplayNearestPoint(screen.getCursorScreenPoint())
const miniWindowDisplay = screen.getDisplayNearestPoint(miniWindowBounds)
// Show the miniWindow on the cursor's screen center
// If miniWindow is not on the same screen as cursor, move it to cursor's screen center
if (cursorDisplay.id !== miniWindowDisplay.id) {
const workArea = cursorDisplay.bounds
// use remembered size to avoid the bug of Electron with screens of different scale factor
const miniWindowWidth = this.miniWindowSize.width
const miniWindowHeight = this.miniWindowSize.height
// move to the center of the cursor's screen
const miniWindowX = Math.round(workArea.x + (workArea.width - miniWindowWidth) / 2)
const miniWindowY = Math.round(workArea.y + (workArea.height - miniWindowHeight) / 2)
this.miniWindow.setPosition(miniWindowX, miniWindowY, false)
this.miniWindow.setBounds({
x: miniWindowX,
y: miniWindowY,
width: miniWindowWidth,
height: miniWindowHeight
})
}
this.miniWindow?.setOpacity(1)
this.miniWindow?.show()
return
}
@ -519,20 +571,26 @@ export class WindowService {
}
public hideMiniWindow() {
//hacky-fix:[mac/win] previous window(not self-app) should be focused again after miniWindow hide
if (!this.miniWindow || this.miniWindow.isDestroyed()) {
return
}
//[macOs/Windows] hacky fix
// previous window(not self-app) should be focused again after miniWindow hide
// this workaround is to make previous window focused again after miniWindow hide
if (isWin) {
this.miniWindow?.minimize()
this.miniWindow?.hide()
this.miniWindow.setOpacity(0) // don't show the minimizing animation
this.miniWindow.minimize()
return
} else if (isMac) {
this.miniWindow?.hide()
this.miniWindow.hide()
if (!this.wasMainWindowFocused) {
app.hide()
}
return
}
this.miniWindow?.hide()
this.miniWindow.hide()
}
public closeMiniWindow() {