Refactor window management for macOS and Windows
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Updated `createWindow` and `createMainWindow` functions to conditionally set title bar styles and traffic light positions based on the operating system. - Enhanced window layout synchronization by introducing `syncMaximizedWindowFrame` and improving the logic in `isWindowWorkAreaMaximized` to account for maximized window frames. - Added functions to calculate DWM border padding and adjusted frame handling to ensure proper window sizing and positioning across different platforms.
This commit is contained in:
parent
cfb8c6ede1
commit
2a72697129
@ -205,8 +205,12 @@ export function createWindow() {
|
||||
width: 1200,
|
||||
height: 800,
|
||||
frame: false,
|
||||
titleBarStyle: 'hiddenInset',
|
||||
trafficLightPosition: { x: 14, y: 12 },
|
||||
...(process.platform === 'darwin'
|
||||
? {
|
||||
titleBarStyle: 'hiddenInset',
|
||||
trafficLightPosition: { x: 14, y: 12 }
|
||||
}
|
||||
: {}),
|
||||
backgroundColor: '#141414',
|
||||
icon: path.join(__dirname, './logo512.png'),
|
||||
webPreferences: {
|
||||
|
||||
@ -7,7 +7,8 @@ import {
|
||||
import { sendToRenderer, setMessageSender } from './notify.js'
|
||||
import {
|
||||
clampWindowToWorkArea,
|
||||
isWindowWorkAreaMaximized
|
||||
isWindowWorkAreaMaximized,
|
||||
syncMaximizedWindowFrame
|
||||
} from './windows-work-area.js'
|
||||
|
||||
const isMacOS = process.platform === 'darwin'
|
||||
@ -158,6 +159,11 @@ function applyStartupWindowState(window) {
|
||||
}
|
||||
|
||||
function syncWindowsWebviewLayout(window) {
|
||||
if (isWindowWorkAreaMaximized(window)) {
|
||||
syncMaximizedWindowFrame(window)
|
||||
return
|
||||
}
|
||||
|
||||
if (!window?.getSize || !window?.setSize) {
|
||||
return
|
||||
}
|
||||
@ -172,7 +178,7 @@ function syncWindowsWebviewLayout(window) {
|
||||
}
|
||||
|
||||
function handleWindowsWindowChange(window) {
|
||||
if (clampWindowToWorkArea(window)) {
|
||||
if (clampWindowToWorkArea(window) || isWindowWorkAreaMaximized(window)) {
|
||||
syncWindowsWebviewLayout(window)
|
||||
}
|
||||
|
||||
@ -246,10 +252,15 @@ export async function createMainWindow(rpc) {
|
||||
title: 'Farm Control',
|
||||
url,
|
||||
rpc,
|
||||
titleBarStyle: 'hiddenInset',
|
||||
...(isMacOS
|
||||
? { transparent: true, trafficLightOffset: MAC_TRAFFIC_LIGHT_OFFSET }
|
||||
: {}),
|
||||
? {
|
||||
titleBarStyle: 'hiddenInset',
|
||||
transparent: true,
|
||||
trafficLightOffset: MAC_TRAFFIC_LIGHT_OFFSET
|
||||
}
|
||||
: {
|
||||
titleBarStyle: 'hidden'
|
||||
}),
|
||||
frame: {
|
||||
width: 1200,
|
||||
height: 800,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Screen } from 'electrobun/bun'
|
||||
|
||||
const FRAME_TOLERANCE_PX = 4
|
||||
const BASE_DWM_BORDER_PX = 7
|
||||
|
||||
function framesMatch(a, b, tolerance = FRAME_TOLERANCE_PX) {
|
||||
return (
|
||||
@ -34,6 +35,33 @@ function getDisplayForFrame(frame) {
|
||||
return match ?? Screen.getPrimaryDisplay()
|
||||
}
|
||||
|
||||
function getDwmBorderPadding(display) {
|
||||
const scaleFactor = display?.scaleFactor ?? 1
|
||||
return Math.round(BASE_DWM_BORDER_PX * scaleFactor)
|
||||
}
|
||||
|
||||
function getMaximizedFrame(workArea, display) {
|
||||
const borderPx = getDwmBorderPadding(display)
|
||||
|
||||
// Windows keeps invisible resize borders on the left, right, and bottom when
|
||||
// maximized. Extend the outer frame so the webview fills the visible area.
|
||||
return {
|
||||
x: workArea.x - borderPx,
|
||||
y: workArea.y,
|
||||
width: workArea.width + borderPx * 2,
|
||||
height: workArea.height + borderPx
|
||||
}
|
||||
}
|
||||
|
||||
function frameCoversWorkArea(frame, workArea) {
|
||||
return (
|
||||
frame.x <= workArea.x + FRAME_TOLERANCE_PX &&
|
||||
frame.y <= workArea.y + FRAME_TOLERANCE_PX &&
|
||||
frame.x + frame.width >= workArea.x + workArea.width - FRAME_TOLERANCE_PX &&
|
||||
frame.y + frame.height >= workArea.y + workArea.height - FRAME_TOLERANCE_PX
|
||||
)
|
||||
}
|
||||
|
||||
function frameCoversMonitor(frame, bounds) {
|
||||
return (
|
||||
frame.x <= bounds.x + FRAME_TOLERANCE_PX &&
|
||||
@ -49,8 +77,14 @@ export function isWindowWorkAreaMaximized(window) {
|
||||
}
|
||||
|
||||
const frame = window.getFrame()
|
||||
const { workArea } = getDisplayForFrame(frame)
|
||||
return framesMatch(frame, workArea)
|
||||
const display = getDisplayForFrame(frame)
|
||||
const maximizedFrame = getMaximizedFrame(display.workArea, display)
|
||||
|
||||
return (
|
||||
framesMatch(frame, display.workArea) ||
|
||||
framesMatch(frame, maximizedFrame) ||
|
||||
frameCoversWorkArea(frame, display.workArea)
|
||||
)
|
||||
}
|
||||
|
||||
export function clampWindowToWorkArea(window) {
|
||||
@ -69,15 +103,60 @@ export function clampWindowToWorkArea(window) {
|
||||
|
||||
const display = getDisplayForFrame(frame)
|
||||
const { bounds, workArea } = display
|
||||
const maximizedFrame = getMaximizedFrame(workArea, display)
|
||||
|
||||
if (framesMatch(frame, workArea)) {
|
||||
if (framesMatch(frame, maximizedFrame)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!frameCoversMonitor(frame, bounds)) {
|
||||
if (
|
||||
!frameCoversWorkArea(frame, workArea) &&
|
||||
!frameCoversMonitor(frame, bounds)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
window.setFrame(workArea.x, workArea.y, workArea.width, workArea.height)
|
||||
window.setFrame(
|
||||
maximizedFrame.x,
|
||||
maximizedFrame.y,
|
||||
maximizedFrame.width,
|
||||
maximizedFrame.height
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
export function syncMaximizedWindowFrame(window) {
|
||||
if (!window?.getFrame || !window?.setFrame) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (window.isFullScreen?.()) {
|
||||
return false
|
||||
}
|
||||
|
||||
const frame = window.getFrame()
|
||||
if (!frame.width || !frame.height) {
|
||||
return false
|
||||
}
|
||||
|
||||
const display = getDisplayForFrame(frame)
|
||||
if (
|
||||
!frameCoversWorkArea(frame, display.workArea) &&
|
||||
!frameCoversMonitor(frame, display.bounds)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
const maximizedFrame = getMaximizedFrame(display.workArea, display)
|
||||
if (framesMatch(frame, maximizedFrame)) {
|
||||
return false
|
||||
}
|
||||
|
||||
window.setFrame(
|
||||
maximizedFrame.x,
|
||||
maximizedFrame.y,
|
||||
maximizedFrame.width,
|
||||
maximizedFrame.height
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user