DPI awareness.

This commit is contained in:
Nuno Cruces 2021-03-27 23:50:48 +00:00
parent 14ebdecd22
commit bde480b495

View File

@ -48,7 +48,11 @@ var (
isDialogMessage = user32.NewProc("IsDialogMessageW") isDialogMessage = user32.NewProc("IsDialogMessageW")
getSystemMetricsW = user32.NewProc("GetSystemMetrics") getSystemMetricsW = user32.NewProc("GetSystemMetrics")
systemParametersInfoW = user32.NewProc("SystemParametersInfoW") systemParametersInfoW = user32.NewProc("SystemParametersInfoW")
getWindowDC = user32.NewProc("GetWindowDC")
releaseDC = user32.NewProc("ReleaseDC")
getDpiForWindow = user32.NewProc("GetDpiForWindow")
getDeviceCaps = gdi32.NewProc("GetDeviceCaps")
createFontIndirectW = gdi32.NewProc("CreateFontIndirectW") createFontIndirectW = gdi32.NewProc("CreateFontIndirectW")
getModuleHandleW = kernel32.NewProc("GetModuleHandleW") getModuleHandleW = kernel32.NewProc("GetModuleHandleW")
@ -188,11 +192,35 @@ func getModuleHandle() (syscall.Handle, error) {
return syscall.Handle(ret), nil return syscall.Handle(ret), nil
} }
func createWindow(exStyle uint64, className, windowName string, style uint64, x, y, width, height int64, type dpi uintptr
func (d dpi) Scale(dim uintptr) uintptr {
return dim * uintptr(d) / 96 // USER_DEFAULT_SCREEN_DPI
}
func getDPI(wnd uintptr) (dpi, error) {
var res uintptr = 96
if wnd != 0 && getDpiForWindow.Find() == nil {
res, _, _ = getDpiForWindow.Call(wnd)
} else {
dc, _, err := getWindowDC.Call(wnd)
if dc == 0 {
return 0, err
}
defer releaseDC.Call(0, dc)
res, _, _ = getDeviceCaps.Call(dc, 90) // LOGPIXELSY
}
return dpi(res), nil
}
func createWindow(exStyle uint64, className, windowName string, style, x, y, width, height uintptr,
parent, menu, instance syscall.Handle) (syscall.Handle, error) { parent, menu, instance syscall.Handle) (syscall.Handle, error) {
ret, _, err := createWindowEx.Call(uintptr(exStyle), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(className))), ret, _, err := createWindowEx.Call(uintptr(exStyle), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(className))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(windowName))), uintptr(style), uintptr(x), uintptr(y), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(windowName))), uintptr(style), x, y,
uintptr(width), uintptr(height), uintptr(parent), uintptr(menu), uintptr(instance), uintptr(0)) width, height, uintptr(parent), uintptr(menu), uintptr(instance), uintptr(0))
if ret == 0 { if ret == 0 {
return 0, err return 0, err
@ -329,10 +357,9 @@ func messageLoop(hwnd uintptr) error {
translateMessage := translateMessage.Addr() translateMessage := translateMessage.Addr()
dispatchMessage := dispatchMessage.Addr() dispatchMessage := dispatchMessage.Addr()
var msg _MSG
var ptr = uintptr(unsafe.Pointer(&msg))
for { for {
ret, _, err := syscall.Syscall6(getMessage, 4, ptr, 0, 0, 0, 0, 0) var msg _MSG
ret, _, err := syscall.Syscall6(getMessage, 4, uintptr(unsafe.Pointer(&msg)), 0, 0, 0, 0, 0)
if int32(ret) == -1 { if int32(ret) == -1 {
return err return err
} }
@ -340,10 +367,10 @@ func messageLoop(hwnd uintptr) error {
return nil return nil
} }
ret, _, _ = syscall.Syscall(isDialogMessage, 2, hwnd, ptr, 0) ret, _, _ = syscall.Syscall(isDialogMessage, 2, hwnd, uintptr(unsafe.Pointer(&msg)), 0)
if ret == 0 { if ret == 0 {
syscall.Syscall(translateMessage, 1, ptr, 0, 0) syscall.Syscall(translateMessage, 1, uintptr(unsafe.Pointer(&msg)), 0, 0)
syscall.Syscall(dispatchMessage, 1, ptr, 0, 0) syscall.Syscall(dispatchMessage, 1, uintptr(unsafe.Pointer(&msg)), 0, 0)
} }
} }
} }
@ -380,6 +407,7 @@ func editBox(title, text, defaultText, className string, password bool) (string,
notCancledOrClosed = false notCancledOrClosed = false
destroyWindow(hwnd) destroyWindow(hwnd)
} }
case 0x2e0: // WM_DPICHANGED
default: default:
ret := defWindowProc(hwnd, msg, wparam, lparam) ret := defWindowProc(hwnd, msg, wparam, lparam)
return ret return ret
@ -388,23 +416,26 @@ func editBox(title, text, defaultText, className string, password bool) (string,
return 0 return 0
} }
defer setup()()
err = registerClass(className, instance, fn) err = registerClass(className, instance, fn)
if err != nil { if err != nil {
return out, false, err return out, false, err
} }
defer unregisterClass(className, instance) defer unregisterClass(className, instance)
hwnd, _ := createWindow(0, className, title, wsOverlappedWindow, swUseDefault, swUseDefault, 235, 140, 0, 0, instance) dpi, err := getDPI(0)
hwndText, _ := createWindow(0, "STATIC", text, wsChild|wsVisible, 10, 10, 200, 16, hwnd, 0, instance) hwnd, _ := createWindow(0, className, title, wsOverlappedWindow, swUseDefault, swUseDefault, dpi.Scale(235), dpi.Scale(140), 0, 0, instance)
hwndText, _ := createWindow(0, "STATIC", text, wsChild|wsVisible, dpi.Scale(10), dpi.Scale(10), dpi.Scale(200), dpi.Scale(16), hwnd, 0, instance)
flags := wsBorder | wsChild | wsVisible | wsGroup | wsTabStop | esAutoHScroll flags := wsBorder | wsChild | wsVisible | wsGroup | wsTabStop | esAutoHScroll
if password { if password {
flags |= esPassword flags |= esPassword
} }
hwndEdit, _ = createWindow(wsExClientEdge, "EDIT", defaultText, uint64(flags), 10, 30, 200, 24, hwnd, 0, instance) hwndEdit, _ = createWindow(wsExClientEdge, "EDIT", defaultText, uintptr(flags), dpi.Scale(10), dpi.Scale(30), dpi.Scale(200), dpi.Scale(24), hwnd, 0, instance)
hwndOK, _ := createWindow(wsExClientEdge, "BUTTON", "OK", wsChild|wsVisible|bsPushButton|wsGroup|wsTabStop, 10, 65, 90, 24, hwnd, 100, instance) hwndOK, _ := createWindow(wsExClientEdge, "BUTTON", "OK", wsChild|wsVisible|bsPushButton|wsGroup|wsTabStop, dpi.Scale(10), dpi.Scale(65), dpi.Scale(90), dpi.Scale(24), hwnd, 100, instance)
hwndCancel, _ := createWindow(wsExClientEdge, "BUTTON", "Cancel", wsChild|wsVisible|bsPushButton|wsGroup|wsTabStop, 120, 65, 90, 24, hwnd, 110, instance) hwndCancel, _ := createWindow(wsExClientEdge, "BUTTON", "Cancel", wsChild|wsVisible|bsPushButton|wsGroup|wsTabStop, dpi.Scale(120), dpi.Scale(65), dpi.Scale(90), dpi.Scale(24), hwnd, 110, instance)
setWindowLong(hwnd, gwlStyle, getWindowLong(hwnd, gwlStyle)^wsMinimizeBox) setWindowLong(hwnd, gwlStyle, getWindowLong(hwnd, gwlStyle)^wsMinimizeBox)
setWindowLong(hwnd, gwlStyle, getWindowLong(hwnd, gwlStyle)^wsMaximizeBox) setWindowLong(hwnd, gwlStyle, getWindowLong(hwnd, gwlStyle)^wsMaximizeBox)