Release 4.2.7+1: adaptive HiDPI window sizing (work-area DIPs + min size) and responsive CSS so the UI opens usable without stretch. Windows 4.2.7.1.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-08-02 12:00:10 +03:00
co-authored by Cursor
parent a1756715ef
commit fa3e11216e
15 changed files with 354 additions and 60 deletions
+215
View File
@@ -0,0 +1,215 @@
//go:build windows
package main
import (
"unsafe"
"github.com/jchv/go-webview2"
"golang.org/x/sys/windows"
)
// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = (DPI_AWARENESS_CONTEXT)-4
const dpiAwarenessContextPerMonitorAwareV2 = ^uintptr(3)
const (
spiGetWorkArea = 0x0030
monitorDefaultToNearest = 2
)
type monitorInfo struct {
CbSize uint32
RcMonitor windows.Rect
RcWork windows.Rect
DwFlags uint32
}
// enableProcessDPIAware opts into per-monitor DPI before any HWND is created.
// The embedded app.manifest already declares PerMonitorV2; this is a belt-and-
// suspenders call for builds that lose the manifest resource.
func enableProcessDPIAware() {
user32 := windows.NewLazySystemDLL("user32.dll")
if p := user32.NewProc("SetProcessDpiAwarenessContext"); p.Find() == nil {
_, _, _ = p.Call(dpiAwarenessContextPerMonitorAwareV2)
return
}
if p := user32.NewProc("SetProcessDPIAware"); p.Find() == nil {
_, _, _ = p.Call()
}
}
func systemDPI() int {
user32 := windows.NewLazySystemDLL("user32.dll")
if p := user32.NewProc("GetDpiForSystem"); p.Find() == nil {
if r, _, _ := p.Call(); r >= 72 && r <= 480 {
return int(r)
}
}
return 96
}
func windowDPI(hwnd uintptr) int {
if hwnd != 0 {
user32 := windows.NewLazySystemDLL("user32.dll")
if p := user32.NewProc("GetDpiForWindow"); p.Find() == nil {
if r, _, _ := p.Call(hwnd); r >= 72 && r <= 480 {
return int(r)
}
}
}
return systemDPI()
}
func dipsToPhysical(dips, dpi int) int {
if dpi <= 0 {
dpi = 96
}
return (dips*dpi + 48) / 96
}
func physicalToDIPs(px, dpi int) int {
if dpi <= 0 {
dpi = 96
}
return (px*96 + dpi/2) / dpi
}
func primaryWorkAreaPhysical() (w, h int, ok bool) {
var r windows.Rect
user32 := windows.NewLazySystemDLL("user32.dll")
p := user32.NewProc("SystemParametersInfoW")
ret, _, _ := p.Call(spiGetWorkArea, 0, uintptr(unsafe.Pointer(&r)), 0)
if ret == 0 {
return 0, 0, false
}
return int(r.Right - r.Left), int(r.Bottom - r.Top), true
}
func monitorWorkAreaPhysical(hwnd uintptr) (w, h int, ok bool) {
if hwnd == 0 {
return primaryWorkAreaPhysical()
}
user32 := windows.NewLazySystemDLL("user32.dll")
fromWin := user32.NewProc("MonitorFromWindow")
getInfo := user32.NewProc("GetMonitorInfoW")
if fromWin.Find() != nil || getInfo.Find() != nil {
return primaryWorkAreaPhysical()
}
hmon, _, _ := fromWin.Call(hwnd, monitorDefaultToNearest)
if hmon == 0 {
return primaryWorkAreaPhysical()
}
var mi monitorInfo
mi.CbSize = uint32(unsafe.Sizeof(mi))
ret, _, _ := getInfo.Call(hmon, uintptr(unsafe.Pointer(&mi)))
if ret == 0 {
return primaryWorkAreaPhysical()
}
return int(mi.RcWork.Right - mi.RcWork.Left), int(mi.RcWork.Bottom - mi.RcWork.Top), true
}
// computeClientSizeDIPs picks a comfortable client size in DIPs from the
// monitor work area (also expressed as physical px + dpi).
// Target: ~min(1100, workW*0.72) x min(780, workH*0.78), floored near
// 960x680 when the screen allows, always capped with margins.
func computeClientSizeDIPs(workWPhys, workHPhys, dpi int) (w, h int) {
if dpi <= 0 {
dpi = 96
}
workW := physicalToDIPs(workWPhys, dpi)
workH := physicalToDIPs(workHPhys, dpi)
if workW < 320 {
workW = 320
}
if workH < 240 {
workH = 240
}
const marginX, marginY = 64, 64
maxW := workW - marginX
maxH := workH - marginY
if maxW < 480 {
maxW = workW
}
if maxH < 360 {
maxH = workH
}
if maxW < 480 {
maxW = 480
}
if maxH < 360 {
maxH = 360
}
prefW := int(float64(workW) * 0.72)
if prefW > 1100 {
prefW = 1100
}
prefH := int(float64(workH) * 0.78)
if prefH > 780 {
prefH = 780
}
if prefW < 960 && maxW >= 960 {
prefW = 960
}
if prefH < 680 && maxH >= 680 {
prefH = 680
}
if prefW > maxW {
prefW = maxW
}
if prefH > maxH {
prefH = maxH
}
if prefW < 640 && maxW >= 640 {
prefW = 640
}
if prefH < 480 && maxH >= 480 {
prefH = 480
}
return prefW, prefH
}
// initialWindowPhysicalSize estimates CreateWindow size before an HWND exists
// (primary work area + system DPI). go-webview2 treats Width/Height as physical
// pixels when the process is DPI-aware.
func initialWindowPhysicalSize() (w, h int) {
dpi := systemDPI()
ww, wh, ok := primaryWorkAreaPhysical()
if !ok || ww <= 0 || wh <= 0 {
return dipsToPhysical(960, dpi), dipsToPhysical(680, dpi)
}
dipW, dipH := computeClientSizeDIPs(ww, wh, dpi)
return dipsToPhysical(dipW, dpi), dipsToPhysical(dipH, dpi)
}
// applyAdaptiveWindowSize sets HintMin (~720x520 DIPs) then the preferred
// client size from the window's monitor work area, both in physical pixels.
func applyAdaptiveWindowSize(w webview2.WebView) {
if w == nil {
return
}
hwnd := uintptr(w.Window())
dpi := windowDPI(hwnd)
ww, wh, ok := monitorWorkAreaPhysical(hwnd)
if !ok || ww <= 0 || wh <= 0 {
ww, wh, _ = primaryWorkAreaPhysical()
}
dipW, dipH := computeClientSizeDIPs(ww, wh, dpi)
physW := dipsToPhysical(dipW, dpi)
physH := dipsToPhysical(dipH, dpi)
minW := dipsToPhysical(720, dpi)
minH := dipsToPhysical(520, dpi)
if minW > physW {
minW = physW
}
if minH > physH {
minH = physH
}
w.SetSize(minW, minH, webview2.HintMin)
w.SetSize(physW, physH, webview2.HintNone)
}