Documentation
¶
Overview ¶
Package win32 is the pure-Go (CGO-free) Windows Win32/GDI windowing backend for the go-widgets toolkit. It registers a window class and creates a real top-level HWND, blits the toolkit's RGBA framebuffer into it through a top-down 32bpp DIB with StretchDIBits, and routes native WM_* mouse/wheel/key input into toolkit.Event, so a go-widgets widget tree runs on a Windows desktop exactly as it does on X11, Wayland, macOS or in the browser/wasm host.
The Win32 API is reached through the process' own kernel32/user32/gdi32 DLLs via syscall.NewLazyDLL + syscall.SyscallN and a syscall.NewCallback WNDPROC — no cgo — so the whole module builds and links with CGO_ENABLED=0.
This file is the SOVEREIGN, OS-INDEPENDENT half: the WM_*→toolkit.Event mapping (virtual-key decode, modifier decode, button/wheel mapping), the RGBA→BGRA DIB packing, the Per-Monitor-V2 DPI/size maths and the damage-rect→InvalidateRect conversion, all expressed over plain Go values with a single toolkit dependency (the event model). It carries NO syscall/unsafe/windows dependency, so it builds — and is unit-tested to 100% — on every GOOS, mirroring internal/cocoa's mapping.go and internal/wasmbox's protocol.go. The thin Win32 glue that actually creates the HWND, presents the DIB and pumps the message loop lives in win32_windows.go (//go:build windows) and drives everything here.
Index ¶
- Constants
- func A11yNodes(root toolkit.Widget) []toolkit.A11yNode
- func A11ySkip(n toolkit.A11yNode) bool
- func AnyButtonDown(wparam uintptr) bool
- func CenterOffset(avail, winExtent int) int
- func ClientCoords(px, py int, scale float64) (int, int)
- func DecodeMouseMods(wparam uintptr) (shift, ctrl bool)
- func DecodeVK(vk uint32) string
- func DefaultContentSize(workW, workH float64) (w, h int)
- func InvalidRect(r toolkit.Rect, scale float64) (x, y, w, h int)
- func LogicalFromPhysical(phys int, scale float64) int
- func MapCharDown(r rune, shift, ctrl bool) []toolkit.Event
- func MapCharUp(r rune, shift, ctrl bool) []toolkit.Event
- func MapKeyDown(vk uint32, shift, ctrl bool) []toolkit.Event
- func MapKeyUp(vk uint32, shift, ctrl bool) []toolkit.Event
- func MapMouseDown(x, y int, shift, ctrl bool) toolkit.Event
- func MapMouseMove(x, y int, buttonHeld, shift, ctrl bool) toolkit.Event
- func MapMouseUp(x, y int, shift, ctrl bool) toolkit.Event
- func MapWheel(x, y, delta int, shift, ctrl bool) toolkit.Event
- func PackBGRA(dst, src []byte)
- func PackBGRARect(dst, src []byte, width, height, x, y, w0, h0 int)
- func ParsePressPoint(s string) (x, y int, ok bool)
- func PhysicalFromLogical(logical int, scale float64) int
- func PressPoint(n toolkit.A11yNode) string
- func ScaleForDpi(dpi uint32) float64
- func ScreenRect(n toolkit.A11yNode, scale float64, originX, originY int) (x, y, w, h float64)
- func UIAControlType(r toolkit.Role) int32
Constants ¶
const ( CtButton = 50000 CtEdit = 50004 CtImage = 50006 CtListItem = 50007 CtList = 50008 CtMenu = 50009 CtMenuBar = 50010 CtProgress = 50012 CtSlider = 50015 CtSpinner = 50016 CtTab = 50018 CtText = 50020 CtToolBar = 50021 CtTree = 50023 CtGroup = 50026 CtDataGrid = 50028 CtDocument = 50030 CtWindow = 50032 CtPane = 50033 CtCheckBox = 50002 CtComboBox = 50003 CtRadio = 50013 )
UI Automation control type identifiers. A wrong number renames every element for the user, so these are the documented values rather than a guess.
Variables ¶
This section is empty.
Functions ¶
func A11yNodes ¶ added in v0.8.0
A11yNodes is the tree to publish for a widget root: every meaningful element, in visual order, with the ones no reader could use already removed.
func A11ySkip ¶ added in v0.8.0
A11ySkip reports whether a node should be left out of the published tree. An element with no name says nothing a screen reader could announce, and one with no area cannot be pointed at; either is a stop the user has to skip past for nothing.
func AnyButtonDown ¶
AnyButtonDown reports whether any mouse button is held per a WM_MOUSEMOVE wParam, which is how the backend distinguishes a drag from a plain hover move (the X11/Wayland backends read the same button mask; Cocoa gets it from the distinct -mouseDragged: selector).
func CenterOffset ¶
CenterOffset returns the top-left offset at which a window of outer size winExtent is centred within an axis of usable extent avail: (avail-winExtent)/2, clamped to 0 so a window larger than the work area is pinned to the origin rather than pushed off-screen. The caller adds the work-area origin (left/top) to place the window absolutely.
func ClientCoords ¶
ClientCoords converts a mouse position in physical client pixels (top-left origin, the space every WM_MOUSE* message reports) into framebuffer pixels — the LOGICAL-point coordinate space the toolkit framebuffer and every toolkit.Event uses. At the default render scale of 1 the two spaces coincide; at 150% a click at physical (300,150) maps to framebuffer (200,100), so a widget is hit where the user sees it. The result is clamped to be non-negative.
func DecodeMouseMods ¶
DecodeMouseMods splits a Win32 mouse-message wParam (its low word carries the MK_* key-state bits) into the toolkit's Shift/Ctrl booleans, so a Ctrl-click or Shift-click reaches a widget with the same flags an X11/Cocoa chord would.
func DecodeVK ¶
DecodeVK maps a Win32 virtual-key code to the toolkit's symbolic key NAME (DOM-style: "Enter", "ArrowLeft", …, exactly the names the toolkit widgets match and the X11/Cocoa/wasmbox backends emit). It returns "" for every key that is not one of the named editing/navigation keys — those carry a printable rune instead, delivered via the WM_CHAR path (MapCharDown).
func DefaultContentSize ¶
DefaultContentSize picks a readable default window content size, in LOGICAL points, from the monitor work area (workW×workH, also in logical points). It takes defaultScreenFraction of the work area and clamps each axis to the [min,max] readability band, then to the work extent so the window never exceeds the usable screen. When the work area is unknown (workW or workH ≤ 0) it returns the fixed fallback. The result is always ≥ 1×1 and ≤ the work area, so a defaulted window is legible without manual sizing. It mirrors the Cocoa backend's DefaultContentSize exactly.
func InvalidRect ¶
InvalidRect converts a damage rectangle in framebuffer (LOGICAL) pixels — the space RenderDamaged reports and the framebuffer uses — into a rectangle in physical client pixels, ready for InvalidateRect / the WM_PAINT update region. Because the framebuffer is logical and the client area is physical, the rect is multiplied by the render scale (the inverse of the Cocoa DirtyRect, which divides a device-pixel rect back to points). The rectangle is clamped to be non-negative and expanded to whole pixels (floor origin, ceil far edge) so a sub-pixel damage rect never leaves a seam on screen.
func LogicalFromPhysical ¶
LogicalFromPhysical converts a physical client extent (WM_SIZE reports the client area in device pixels) back to the logical-point size the framebuffer is rendered at, rounded to the nearest whole point and never below 1. It is the inverse of PhysicalFromLogical: at 150% a 1200-pixel client becomes an 800-point framebuffer, keeping the UI readable as the window resizes.
func MapCharDown ¶
MapCharDown turns a committed printable rune (from WM_CHAR on key press) into the EventKeyDown+EventChar pair the toolkit expects for text input — the same press/char split the X11 and Cocoa backends perform. A non-printable code (a control code such as the ^M/^I/^[ that WM_CHAR also delivers for Enter/Tab/Escape, or DEL) yields nothing, because those keys are already delivered as named keys through MapKeyDown.
func MapCharUp ¶
MapCharUp turns a printable rune (the glue translates the WM_KEYUP virtual key to its character) into the single EventKeyUp the toolkit expects on release. A non-printable rune yields nothing.
func MapKeyDown ¶
MapKeyDown turns a WM_KEYDOWN virtual key into the toolkit event(s) it produces. A NAMED key (Enter, ArrowLeft, …) yields a single EventKeyDown carrying the name in Code. A key that is not named yields nothing here: on Windows the printable character is not known until the OS translates the keystroke into the following WM_CHAR, so MapCharDown emits the KeyDown+Char pair for printables — keeping the toolkit's press/char split identical to the X11 and Cocoa backends.
func MapKeyUp ¶
MapKeyUp turns a WM_KEYUP virtual key into the toolkit event(s) it produces. A NAMED key yields a single EventKeyUp carrying the name; a non-named (printable) key's release is delivered via MapCharUp (the glue translates the virtual key to its rune), so a printable key produces EventKeyUp{rune} exactly as the X11 backend does.
func MapMouseDown ¶
MapMouseDown turns a WM_LBUTTONDOWN/WM_RBUTTONDOWN at the given framebuffer pixel into an EventClick, mirroring the X11 ButtonPress (buttons 1–3 → click) and Cocoa mapping. Windows delivers a distinct message per button; the backend routes all of them here, button-agnostically, exactly as the toolkit's click model expects.
func MapMouseMove ¶
MapMouseMove turns a WM_MOUSEMOVE into a drag (a button held) or a plain hover move (no button), per buttonHeld — the same drag-vs-move split the X11/Wayland backends derive from the event's button-state mask.
func MapMouseUp ¶
MapMouseUp turns a WM_LBUTTONUP/WM_RBUTTONUP into an EventMouseUp.
func MapWheel ¶
MapWheel turns a WM_MOUSEWHEEL delta into an EventScroll whose Delta is normalised to the toolkit's ±1 row step. Windows reports a POSITIVE delta when the wheel is rotated forward/away from the user (a scroll-up gesture); the toolkit's Delta is POSITIVE to scroll down/forward, so the sign is inverted — matching the browser/wheel convention the X11 and wasmbox backends use. A zero delta yields a Delta-0 EventScroll (harmless; scrollable widgets clamp it), so the mapping is total.
func PackBGRA ¶
func PackBGRA(dst, src []byte)
PackBGRA converts the whole RGBA framebuffer src (the toolkit's byte order: R,G,B,A) into the BGRA byte order a Win32 top-down 32bpp BI_RGB DIB requires (B,G,R,A), writing into dst. It swaps the R and B channels of every pixel and preserves G and A. dst and src must be the same length and a multiple of 4; any tail shorter than a whole pixel is left untouched. This is the pure core of the StretchDIBits present path.
func PackBGRARect ¶
PackBGRARect converts only the w0×h0 sub-rectangle at (x,y) of the RGBA framebuffer src into the BGRA DIB dst, both laid out as width×height 32bpp rows (stride = 4*width bytes). It is the damage-region packer: after an incremental repaint only the changed rectangle is re-packed before the damaged sub-blit, instead of re-packing the whole surface. The rectangle is clamped to the surface, so an out-of-bounds rect packs only its visible part (and an empty intersection packs nothing).
func ParsePressPoint ¶ added in v0.8.0
ParsePressPoint reads back what PressPoint wrote. A malformed value REFUSES rather than defaulting to (0,0), which is a real and usually clickable place.
func PhysicalFromLogical ¶
PhysicalFromLogical converts a logical-point extent to physical device pixels at the given render scale, rounded to the nearest whole pixel and never below 1 (a visible window always has a positive pixel size). It sizes the window's physical client area from the toolkit's logical layout: at 150% a 800-point content width becomes a 1200-pixel client area, so the OS shows the logical UI at a readable physical size.
func PressPoint ¶ added in v0.8.0
PressPoint encodes an element's centre in the LOGICAL points the input path speaks, as the string carried on its AutomationId.
Carrying the point ON the element beats a Go-side table keyed by index: the tree is rebuilt whenever the frame changes, and an index would go stale the moment content scrolled under a screen-reader user's cursor — invoking would then activate whatever moved into that slot.
func ScaleForDpi ¶
ScaleForDpi converts a Win32 DPI value (as returned by GetDpiForWindow / WM_DPICHANGED) into the framebuffer render scale: physical device pixels per logical point. 96 DPI (100%) → 1.0, 144 (150%) → 1.5, 192 (200%) → 2.0. A zero or negative DPI (an unavailable monitor) defaults to 1.0 so the maths never divides by zero downstream.
func ScreenRect ¶ added in v0.8.0
ScreenRect converts a node's rectangle from the LOGICAL points the toolkit lays out in to the PHYSICAL screen pixels UI Automation reports, given the window's DPI scale and the screen position of its client area.
Both halves matter and both are invisible when wrong: forgetting the scale puts every element at a fraction of its true size on a high-DPI display, and forgetting the origin reports each one relative to the window while the client places it on the desktop — so a screen reader's focus ring lands in the top-left corner of the screen instead of on the control.
func UIAControlType ¶ added in v0.8.0
UIAControlType maps a toolkit role to its UI Automation control type. Anything unrecognised becomes a group — UIA's "a thing containing things", the honest answer for a role this table does not know, and never a wrong announcement.
Types ¶
This section is empty.