// macOS/AppKit F01 demo — first pixel & init cost (../../../features/f01-first-pixel.md).
// Presents ONE software-drawn gradient frame and exits right after presentation is
// confirmed. Every initialization API call is logged as a `step name=…` event so the
// cost of each can be split out — in particular the first-WindowServer-connection
// cost (the scaffold saw CGMainDisplayID() alone take ~19 ms cold). Run the binary
// twice in a row to compare cold vs warm process starts. Findings:
// ../../f01-first-pixel.md; the subclassing recipe and build command come from
// ../../scaffold.md (this demo is the scaffold minus the resize storm, plus
// finer-grained init steps and an exit-on-first-pixel schedule).
//
// Modes (environment variables):
// WSI_AUTO_EXIT=1 exit as soon as the first drawRect: has returned (first pixel
// presented); a ~16 ms NSTimer is the exit scheduler and a
// 600-tick watchdog bounds the run if no draw ever arrives
// (exit code 1 in that case).
// (neither) runs until the window closes (windowWillClose: ->
// [NSApp terminate:]).
//
// Headless-safe: prints `SKIP:` and exits 0 when there is no window server
// (CGMainDisplayID() == 0), per the research-docs guidelines.
module (module) appapp;
import (package) corecore.(module) core.attributeThis module contains UDA's (User Defined Attributes) either used in
the runtime or special UDA's recognized by compiler.
Attribute Name, Linkage, Description
gnuAbiTag, C++,
Declares an ABI tag on a C++ symbol.
mustuse,,
Ensures that values of a struct or union type are not discarded.
optional, Objective-C,
Makes an Objective-C interface method optional.
selector, Objective-C,
Attaches an Objective-C selector to a method.
standalone,,
Marks a shared module constructor as not depending on any
other module constructor being run first.
weak,,
Specifies that a global symbol should be emitted with weak linkage.
Source
core/attribute.d
attribute : selector;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdioD header file for C99 <stdio.h>
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h
Source
core/stdc/stdio.d
stdio : (alias) app.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdlibD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h
Source
core/stdc/stdlib.d
stdlib : (alias) app.getenv = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogcgetenv, (alias) app.malloc = void* core.stdc.stdlib.malloc(ulong size) nothrow @nogcmalloc, (alias) app.free = void core.stdc.stdlib.free(void* ptr) nothrow @nogcfree;
import instrument : instr, instrInit, instrNowUs;
import objc.autorelease : autoreleasepool_push, autoreleasepool_pop; // objective-d
// Objective-C runtime selector lookup (objective-d wraps libobjc; declaring
// sel_registerName ourselves would clash with objc.rt's typed declaration).
import objc.rt : SEL;
// --- C-level declarations -----------------------------------------------------
// CoreGraphics C API — linked transitively via the Cocoa umbrella framework.
// CGRect has the same layout as NSRect (4 CGFloat = double on 64-bit), so the
// struct-by-value calls below reuse NSRect. The CF objects (CGColorSpaceRef,
// CGDataProviderRef, CGImageRef, CGContextRef) are opaque pointers.
extern (C) nothrow @nogc
{
uint uint app.CGMainDisplayID() nothrow @nogcCGMainDisplayID();
void* void* app.CGColorSpaceCreateDeviceRGB() nothrow @nogcCGColorSpaceCreateDeviceRGB();
void void app.CGColorSpaceRelease(void* space) nothrow @nogcCGColorSpaceRelease(void* (parameter) void* spacespace);
void* void* app.CGDataProviderCreateWithData(void* info, const(void)* data, ulong size, void* releaseCallback) nothrow @nogcCGDataProviderCreateWithData(void* (parameter) void* infoinfo, const(void)* (parameter) const(void)* datadata, (alias) object.size_t = ulongsize_t (parameter) ulong sizesize,
void* (parameter) void* releaseCallbackreleaseCallback);
void void app.CGDataProviderRelease(void* provider) nothrow @nogcCGDataProviderRelease(void* (parameter) void* providerprovider);
void* void* app.CGImageCreate(ulong width, ulong height, ulong bitsPerComponent, ulong bitsPerPixel, ulong bytesPerRow, void* colorSpace, uint bitmapInfo, void* provider, const(double)* decode, bool shouldInterpolate, int intent) nothrow @nogcCGImageCreate((alias) object.size_t = ulongsize_t (parameter) ulong widthwidth, (alias) object.size_t = ulongsize_t (parameter) ulong heightheight, (alias) object.size_t = ulongsize_t (parameter) ulong bitsPerComponentbitsPerComponent,
(alias) object.size_t = ulongsize_t (parameter) ulong bitsPerPixelbitsPerPixel, (alias) object.size_t = ulongsize_t (parameter) ulong bytesPerRowbytesPerRow, void* (parameter) void* colorSpacecolorSpace, uint (parameter) uint bitmapInfobitmapInfo,
void* (parameter) void* providerprovider, const(double)* (parameter) const(double)* decodedecode, bool (parameter) bool shouldInterpolateshouldInterpolate, int (parameter) int intentintent);
void void app.CGImageRelease(void* image) nothrow @nogcCGImageRelease(void* (parameter) void* imageimage);
void void app.CGContextDrawImage(void* ctx, app.NSRect rect, void* image) nothrow @nogcCGContextDrawImage(void* (parameter) void* ctxctx, (struct) app.NSRectNSRect (parameter) app.NSRect rectrect, void* (parameter) void* imageimage);
}
enum uint (constant) uint app.kCGImageAlphaNoneSkipFirst = 6ukCGImageAlphaNoneSkipFirst = 6; // XRGB: alpha byte present, ignored
enum uint (constant) uint app.kCGBitmapByteOrder32Little = 8192ukCGBitmapByteOrder32Little = 2 << 12; // 32-bit little-endian packing
enum int (constant) int app.kCGRenderingIntentDefault = 0kCGRenderingIntentDefault = 0;
// Cocoa geometry (CGFloat == double on 64-bit). Plain C structs, not ObjC objects.
extern (C) struct (struct) app.NSPointNSPoint
{
double (field) double app.NSPoint.xx, (field) double app.NSPoint.yy;
}
extern (C) struct (struct) app.NSSizeNSSize
{
double (field) double app.NSSize.widthwidth, (field) double app.NSSize.heightheight;
}
extern (C) struct (struct) app.NSRectNSRect
{
(struct) app.NSPointNSPoint (field) app.NSPoint app.NSRect.originorigin;
(struct) app.NSSizeNSSize (field) app.NSSize app.NSRect.sizesize;
}
// --- AppKit class declarations (objective-d bundles Foundation, not AppKit) ----
extern (Objective-C):
extern class (class) app.NSObjectNSObject
{
// `alloc` is declared on the leaf classes that need it (with their own return
// type) to avoid an Objective-C covariant-return clash on the base method.
}
extern class (class) app.NSStringNSString : (class) app.NSObjectNSObject
{
static (class) app.NSStringNSString app.NSString app.NSString.alloc()alloc() @selector("alloc");
(class) app.NSStringNSString app.NSString app.NSString.initWithUTF8String(const(char)* s)initWithUTF8String(const(char)* (parameter) const(char)* ss) @selector("initWithUTF8String:");
}
extern class (class) app.NSResponderNSResponder : (class) app.NSObjectNSObject
{
}
extern class (class) app.NSEventNSEvent : (class) app.NSObjectNSObject
{
static (class) app.NSEventNSEvent app.NSEvent app.NSEvent.otherEventWithType(long type, app.NSPoint location, ulong modifierFlags, double timestamp, long windowNumber, app.NSObject context, short subtype, long data1, long data2)otherEventWithType(long (parameter) long typetype, (struct) app.NSPointNSPoint (parameter) app.NSPoint locationlocation, ulong (parameter) ulong modifierFlagsmodifierFlags,
double (parameter) double timestamptimestamp, long (parameter) long windowNumberwindowNumber, (class) app.NSObjectNSObject (parameter) app.NSObject contextcontext, short (parameter) short subtypesubtype,
long (parameter) long data1data1, long (parameter) long data2data2)
@selector("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:");
}
extern class (class) app.NSTimerNSTimer : (class) app.NSObjectNSObject
{
static (class) app.NSTimerNSTimer app.NSTimer.scheduledTimerWithTimeIntervalscheduledTimerWithTimeInterval(double interval, (class) app.NSObjectNSObject target,
SEL sel, (class) app.NSObjectNSObject userInfo, bool repeats)
@selector("scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:");
}
extern class (class) app.NSGraphicsContextNSGraphicsContext : (class) app.NSObjectNSObject
{
static (class) app.NSGraphicsContextNSGraphicsContext app.NSGraphicsContext app.NSGraphicsContext.currentContext()currentContext() @selector("currentContext");
void* void* app.NSGraphicsContext.CGContext()CGContext() @selector("CGContext"); // CGContextRef
}
extern class (class) app.NSApplicationNSApplication : (class) app.NSResponderNSResponder
{
static (class) app.NSApplicationNSApplication app.NSApplication app.NSApplication.sharedApplication()sharedApplication() @selector("sharedApplication");
void void app.NSApplication.setActivationPolicy(long policy)setActivationPolicy(long (parameter) long policypolicy) @selector("setActivationPolicy:");
void void app.NSApplication.activateIgnoringOtherApps(bool flag)activateIgnoringOtherApps(bool (parameter) bool flagflag) @selector("activateIgnoringOtherApps:");
void void app.NSApplication.run()run() @selector("run");
void void app.NSApplication.stop(app.NSObject sender)stop((class) app.NSObjectNSObject (parameter) app.NSObject sendersender) @selector("stop:");
void void app.NSApplication.postEvent(app.NSEvent event, bool atStart)postEvent((class) app.NSEventNSEvent (parameter) app.NSEvent eventevent, bool (parameter) bool atStartatStart) @selector("postEvent:atStart:");
void void app.NSApplication.terminate(app.NSObject sender)terminate((class) app.NSObjectNSObject (parameter) app.NSObject sendersender) @selector("terminate:");
}
extern class (class) app.NSViewNSView : (class) app.NSResponderNSResponder
{
void void app.NSView.setFrameSize(app.NSSize newSize)setFrameSize((struct) app.NSSizeNSSize (parameter) app.NSSize newSizenewSize) @selector("setFrameSize:");
void void app.NSView.setNeedsDisplay(bool flag)setNeedsDisplay(bool (parameter) bool flagflag) @selector("setNeedsDisplay:");
(struct) app.NSRectNSRect app.NSRect app.NSView.bounds()bounds() @selector("bounds");
}
extern class (class) app.NSWindowNSWindow : (class) app.NSResponderNSResponder
{
static (class) app.NSWindowNSWindow app.NSWindow app.NSWindow.alloc()alloc() @selector("alloc");
(class) app.NSWindowNSWindow app.NSWindow app.NSWindow.initWithContentRect(app.NSRect contentRect, ulong styleMask, ulong backing, bool defer)initWithContentRect((struct) app.NSRectNSRect (parameter) app.NSRect contentRectcontentRect, ulong (parameter) ulong styleMaskstyleMask,
ulong (parameter) ulong backingbacking, bool (parameter) bool deferdefer) @selector("initWithContentRect:styleMask:backing:defer:");
void void app.NSWindow.setTitle(app.NSString title)setTitle((class) app.NSStringNSString (parameter) app.NSString titletitle) @selector("setTitle:");
void void app.NSWindow.setContentView(app.NSView view)setContentView((class) app.NSViewNSView (parameter) app.NSView viewview) @selector("setContentView:");
void void app.NSWindow.setDelegate(app.NSObject anObject)setDelegate((class) app.NSObjectNSObject (parameter) app.NSObject anObjectanObject) @selector("setDelegate:");
void void app.NSWindow.makeKeyAndOrderFront(app.NSObject sender)makeKeyAndOrderFront((class) app.NSObjectNSObject (parameter) app.NSObject sendersender) @selector("makeKeyAndOrderFront:");
double double app.NSWindow.backingScaleFactor()backingScaleFactor() @selector("backingScaleFactor");
}
// --- The custom NSView subclass, defined in D ----------------------------------
// A *non-extern* `extern (Objective-C)` class per the scaffold recipe: bodied
// @selector methods are the subclass implementation; bodyless alloc/initWithFrame
// bind to the inherited implementations; drawRect:/tick:/windowWillClose: are
// dispatched by selector and need no base declaration.
class (class) app.GradientViewGradientView : (class) app.NSViewNSView
{
static (class) app.GradientViewGradientView app.GradientView app.GradientView.alloc()alloc() @selector("alloc");
(class) app.GradientViewGradientView app.GradientView app.GradientView.initWithFrame(app.NSRect frame)initWithFrame((struct) app.NSRectNSRect (parameter) app.NSRect frameframe) @selector("initWithFrame:");
// AppKit's geometry callback to a view: the first call fires synchronously
// inside setContentView: (our "first_configure"). Must forward to super or
// the view never resizes.
override void void app.GradientView.setFrameSize(app.NSSize newSize)setFrameSize((struct) app.NSSizeNSSize (parameter) app.NSSize newSizenewSize) @selector("setFrameSize:")
{
super.super.setFrameSizesetFrameSize(newSize);
onViewResized(newSize);
}
void void app.GradientView.drawRect(app.NSRect dirtyRect)drawRect((struct) app.NSRectNSRect (parameter) app.NSRect dirtyRectdirtyRect) @selector("drawRect:")
{
onDrawRect(this.this.boundsbounds());
}
void void app.GradientView.tick(app.NSTimer timer)tick((class) app.NSTimerNSTimer (parameter) app.NSTimer timertimer) @selector("tick:")
{
onTick(this);
}
void void app.GradientView.windowWillClose(app.NSObject notification)windowWillClose((class) app.NSObjectNSObject (parameter) app.NSObject notificationnotification) @selector("windowWillClose:")
{
instr("close_requested");
g_app.g_app.terminateterminate(null);
}
}
extern (D): // back to D linkage for the rest of the module
enum (constant) int app.NSApplicationActivationPolicyRegular = 0NSApplicationActivationPolicyRegular = 0;
enum : ulong
{
(enum value) app.NSWindowStyleMaskTitled = 1LUNSWindowStyleMaskTitled = 1,
(enum value) app.NSWindowStyleMaskClosable = 2LUNSWindowStyleMaskClosable = 2,
(enum value) app.NSWindowStyleMaskResizable = 8LUNSWindowStyleMaskResizable = 8,
}
enum ulong (constant) ulong app.NSBackingStoreBuffered = 2LUNSBackingStoreBuffered = 2;
enum long (constant) long app.NSEventTypeApplicationDefined = 15LNSEventTypeApplicationDefined = 15;
// --- Demo state (single window — module globals keep the ObjC class trivial) ---
__gshared (class) app.NSApplicationNSApplication (__gshared global) app.NSApplication app.g_appg_app;
__gshared (class) app.NSWindowNSWindow (__gshared global) app.NSWindow app.g_wing_win;
__gshared uint* (__gshared global) uint* app.g_bufg_buf; // CPU framebuffer, 0xAARRGGBB (BGRA bytes, LE)
__gshared (alias) object.size_t = ulongsize_t (__gshared global) ulong app.g_bufWg_bufW, (__gshared global) ulong app.g_bufHg_bufH;
__gshared int (__gshared global) int app.g_tickg_tick, (__gshared global) int app.g_framesg_frames;
__gshared bool (__gshared global) bool app.g_autog_auto;
__gshared bool (__gshared global) bool app.g_firstConfigureSeeng_firstConfigureSeen, (__gshared global) bool app.g_firstDrawSeeng_firstDrawSeen, (__gshared global) bool app.g_firstPixelSeeng_firstPixelSeen, (__gshared global) bool app.g_stopRequestedg_stopRequested;
__gshared ulong (__gshared global) ulong app.g_firstPixelUsg_firstPixelUs;
enum (constant) int app.watchdogTicks = 600watchdogTicks = 600; // ~10 s upper bound if no drawRect: ever arrives
// Corner-anchored diagonal gradient (one frame is enough for F01).
void void app.renderGradient(uint* buf, ulong w, ulong h) nothrow @nogcrenderGradient(uint* (parameter) uint* bufbuf, (alias) object.size_t = ulongsize_t (parameter) ulong ww, (alias) object.size_t = ulongsize_t (parameter) ulong hh) nothrow @nogc
{
foreach ((parameter) yy; 0 .. h)
foreach ((parameter) xx; 0 .. w)
{
immutable _error_ rr = cast(uint) (x * 255 / w);
immutable _error_ gg = cast(uint) (y * 255 / h);
immutable _error_ bb = cast(uint) ((x + y) * 255 / (w + h));
buf[y * w + x] = 0xFF00_0000 | (r << 16) | (g << 8) | b;
}
}
void void app.onViewResized(app.NSSize size)onViewResized((struct) app.NSSizeNSSize (parameter) app.NSSize sizesize)
{
immutable double _error_ scalescale = g_win !is null ? g_win.g_win.backingScaleFactorbackingScaleFactor() : 1.0;
if (!g_firstConfigureSeen)
{
g_firstConfigureSeen = true;
instr("first_configure", "size=%dx%d scale=%.1f",
cast(int) size.size.widthwidth, cast(int) size.size.heightheight, scale);
}
else
instr("resize", "size=%dx%d scale=%.1f",
cast(int) size.size.widthwidth, cast(int) size.size.heightheight, scale);
}
void void app.onDrawRect(app.NSRect bounds)onDrawRect((struct) app.NSRectNSRect (parameter) app.NSRect boundsbounds)
{
// Split run-loop dispatch latency from render+blit cost: the entry of the
// first drawRect: is its own step; first_pixel_presented is its *return*.
if (!g_firstDrawSeen)
{
g_firstDrawSeen = true;
instr("step", "name=first_drawRect_entered size=%dx%d",
cast(int) bounds.bounds.sizesize.bounds.size.widthwidth, cast(int) bounds.bounds.sizesize.bounds.size.heightheight);
}
immutable double _error_ scalescale = g_win.g_win.backingScaleFactorbackingScaleFactor();
immutable (unresolved type) size_tsize_t _error_ pwpw = cast((unresolved type) size_tsize_t) (bounds.bounds.sizesize.bounds.size.widthwidth * scale);
immutable (unresolved type) size_tsize_t _error_ phph = cast((unresolved type) size_tsize_t) (bounds.bounds.sizesize.bounds.size.heightheight * scale);
if (pw == 0 || ph == 0)
return;
if (pw != g_bufW || ph != g_bufH)
{
free(g_buf);
g_buf = cast(uint*) malloc(pw * ph * 4);
g_bufW = pw;
g_bufH = ph;
instr("buffer_alloc", "size=%zux%zu bytes=%zu", pw, ph, pw * ph * 4);
}
renderGradient(g_buf, pw, ph);
// Wrap the pixel buffer in a CGImage and draw it into the view's current
// CGContext. The image is pw×ph *pixels* drawn into a points rect — Quartz
// maps points->pixels via the context's CTM, so the blit is 1:1 on screen.
void* _error_ cscs = CGColorSpaceCreateDeviceRGB();
void* _error_ dpdp = CGDataProviderCreateWithData(null, g_buf, pw * ph * 4, null);
void* _error_ imgimg = CGImageCreate(pw, ph, 8, 32, pw * 4, cs,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, dp, null, false,
kCGRenderingIntentDefault);
void* _error_ ctxctx = NSGraphicsContext.NSGraphicsContext.currentContextcurrentContext().NSGraphicsContext.currentContext().CGContextCGContext();
CGContextDrawImage(ctx, bounds, img);
CGImageRelease(img);
CGDataProviderRelease(dp);
CGColorSpaceRelease(cs);
++g_frames;
if (!g_firstPixelSeen)
{
g_firstPixelSeen = true;
g_firstPixelUs = instrNowUs();
// "Presented" = return of the first drawRect:. This is the strongest
// confirmation AppKit gives a software renderer — CoreAnimation may
// still defer actual compositing to the end-of-cycle CATransaction
// commit (the F04 frame-pacing demo's CADisplayLink/CVDisplayLink
// territory), and with the console locked nothing is composited at all.
instr("first_pixel_presented", "t=%d", g_frames);
}
instr("frame_callback", "t=%d", g_frames);
}
void void app.onTick(app.GradientView view)onTick((class) app.GradientViewGradientView (parameter) app.GradientView viewview)
{
++g_tick;
if (!g_auto)
return;
if (!g_firstPixelSeen)
{
// Belt and braces: the initial display pass should draw on its own, but
// keep marking the view dirty until the first frame lands.
view.view.setNeedsDisplaysetNeedsDisplay(true);
if (g_tick < watchdogTicks)
return;
instr("watchdog_timeout", "ticks=%d", g_tick);
}
if (g_stopRequested)
return;
g_stopRequested = true;
instr("step", "name=NSApp_stop tick=%d", g_tick);
g_app.g_app.stopstop(null);
// stop: is only checked after an event is dispatched; without a real event
// in the queue [NSApp run] would keep blocking. Post a synthetic
// application-defined event so the loop wakes up and exits.
(unresolved type) NSEventNSEvent _error_ evev = NSEvent.NSEvent.otherEventWithTypeotherEventWithType(NSEventTypeApplicationDefined,
NSPoint(0, 0), 0, 0, 0, null, 0, 0, 0);
g_app.g_app.postEventpostEvent(ev, true);
}
int int D main()main()
{
g_auto = getenv("WSI_AUTO_EXIT") !is null;
instrInit("APPKIT_F01");
instr("init_start", "auto_exit=%d", g_auto ? 1 : 0);
// Headless guard — and, per the scaffold finding, itself the *first
// WindowServer round-trip*: the first call into CoreGraphics bootstraps the
// connection (~19 ms cold), so its return is instrumented as its own step.
instr("step", "name=CGMainDisplayID");
immutable _error_ displayIDdisplayID = CGMainDisplayID();
instr("step", "name=CGMainDisplayID_returned id=%u", displayID);
if (displayID == 0)
{
printf("SKIP: no macOS window server (CGMainDisplayID == 0)\n");
return 0;
}
// objective-d's autorelease pool wraps the AppKit setup; [NSApp run] drains
// its own per-event pools.
auto _error_ poolpool = autoreleasepool_push();
scope (exit)
autoreleasepool_pop(pool);
// 1. The shared application object + activation policy.
instr("step", "name=NSApplication_sharedApplication");
g_app = NSApplication.NSApplication.sharedApplicationsharedApplication();
instr("step", "name=setActivationPolicy policy=regular");
g_app.g_app.setActivationPolicysetActivationPolicy(NSApplicationActivationPolicyRegular);
// 2. A titled, closable, resizable window with a buffered backing store.
// alloc and the designated initializer are separate steps so the window
// *device* creation cost is visible on its own.
immutable _error_ contentRectcontentRect = NSRect(NSPoint(120, 120), NSSize(480, 320));
instr("step", "name=NSWindow_alloc");
(unresolved type) NSWindowNSWindow _error_ winwin = NSWindow.NSWindow.allocalloc();
instr("step", "name=NSWindow_initWithContentRect size=480x320");
g_win = win.win.initWithContentRectinitWithContentRect(contentRect,
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable,
NSBackingStoreBuffered, false);
instr("step", "name=setTitle");
g_win.g_win.setTitlesetTitle(NSString.NSString.allocalloc().NSString.alloc().initWithUTF8StringinitWithUTF8String("wsi-f01"));
instr("window_created", "scale=%.1f", g_win.g_win.backingScaleFactorbackingScaleFactor());
// 3. The D-defined NSView subclass becomes the content view; installing it
// triggers the first setFrameSize: (-> first_configure) *synchronously
// inside setContentView:*. It also serves as window delegate.
instr("step", "name=GradientView_alloc");
(unresolved type) GradientViewGradientView _error_ viewview = GradientView.GradientView.allocalloc();
instr("step", "name=GradientView_initWithFrame");
view = view.view.initWithFrameinitWithFrame(contentRect);
instr("step", "name=setContentView");
g_win.g_win.setContentViewsetContentView(view);
instr("step", "name=setDelegate");
g_win.g_win.setDelegatesetDelegate(view);
// 4. Show + activate.
instr("step", "name=makeKeyAndOrderFront");
g_win.g_win.makeKeyAndOrderFrontmakeKeyAndOrderFront(null);
instr("step", "name=activateIgnoringOtherApps");
g_app.g_app.activateIgnoringOtherAppsactivateIgnoringOtherApps(true);
// 5. A ~16 ms repeating NSTimer is the exit scheduler (and a dirty-mark
// fallback until the first frame). It is bookkeeping, not part of the
// draw path — the initial drawRect: arrives from the run loop's first
// drawing pass regardless.
instr("step", "name=NSTimer_scheduledTimerWithTimeInterval interval_ms=16");
NSTimer.NSTimer.scheduledTimerWithTimeIntervalscheduledTimerWithTimeInterval(0.016, view, SEL.register("tick:"),
null, true);
// 6. Cede the main thread to AppKit. The first drawRect: only arrives inside
// run — makeKeyAndOrderFront: paints nothing (scaffold finding).
instr("step", "name=NSApp_run");
g_app.g_app.runrun();
instr("loop_exit", "frames=%d ticks=%d first_pixel_us=%llu",
g_frames, g_tick, g_firstPixelUs);
free(g_buf);
if (g_auto && !g_firstPixelSeen)
return 1;
return 0;
}