mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
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:
parent
76de357cbf
commit
397965f6e9
@ -5,7 +5,7 @@ import { is } from '@electron-toolkit/utils'
|
|||||||
import { isDev, isLinux, isMac, isWin } from '@main/constant'
|
import { isDev, isLinux, isMac, isWin } from '@main/constant'
|
||||||
import { getFilesDir } from '@main/utils/file'
|
import { getFilesDir } from '@main/utils/file'
|
||||||
import { IpcChannel } from '@shared/IpcChannel'
|
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 Logger from 'electron-log'
|
||||||
import windowStateKeeper from 'electron-window-state'
|
import windowStateKeeper from 'electron-window-state'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
@ -16,6 +16,9 @@ import { configManager } from './ConfigManager'
|
|||||||
import { contextMenu } from './ContextMenu'
|
import { contextMenu } from './ContextMenu'
|
||||||
import { initSessionUserAgent } from './WebviewService'
|
import { initSessionUserAgent } from './WebviewService'
|
||||||
|
|
||||||
|
const DEFAULT_MINIWINDOW_WIDTH = 550
|
||||||
|
const DEFAULT_MINIWINDOW_HEIGHT = 400
|
||||||
|
|
||||||
export class WindowService {
|
export class WindowService {
|
||||||
private static instance: WindowService | null = null
|
private static instance: WindowService | null = null
|
||||||
private mainWindow: BrowserWindow | null = null
|
private mainWindow: BrowserWindow | null = null
|
||||||
@ -26,6 +29,11 @@ export class WindowService {
|
|||||||
private wasMainWindowFocused: boolean = false
|
private wasMainWindowFocused: boolean = false
|
||||||
private lastRendererProcessCrashTime: number = 0
|
private lastRendererProcessCrashTime: number = 0
|
||||||
|
|
||||||
|
private miniWindowSize: { width: number; height: number } = {
|
||||||
|
width: DEFAULT_MINIWINDOW_WIDTH,
|
||||||
|
height: DEFAULT_MINIWINDOW_HEIGHT
|
||||||
|
}
|
||||||
|
|
||||||
public static getInstance(): WindowService {
|
public static getInstance(): WindowService {
|
||||||
if (!WindowService.instance) {
|
if (!WindowService.instance) {
|
||||||
WindowService.instance = new WindowService()
|
WindowService.instance = new WindowService()
|
||||||
@ -426,8 +434,8 @@ export class WindowService {
|
|||||||
|
|
||||||
public createMiniWindow(isPreload: boolean = false): BrowserWindow {
|
public createMiniWindow(isPreload: boolean = false): BrowserWindow {
|
||||||
this.miniWindow = new BrowserWindow({
|
this.miniWindow = new BrowserWindow({
|
||||||
width: 550,
|
width: this.miniWindowSize.width,
|
||||||
height: 400,
|
height: this.miniWindowSize.height,
|
||||||
minWidth: 350,
|
minWidth: 350,
|
||||||
minHeight: 380,
|
minHeight: 380,
|
||||||
maxWidth: 1024,
|
maxWidth: 1024,
|
||||||
@ -437,13 +445,12 @@ export class WindowService {
|
|||||||
transparent: isMac,
|
transparent: isMac,
|
||||||
vibrancy: 'under-window',
|
vibrancy: 'under-window',
|
||||||
visualEffectState: 'followWindow',
|
visualEffectState: 'followWindow',
|
||||||
center: true,
|
|
||||||
frame: false,
|
frame: false,
|
||||||
alwaysOnTop: true,
|
alwaysOnTop: true,
|
||||||
resizable: true,
|
|
||||||
useContentSize: true,
|
useContentSize: true,
|
||||||
...(isMac ? { type: 'panel' } : {}),
|
...(isMac ? { type: 'panel' } : {}),
|
||||||
skipTaskbar: true,
|
skipTaskbar: true,
|
||||||
|
resizable: true,
|
||||||
minimizable: false,
|
minimizable: false,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
fullscreenable: false,
|
fullscreenable: false,
|
||||||
@ -485,6 +492,13 @@ export class WindowService {
|
|||||||
this.miniWindow?.webContents.send(IpcChannel.HideMiniWindow)
|
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.on('show', () => {
|
||||||
this.miniWindow?.webContents.send(IpcChannel.ShowMiniWindow)
|
this.miniWindow?.webContents.send(IpcChannel.ShowMiniWindow)
|
||||||
})
|
})
|
||||||
@ -508,10 +522,48 @@ export class WindowService {
|
|||||||
if (this.miniWindow && !this.miniWindow.isDestroyed()) {
|
if (this.miniWindow && !this.miniWindow.isDestroyed()) {
|
||||||
this.wasMainWindowFocused = this.mainWindow?.isFocused() || false
|
this.wasMainWindowFocused = this.mainWindow?.isFocused() || false
|
||||||
|
|
||||||
if (this.miniWindow.isMinimized()) {
|
// [Windows] hacky fix
|
||||||
this.miniWindow.restore()
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,20 +571,26 @@ export class WindowService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hideMiniWindow() {
|
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) {
|
if (isWin) {
|
||||||
this.miniWindow?.minimize()
|
this.miniWindow.setOpacity(0) // don't show the minimizing animation
|
||||||
this.miniWindow?.hide()
|
this.miniWindow.minimize()
|
||||||
return
|
return
|
||||||
} else if (isMac) {
|
} else if (isMac) {
|
||||||
this.miniWindow?.hide()
|
this.miniWindow.hide()
|
||||||
if (!this.wasMainWindowFocused) {
|
if (!this.wasMainWindowFocused) {
|
||||||
app.hide()
|
app.hide()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.miniWindow?.hide()
|
this.miniWindow.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeMiniWindow() {
|
public closeMiniWindow() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user