mirror of
https://github.com/Boof2015/prism.git
synced 2026-08-12 05:10:51 +02:00
fix hover state bug
This commit is contained in:
@@ -695,6 +695,16 @@ function stopWindowResizeController(): void {
|
||||
resizeEdge = null
|
||||
}
|
||||
|
||||
function isCursorInsideWindow(window: BrowserWindow): boolean {
|
||||
const cursor = screen.getCursorScreenPoint()
|
||||
const bounds = window.getBounds()
|
||||
|
||||
return cursor.x > bounds.x
|
||||
&& cursor.x < bounds.x + bounds.width
|
||||
&& cursor.y > bounds.y
|
||||
&& cursor.y < bounds.y + bounds.height
|
||||
}
|
||||
|
||||
function getFramelessWindowChromeOptions(): Pick<
|
||||
BrowserWindowConstructorOptions,
|
||||
'frame' | 'transparent' | 'backgroundColor' | 'roundedCorners' | 'hasShadow' | 'thickFrame' | 'backgroundMaterial'
|
||||
@@ -1445,6 +1455,11 @@ function setupIPC(): void {
|
||||
return getWindowFromSender(event.sender)?.isAlwaysOnTop() ?? false
|
||||
})
|
||||
|
||||
ipcMain.handle('window:is-cursor-inside', (event) => {
|
||||
const targetWindow = getWindowFromSender(event.sender)
|
||||
return targetWindow ? isCursorInsideWindow(targetWindow) : false
|
||||
})
|
||||
|
||||
ipcMain.handle('app:get-build-info', () => {
|
||||
return getAppBuildInfo()
|
||||
})
|
||||
|
||||
@@ -59,6 +59,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
repositionWindow: (position: 'top' | 'bottom') => ipcRenderer.send('window:reposition', position),
|
||||
toggleAlwaysOnTop: () => ipcRenderer.send('window:toggle-always-on-top'),
|
||||
isAlwaysOnTop: () => ipcRenderer.invoke('window:is-always-on-top'),
|
||||
isCursorInsideWindow: () => ipcRenderer.invoke('window:is-cursor-inside') as Promise<boolean>,
|
||||
getCaptureBackendSupport: async () => getCaptureBackendSupport(process.platform, nativeCaptureAPI) as CaptureBackendSupport,
|
||||
getNowPlayingState: () => ipcRenderer.invoke('now-playing:get-state') as Promise<NowPlayingState>,
|
||||
setNowPlayingConsumerActive: (active: boolean) => ipcRenderer.invoke('now-playing:set-active', active) as Promise<NowPlayingState>,
|
||||
|
||||
+60
-3
@@ -20,6 +20,7 @@ export default function App(): JSX.Element {
|
||||
const [settingsPanelHeight, setSettingsPanelHeight] = useState(0)
|
||||
const [bottomBarHeight, setBottomBarHeight] = useState(0)
|
||||
const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const settingsOpenRef = useRef(false)
|
||||
const externalProfileOpenQueueRef = useRef(Promise.resolve())
|
||||
|
||||
const initializeProfiles = useSettingsStore((s) => s.initializeProfiles)
|
||||
@@ -175,12 +176,67 @@ export default function App(): JSX.Element {
|
||||
setToolbarVisible(true)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
settingsOpenRef.current = settingsOpen
|
||||
if (settingsOpen) {
|
||||
showToolbar()
|
||||
}
|
||||
}, [settingsOpen, showToolbar])
|
||||
|
||||
const scheduleHide = useCallback(() => {
|
||||
if (settingsOpen) return
|
||||
if (settingsOpenRef.current || hideTimeoutRef.current) return
|
||||
|
||||
hideTimeoutRef.current = setTimeout(() => {
|
||||
hideTimeoutRef.current = null
|
||||
if (settingsOpenRef.current) return
|
||||
setToolbarVisible(false)
|
||||
}, 400)
|
||||
}, [settingsOpen])
|
||||
}, [])
|
||||
|
||||
const handleToolbarHoverLeave = useCallback((event: React.MouseEvent<HTMLDivElement>) => {
|
||||
const relatedTarget = event.relatedTarget
|
||||
if (relatedTarget instanceof Node && event.currentTarget.contains(relatedTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
const bounds = event.currentTarget.getBoundingClientRect()
|
||||
const isPointerInside = event.clientX > bounds.left
|
||||
&& event.clientX < bounds.right
|
||||
&& event.clientY > bounds.top
|
||||
&& event.clientY < bounds.bottom
|
||||
|
||||
if (isPointerInside) {
|
||||
showToolbar()
|
||||
return
|
||||
}
|
||||
|
||||
scheduleHide()
|
||||
}, [scheduleHide, showToolbar])
|
||||
|
||||
useEffect(() => {
|
||||
if (!toolbarVisible || settingsOpen) return
|
||||
|
||||
let isDisposed = false
|
||||
const checkCursorInsideWindow = (): void => {
|
||||
void window.electronAPI.isCursorInsideWindow()
|
||||
.then((isInside) => {
|
||||
if (!isDisposed && !isInside) {
|
||||
scheduleHide()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// Renderer leave events still handle auto-hide if the cursor query is unavailable.
|
||||
})
|
||||
}
|
||||
|
||||
checkCursorInsideWindow()
|
||||
const interval = setInterval(checkCursorInsideWindow, 120)
|
||||
|
||||
return () => {
|
||||
isDisposed = true
|
||||
clearInterval(interval)
|
||||
}
|
||||
}, [scheduleHide, settingsOpen, toolbarVisible])
|
||||
|
||||
const handleToggleSettings = useCallback(() => {
|
||||
toggleSettings()
|
||||
@@ -222,7 +278,8 @@ export default function App(): JSX.Element {
|
||||
<div
|
||||
className="prism-app"
|
||||
onMouseEnter={showToolbar}
|
||||
onMouseLeave={scheduleHide}
|
||||
onMouseMove={showToolbar}
|
||||
onMouseLeave={handleToolbarHoverLeave}
|
||||
onMouseDown={useNativeDragRegions ? undefined : handleAltDragStart}
|
||||
onMouseUp={useNativeDragRegions ? undefined : handleAltDragEnd}
|
||||
>
|
||||
|
||||
Vendored
+1
@@ -55,6 +55,7 @@ declare global {
|
||||
repositionWindow: (position: 'top' | 'bottom') => void
|
||||
toggleAlwaysOnTop: () => void
|
||||
isAlwaysOnTop: () => Promise<boolean>
|
||||
isCursorInsideWindow: () => Promise<boolean>
|
||||
getCaptureBackendSupport: () => Promise<CaptureBackendSupport>
|
||||
getNowPlayingState: () => Promise<NowPlayingState>
|
||||
setNowPlayingConsumerActive: (active: boolean) => Promise<NowPlayingState>
|
||||
|
||||
Reference in New Issue
Block a user