apprt: minimal Win32 skeleton (window + WGL + CoreSurface wiring)#12403
apprt: minimal Win32 skeleton (window + WGL + CoreSurface wiring)#12403mattn wants to merge 6 commits intoghostty-org:mainfrom
Conversation
Introduce a new `win32` apprt backend that creates a native Win32 window and runs a standard message loop. This enables `zig build` on Windows (with MinGW/GNU ABI) to produce a working ghostty.exe. Changes: - Add `win32` variant to apprt Runtime enum, defaulting on Windows - Create win32/App.zig with Win32 window creation and event loop - Create win32/Surface.zig stub - Link user32, gdi32, opengl32 for win32 runtime in SharedDeps - Fix DllMain for GNU ABI (provide no-op handler instead of void type) - Handle win32 case in Config.zig apprt-specific defaults The window opens but does not yet render terminal content. Next steps include OpenGL context setup, ConPTY integration, and input handling. Co-authored-by: Claude <noreply@anthropic.com>
- Create WGL OpenGL context in Surface.zig with pixel format setup - Add core Surface interface methods (getContentScale, getSize, etc.) - Add win32 cases to OpenGL.zig renderer (surfaceInit, threadEnter, threadExit) - Fix Clipboard.getGObjectType for win32 runtime in structs.zig - Store App pointer in HWND userdata for wndProc callbacks - Handle WM_SIZE to track window dimensions Co-authored-by: Claude <noreply@anthropic.com>
- Initialize CoreSurface in App.initCoreSurface() with config and surfaces - Release WGL context from main thread in finalizeSurfaceInit - Re-acquire WGL context on renderer thread in threadEnter - Release context in threadExit - Add makeContextCurrent/releaseContext to win32 Surface - Store App pointer in Surface for rtApp() method - cmd.exe now starts successfully via ConPTY Co-authored-by: Claude <noreply@anthropic.com>
- Call swapBuffers() after drawFrame on Win32 to present rendered content - Forward WM_SIZE to CoreSurface.sizeCallback for terminal resize - Use @hasDecl to conditionally call swapBuffers only on Win32 Co-authored-by: Claude <noreply@anthropic.com>
|
Here's my feedback. I'm not a ghostty maintainer but I have alot of experience writing code for Windows. It looks like there's alot of return values being ignored. IMO you should almost never ignore a return value when calling a win32 function. In addition, when an error is being handled, the error should be retrieved via GetLastError to see what went wrong, probably logged somewhere. You're also free to leverage "zigwin32" for all these type/function definitions from the win32 API. It's found at https://github.com/marlersoft/zigwin32, I'd add this as a dependency and here's how I'd recommend using it: const win32 = @import("win32").everything;
const my_hello_string= win32.L("Hello");
const hwnd = win32.CreateWindowExW(...) orelse win32.panicWin32("CreateWindow", win32.GetLastError());Since the win32 API is in C, every symbol pretty much has to be unique so we can expose it all in a single namespace. For many functions in win32, if they fail, something has gone horribly wrong. For these kinds of functions you can simply call const dpi = win32.dpiFromHwnd(hwnd);
const client_size = win32.getClientSize(hwnd);
_, const ps = win32.beginPaint(hwnd);
defer win32.endPaint(hwnd, &ps); |
Add GetLastError-based warning logs for Win32 calls whose failure is worth surfacing: PostMessageW (wakeup), DestroyWindow, SwapBuffers, and wglMakeCurrent. Other ignored returns (TranslateMessage, DispatchMessageW, ShowWindow, UpdateWindow, EndPaint, SetWindowLongPtrW on first call) do not indicate errors and are intentionally unchecked. Co-authored-by: Claude <noreply@anthropic.com>
|
Thanks! Addressed the ignored-return issue in 289c6a5. Added Re: |
|
Re: |
Per @marler8997 and @jcollie, use the marlersoft/zigwin32 bindings instead of hand-rolled extern decls for the Win32 API. Drops the inline type / constant / function declarations in App.zig and Surface.zig in favor of `@import("win32").everything`. The binding is declared lazy in build.zig.zon so it's only fetched when building the win32 apprt. Net effect: -240 / +101 lines. Type-safe style flags (packed structs for `WNDCLASS_STYLES`, `WINDOW_STYLE`, pixel format flags) replace raw OR'd u32 constants. Also clears a known Zig 0.16 risk since std.os.windows is shedding symbols the earlier code was relying on (pointed out in jcollie's review note). Co-authored-by: Claude <noreply@anthropic.com>
|
Ported the apprt to zigwin32 in 2ad00dc. Dropped the hand-rolled extern decls in App.zig and Surface.zig and now go through |
First Tier 2 PR of the win32-apprt upstreaming series. Adds a
.win32variant to the apprt Runtime enum, defaulting on Windows exe builds, and enough surface/renderer wiring thatzig build -Dtarget=native-native-gnuproduces aghostty.exewhich opens a window and runscmd.exeunder ConPTY. The result is a working terminal at a basic level -- you can see output and the terminal resizes with the window.The four commits stack in a straightforward order:
src/apprt/win32/App.zigcreates the HWND and runs the message loop,src/apprt/win32/Surface.zigis a stub. Window opens, no rendering yet.Surfaceinterface methods (getContentScale,getSize, etc.) the renderer needs.App.initCoreSurface, release/re-acquire GL context between main thread and renderer thread, so the renderer thread can draw. ConPTY successfully launchescmd.exeat this point.SwapBuffersandWM_SIZE--SwapBuffersafterdrawFrameso rendered frames actually appear, andWM_SIZEforwards toCoreSurface.sizeCallbackso the terminal resizes.These four commits are bundled into one PR rather than four because each intermediate state would merge a non-functional
ghostty.exeintomain-- after commit 1 the window is blank, after commit 2 it's still blank, after commit 3cmd.exeruns but produces no visible output. Only after commit 4 does the binary behave like a terminal. The commit boundaries are preserved inside this PR so the review can be read as a sequence, but the merge itself needs all four.Intentionally not included (each item is its own PR in the series):
The tracker (mattn#1) lists all the follow-up items.
AI usage disclosure: developed with Claude Code (Claude Opus 4.7). The skeleton code comes from my existing win32-apprt branch; Claude assisted with cherry-picking onto upstream main, resolving a merge conflict against the already-merged DllMain change from #12373, and validating the build.
Part of the Win32 apprt upstreaming series (see discussion #2563 / mattn#1).