First window
A window opened.
The image sends Display beDisplay during initialisation, which calls Primitive 102 — the beDisplay primitive. For six months that primitive was a stub that returned true and did nothing. Today it creates a WinForms window, sets up a 32bpp bitmap buffer, and registers a paint handler that copies the bitmap to the window surface.
Everything after that is deferred. The window exists but it’s blank. DisplayScreen doesn’t know its extent yet. The display bitmap dimensions aren’t wired to the Smalltalk DisplayScreen width and height methods. But the primitive fired, the OS created a window, and a WinForms message loop is running on a background thread.
The non-trivial part was the two-step initialisation order that the Blue Book requires: beDisplay is called, then DisplayScreen initialize is called, and initialize cannot run before beDisplay because it uses primitives that require the display to exist. Getting those two calls in the right order, with the C# display factory initialised between them, took most of the day.
The display buffer is now created lazily — on the first call to beDisplay, not at interpreter startup. That unblocked cold start: the image can now load and run without a display (for headless testing) and only creates the window when the image explicitly asks for one.
Snapshot save is also working: Smalltalk snapshot writes the object graph to %APPDATA%\Smalltalk-80\image.json. The save path is no longer the current working directory, which was writing into the build output folder and being deleted by the next build.
Next: get the display dimensions right, implement BitBlt enough to render the System Browser background.