Zum Inhalt springen
Natives Fenster

Ein natives Fenster

go-widgets/window: eine einzige Open/Run-API über X11, Wayland, GTK4, Cocoa, Win32, Android, wasmbox und einen Browser-Tab, alle mit CGO_ENABLED=0.

go-widgets/window öffnet ein echtes Fenster und führt darin einen Widget-Baum aus: Layout, Zeichnen, Darstellen, Eingaben in toolkit.Event übersetzen, wiederholen, bis das Fenster geschlossen wird.

w, err := window.Open(window.Config{Title: "Demo"})
if err != nil {
	return err
}
defer w.Close()
return w.Run(root) // root is any toolkit.Widget

Config nimmt außerdem die Anfangsgröße in logischen Punkten (null bittet um einen lesbaren Standardwert), Instanz und Klasse für WM_CLASS, ein Theme und eine RenderScale.

Wie Open auswählt

Plattform und UmgebungBack-EndWie es auf den Bildschirm kommt
Linux, $GO_WIDGETS_GTK gesetztGTK4GTK besitzt das Fenster; der Framebuffer ist ein GtkPicture, und native Bedienelemente sind echte GTK-Widgets darüber. Benötigt die libgtk-4-Laufzeitbibliothek.
Linux, $WAYLAND_DISPLAY gesetztWaylandxdg-shell über den Unix-Socket des Compositors
Linux, sonst $DISPLAYX11das X11-Kernprotokoll über den Unix-Socket, mit MIT-SHM
macOSCocoaNSWindow und NSView über go-macos/objc (purego)
WindowsWin32ein Top-Level-HWND über Syscalls von user32 und gdi32, StretchDIBits
Android, $GW_ANDROID_SOCKET gesetztAndroid-Hostein gerahmtes Protokoll zum Java-Host, Pixel in einem gemeinsamen memfd
Android, sonstWayland oder X11eine Shell unter Termux hat trotzdem einen Display-Server, mit dem sie sich verbinden kann
js/wasm, innerhalb von wasmdeskwasmboxein Client des wasmdesk-Compositors
js/wasm, eine gewöhnliche SeiteBrowser-Tabein <canvas> der Seite (Config.Canvas, Standard "screen") über webcanvas: kein Compositor, kein SharedArrayBuffer, keine Cross-Origin-Isolation
alles andere—window.ErrUnsupported, damit ein Cross-Build trotzdem kompiliert

Jedes Back-End ist CGO_ENABLED=0. Das X11-Back-End ist das Kernprotokoll, von Grund auf über dem Socket geschrieben – kein Xlib, kein XCB –, mit beiden Byte-Reihenfolgen, dem Xauthority-Cookie, Keysym-Zuordnung, PutImage in Kacheln unterhalb der Anfragegröße des Servers und dem schnellen MIT-SHM-Pfad, wobei das gemeinsame Segment über SCM_RIGHTS übergeben wird. Windows wird über die prozesseigenen DLLs mit syscall.NewLazyDLL und einer Fensterprozedur per syscall.NewCallback erreicht; macOS über die Objective-C-Runtime mit purego.

Der plattformunabhängige Teil jedes Back-Ends – Ereigniszuordnung, Koordinaten- mathematik, Pixel-Packing, Schadensrechtecke – liegt in einem Codec, der zu 100 % abgedeckt ist, auf jedem Betriebssystem. Die dünne Plattformanbindung ist live nachgewiesen: siehe Stand.

Nur was sich geändert hat

Eine Wurzel, die DamageRenderer implementiert (wie toolkit/scene.HostRoot), meldet die Rechtecke, die sie neu gezeichnet hat, und jedes Back-End außer GTK4 stellt nur diese dar: X11 über MIT-SHM ShmPutImage, Wayland über wl_shm-Damage, Cocoa, Win32, Android, wasmbox und der Browser-Tab. Der erste Frame, eine Größenänderung und ein X11-Expose stellen weiterhin die ganze Oberfläche dar.

HiDPI

Standard ist ein Framebuffer-Pixel pro logischem Punkt: Die UI wird in einer lesbaren Größe angeordnet und gezeichnet, und der Compositor skaliert sie hoch. Unter Windows deklariert das Fenster DPI-Bewusstsein pro Monitor, und das Betriebssystem skaliert den logischen Frame auf den physischen Client-Bereich. RenderScale fordert einen Framebuffer in der echten Auflösung des Bildschirms an, was nur für eine Wurzel korrekt ist, die in Gerätepixeln anordnet.

Bildschirme, Anzeigen und Ausblenden

window.Screens() listet die angeschlossenen Displays auf, das primäre zuerst, in logischen Punkten und ohne die Leisten des Desktops, und kann vor Open aufgerufen werden. Der Name eines Bildschirms ist der des Panels selbst ("DELL U2720Q", aus seiner EDID), mit Rückfall auf den Anschluss ("HDMI-1"), wenn es keinen veröffentlicht – und auch, wenn zwei angeschlossene Panels denselben veröffentlichen, denn ein Name, der sie nicht unterscheiden kann, ist kein Name.

window.Show, Hide und Raise nehmen ein offenes Fenster vom Bildschirm, ohne es zu schließen, und holen es zurück – was eine Tray-Anwendung braucht.

Back-EndShowHideRaise
X11MapWindowICCCM-Withdraw, sodass es die Taskleiste verlässtMap, Raise, _NET_ACTIVE_WINDOW
Waylanderneuter CommitNull-Puffer und CommitErrNotSupported: xdg-shell hat keine solche Anfrage
macOSorderFront:orderOut:die App aktivieren, makeKeyAndOrderFront:
WindowsSW_SHOWNASW_HIDESW_RESTORE und SetForegroundWindow
GTK, Android, wasmbox, Browser-TabErrNotSupportedErrNotSupportedErrNotSupported

Den Fokus gewährt die Plattform: Unter einem Schutz gegen Fokusraub kann Raise das Fenster möglicherweise nur als aufmerksamkeitsbedürftig markieren und kann das nicht erkennen.

Erstellt am von tannevaled

Geändert am von tannevaled