app.dhover×369 error×22all
// macOS/AppKit F03 demo — modal-loop survival (../../../features/f03-modal-loop.md).
// On macOS the "modal loop" is a *run-loop mode switch*: during interactive
// live-resize / menu tracking AppKit runs the run loop in NSEventTrackingRunLoopMode
// instead of the default mode, so timers scheduled only in the default mode starve
// and any animation they drive freezes. The cure is scheduling the animation timer
// in NSRunLoopCommonModes, which AppKit's tracking/modal modes are members of.
//
// The demo animates a full-window ~2 Hz color cycle and races two identical
// ~100 ms NSTimers:
//   timer=default  scheduledTimerWithTimeInterval: (default run-loop mode only)
//   timer=common   timerWithTimeInterval: + addTimer:forMode:NSRunLoopCommonModes
//                  (this one drives setNeedsDisplay: -> the color cycle)
// Both log `tick timer=… n=… gap_ms=… phase=…` per fire.
//
// Because a programmatic setFrame: never enters live-resize (scaffold finding) and
// an interactive border-drag cannot be performed over SSH, the bounded run proves
// the *mechanism* headless: two one-shot common-modes timers each run the run loop
// nested (runMode:beforeDate:) in a non-default mode for ~2 s — first
// NSEventTrackingRunLoopMode (the very mode AppKit's live-resize/menu tracking
// loops run in), then NSModalPanelRunLoopMode. The default-mode timer starves for
// each whole phase; the common-modes timer keeps ticking — the same starvation an
// interactive drag causes. Per-timer max-gap statistics are reported per phase at
// exit.
//
// The nested phases are deliberately entered from their own one-shot timers, NOT
// from the animation timer's callback: a repeating NSTimer never fires
// re-entrantly while its own callout is on the stack, so a nested loop run from
// inside tickCommon: would starve the common-modes timer too (measured — see the
// findings doc).
//
// Live-resize instrumentation for the interactive Tier-C run:
// viewWillStartLiveResize/viewDidEndLiveResize log `modal_enter`/`modal_exit`
// (kind=live_resize), and every drawRect: logs inLiveResize.
// Findings: ../../f03-modal-loop.md; recipe and build command: ../../scaffold.md.
//
// Modes (environment variables):
//   WSI_AUTO_EXIT=1  bounded run: default (~3 s) -> tracking (~2 s, nested
//                    NSEventTrackingRunLoopMode) -> resumed (~2 s) -> panel
//                    (~2 s, nested NSModalPanelRunLoopMode) -> resumed (~3 s) ->
//                    [NSApp stop:nil] (+ synthetic event post) -> exit 0.
//   (none)           interactive: no modal phase is injected; runs until the
//                    window closes so a human can border-drag and observe the
//                    default-mode timer freeze while the color cycle survives
//                    (Tier C; see the manual-run queue).
//
// Headless-safe: prints `SKIP:` and exits 0 when there is no window server
// (CGMainDisplayID() == 0), per the research-docs guidelines.
module 
(module) app
app
;
import
(package) core
core
.
(module) core.attribute

This 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

@copyrightCopyright Jacob Carlborg 2015.@licenseBoost License 1.0@authorsJacob Carlborg
attribute
: selector;
module `core.attribute` import `selector` not found
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdio

D header file for C99 <stdio.h>

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h

Source

core/stdc/stdio.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Alex Rønne Petersen@standardsISO/IEC 9899:1999 (E)
stdio
:
(alias) app.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdlib

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h

Source

core/stdc/stdlib.d

@copyrightCopyright Sean Kelly 2005 - 2014.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
stdlib
:
(alias) app.getenv = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
,
(alias) app.malloc = void* core.stdc.stdlib.malloc(ulong size) nothrow @nogc
malloc
,
(alias) app.free = void core.stdc.stdlib.free(void* ptr) nothrow @nogc
free
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.unistd

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 8, IEEE Std 1003.1, 2024 Edition
unistd
:
(alias) app.usleep = int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
;
import
(package) core
core
.
(module) core.time

Module containing core time functionality, such as Duration (which represents a duration of time) or MonoTime (which represents a timestamp of the system's monotonic clock).

Various functions take a string (or strings) to represent a unit of time (e.g. convert!("days", "hours")(numDays)). The valid strings to use with such functions are "years", "months", "weeks", "days", "hours", "minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds), "hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There are a few functions that also allow "nsecs", but very little actually has precision greater than hnsecs.

Symbol Description
Types
Duration Represents a duration of time of weeks or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds).
TickDuration DEPRECATED Represents a duration of time in system clock ticks, using the highest precision that the system provides.
MonoTime Represents a monotonic timestamp in system clock ticks, using the highest precision that the system provides.
Functions
convert Generic way of converting between two time units.
dur Allows constructing a Duration from the given time units with the given length.
weeks&nbsp;days&nbsp;hours

minutes&nbsp;seconds&nbsp;msecs

usecs&nbsp;hnsecs&nbsp;nsecs | Convenience aliases for dur. | | abs | Returns the absolute value of a duration. |

From Duration
From TickDuration
From units
To Duration
tickDuration.to, std,conv!Duration()
dur!"msecs"(5) or 5.msecs()

| To TickDuration | duration.to, std,conv!TickDuration() |

  • | TickDuration.from!"msecs"(msecs) |

| To units | duration.total!"days" | tickDuration.msecs | convert!("days", "msecs")(msecs) |

Source

core/time.d

@copyrightCopyright 2010 - 2012@licenseBoost License 1.0.@authorsJonathan M Davis and Kato Shoichi
time
:
(struct) core.time.MonoTimeImpl!(ClockType.normal)
MonoTime
, msecs;
import instrument : instr, instrInit, instrNowUs;
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
import objc.autorelease : autoreleasepool_push, autoreleasepool_pop; // objective-d
unable to read module `autorelease` Expected 'objc/autorelease.d' or 'objc/autorelease/package.d' in one of the following import paths:
unable to read module `autorelease` Expected 'objc/autorelease.d' or 'objc/autorelease/package.d' in one of the following import paths:
unable to read module `autorelease` Expected 'objc/autorelease.d' or 'objc/autorelease/package.d' in one of the following import paths:
// 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;
unable to read module `rt` Expected 'objc/rt.d' or 'objc/rt/package.d' in one of the following import paths:
unable to read module `rt` Expected 'objc/rt.d' or 'objc/rt/package.d' in one of the following import paths:
unable to read module `rt` Expected 'objc/rt.d' or 'objc/rt/package.d' in one of the following import paths:
// --- C-level declarations ----------------------------------------------------- // CoreGraphics C API — linked transitively via the Cocoa umbrella framework. extern (C) nothrow @nogc { uint
uint app.CGMainDisplayID() nothrow @nogc
CGMainDisplayID
();
void*
void* app.CGColorSpaceCreateDeviceRGB() nothrow @nogc
CGColorSpaceCreateDeviceRGB
();
void
void app.CGColorSpaceRelease(void* space) nothrow @nogc
CGColorSpaceRelease
(void*
(parameter) void* space
space
);
void*
void* app.CGDataProviderCreateWithData(void* info, const(void)* data, ulong size, void* releaseCallback) nothrow @nogc
CGDataProviderCreateWithData
(void*
(parameter) void* info
info
, const(void)*
(parameter) const(void)* data
data
,
(alias) object.size_t = ulong
size_t
(parameter) ulong size
size
,
void*
(parameter) void* releaseCallback
releaseCallback
);
void
void app.CGDataProviderRelease(void* provider) nothrow @nogc
CGDataProviderRelease
(void*
(parameter) void* provider
provider
);
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 @nogc
CGImageCreate
(
(alias) object.size_t = ulong
size_t
(parameter) ulong width
width
,
(alias) object.size_t = ulong
size_t
(parameter) ulong height
height
,
(alias) object.size_t = ulong
size_t
(parameter) ulong bitsPerComponent
bitsPerComponent
,
(alias) object.size_t = ulong
size_t
(parameter) ulong bitsPerPixel
bitsPerPixel
,
(alias) object.size_t = ulong
size_t
(parameter) ulong bytesPerRow
bytesPerRow
, void*
(parameter) void* colorSpace
colorSpace
, uint
(parameter) uint bitmapInfo
bitmapInfo
,
void*
(parameter) void* provider
provider
, const(double)*
(parameter) const(double)* decode
decode
, bool
(parameter) bool shouldInterpolate
shouldInterpolate
, int
(parameter) int intent
intent
);
void
void app.CGImageRelease(void* image) nothrow @nogc
CGImageRelease
(void*
(parameter) void* image
image
);
void
void app.CGContextDrawImage(void* ctx, app.NSRect rect, void* image) nothrow @nogc
CGContextDrawImage
(void*
(parameter) void* ctx
ctx
,
(struct) app.NSRect
NSRect
(parameter) app.NSRect rect
rect
, void*
(parameter) void* image
image
);
} enum uint
(constant) uint app.kCGImageAlphaNoneSkipFirst = 6u
kCGImageAlphaNoneSkipFirst
= 6; // XRGB: alpha byte present, ignored
enum uint
(constant) uint app.kCGBitmapByteOrder32Little = 8192u
kCGBitmapByteOrder32Little
= 2 << 12; // 32-bit little-endian packing
enum int
(constant) int app.kCGRenderingIntentDefault = 0
kCGRenderingIntentDefault
= 0;
// Cocoa geometry (CGFloat == double on 64-bit). Plain C structs, not ObjC objects. extern (C) struct
(struct) app.NSPoint
NSPoint
{ double
(field) double app.NSPoint.x
x
,
(field) double app.NSPoint.y
y
;
} extern (C) struct
(struct) app.NSSize
NSSize
{ double
(field) double app.NSSize.width
width
,
(field) double app.NSSize.height
height
;
} extern (C) struct
(struct) app.NSRect
NSRect
{
(struct) app.NSPoint
NSPoint
(field) app.NSPoint app.NSRect.origin
origin
;
(struct) app.NSSize
NSSize
(field) app.NSSize app.NSRect.size
size
;
} // --- AppKit class declarations (objective-d bundles Foundation, not AppKit) ---- extern (Objective-C): extern class
(class) app.NSObject
NSObject
class `app.NSObject` Objective-C classes not supported
{ } extern class
(class) app.NSString
NSString
:
(class) app.NSObject
NSObject
class `app.NSString` Objective-C classes not supported
{ static
(class) app.NSString
NSString
app.NSString app.NSString.alloc()
alloc
() @selector("alloc");
(class) app.NSString
NSString
app.NSString app.NSString.initWithUTF8String(const(char)* s)
initWithUTF8String
(const(char)*
(parameter) const(char)* s
s
) @selector("initWithUTF8String:");
} extern class
(class) app.NSDate
NSDate
:
(class) app.NSObject
NSObject
class `app.NSDate` Objective-C classes not supported
{ static
(class) app.NSDate
NSDate
app.NSDate app.NSDate.dateWithTimeIntervalSinceNow(double secs)
dateWithTimeIntervalSinceNow
(double
(parameter) double secs
secs
)
@selector("dateWithTimeIntervalSinceNow:"); } extern class
(class) app.NSResponder
NSResponder
:
(class) app.NSObject
NSObject
class `app.NSResponder` Objective-C classes not supported
{ } extern class
(class) app.NSEvent
NSEvent
:
(class) app.NSObject
NSObject
class `app.NSEvent` Objective-C classes not supported
{ static
(class) app.NSEvent
NSEvent
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 type
type
,
(struct) app.NSPoint
NSPoint
(parameter) app.NSPoint location
location
, ulong
(parameter) ulong modifierFlags
modifierFlags
,
double
(parameter) double timestamp
timestamp
, long
(parameter) long windowNumber
windowNumber
,
(class) app.NSObject
NSObject
(parameter) app.NSObject context
context
, short
(parameter) short subtype
subtype
,
long
(parameter) long data1
data1
, long
(parameter) long data2
data2
)
@selector("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"); } extern class
(class) app.NSTimer
NSTimer
:
(class) app.NSObject
NSObject
class `app.NSTimer` Objective-C classes not supported
{ // Schedules on the *current* run loop in the *default* mode. static
(class) app.NSTimer
NSTimer
app.NSTimer.scheduledTimerWithTimeInterval
scheduledTimerWithTimeInterval
(double interval,
(class) app.NSObject
NSObject
target,
SEL sel,
(class) app.NSObject
NSObject
userInfo, bool repeats)
@selector("scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:"); // Creates without scheduling — the caller picks the run-loop mode(s). static
(class) app.NSTimer
NSTimer
app.NSTimer.timerWithTimeInterval
timerWithTimeInterval
(double interval,
(class) app.NSObject
NSObject
target,
SEL sel,
(class) app.NSObject
NSObject
userInfo, bool repeats)
@selector("timerWithTimeInterval:target:selector:userInfo:repeats:"); } extern class
(class) app.NSRunLoop
NSRunLoop
:
(class) app.NSObject
NSObject
class `app.NSRunLoop` Objective-C classes not supported
{ static
(class) app.NSRunLoop
NSRunLoop
app.NSRunLoop app.NSRunLoop.currentRunLoop()
currentRunLoop
() @selector("currentRunLoop");
void
void app.NSRunLoop.addTimer(app.NSTimer timer, app.NSString mode)
addTimer
(
(class) app.NSTimer
NSTimer
(parameter) app.NSTimer timer
timer
,
(class) app.NSString
NSString
(parameter) app.NSString mode
mode
) @selector("addTimer:forMode:");
bool
bool app.NSRunLoop.runMode(app.NSString mode, app.NSDate beforeDate)
runMode
(
(class) app.NSString
NSString
(parameter) app.NSString mode
mode
,
(class) app.NSDate
NSDate
(parameter) app.NSDate beforeDate
beforeDate
) @selector("runMode:beforeDate:");
} extern class
(class) app.NSGraphicsContext
NSGraphicsContext
:
(class) app.NSObject
NSObject
class `app.NSGraphicsContext` Objective-C classes not supported
{ static
(class) app.NSGraphicsContext
NSGraphicsContext
app.NSGraphicsContext app.NSGraphicsContext.currentContext()
currentContext
() @selector("currentContext");
void*
void* app.NSGraphicsContext.CGContext()
CGContext
() @selector("CGContext"); // CGContextRef
} extern class
(class) app.NSApplication
NSApplication
:
(class) app.NSResponder
NSResponder
class `app.NSApplication` Objective-C classes not supported
{ static
(class) app.NSApplication
NSApplication
app.NSApplication app.NSApplication.sharedApplication()
sharedApplication
() @selector("sharedApplication");
void
void app.NSApplication.setActivationPolicy(long policy)
setActivationPolicy
(long
(parameter) long policy
policy
) @selector("setActivationPolicy:");
void
void app.NSApplication.activateIgnoringOtherApps(bool flag)
activateIgnoringOtherApps
(bool
(parameter) bool flag
flag
) @selector("activateIgnoringOtherApps:");
void
void app.NSApplication.run()
run
() @selector("run");
void
void app.NSApplication.stop(app.NSObject sender)
stop
(
(class) app.NSObject
NSObject
(parameter) app.NSObject sender
sender
) @selector("stop:");
void
void app.NSApplication.postEvent(app.NSEvent event, bool atStart)
postEvent
(
(class) app.NSEvent
NSEvent
(parameter) app.NSEvent event
event
, bool
(parameter) bool atStart
atStart
) @selector("postEvent:atStart:");
void
void app.NSApplication.terminate(app.NSObject sender)
terminate
(
(class) app.NSObject
NSObject
(parameter) app.NSObject sender
sender
) @selector("terminate:");
} extern class
(class) app.NSView
NSView
:
(class) app.NSResponder
NSResponder
class `app.NSView` Objective-C classes not supported
{ void
void app.NSView.setFrameSize(app.NSSize newSize)
setFrameSize
(
(struct) app.NSSize
NSSize
(parameter) app.NSSize newSize
newSize
) @selector("setFrameSize:");
void
void app.NSView.setNeedsDisplay(bool flag)
setNeedsDisplay
(bool
(parameter) bool flag
flag
) @selector("setNeedsDisplay:");
(struct) app.NSRect
NSRect
app.NSRect app.NSView.bounds()
bounds
() @selector("bounds");
bool
bool app.NSView.inLiveResize()
inLiveResize
() @selector("inLiveResize");
} extern class
(class) app.NSWindow
NSWindow
:
(class) app.NSResponder
NSResponder
class `app.NSWindow` Objective-C classes not supported
{ static
(class) app.NSWindow
NSWindow
app.NSWindow app.NSWindow.alloc()
alloc
() @selector("alloc");
(class) app.NSWindow
NSWindow
app.NSWindow app.NSWindow.initWithContentRect(app.NSRect contentRect, ulong styleMask, ulong backing, bool defer)
initWithContentRect
(
(struct) app.NSRect
NSRect
(parameter) app.NSRect contentRect
contentRect
, ulong
(parameter) ulong styleMask
styleMask
,
ulong
(parameter) ulong backing
backing
, bool
(parameter) bool defer
defer
) @selector("initWithContentRect:styleMask:backing:defer:");
void
void app.NSWindow.setTitle(app.NSString title)
setTitle
(
(class) app.NSString
NSString
(parameter) app.NSString title
title
) @selector("setTitle:");
void
void app.NSWindow.setContentView(app.NSView view)
setContentView
(
(class) app.NSView
NSView
(parameter) app.NSView view
view
) @selector("setContentView:");
void
void app.NSWindow.setDelegate(app.NSObject anObject)
setDelegate
(
(class) app.NSObject
NSObject
(parameter) app.NSObject anObject
anObject
) @selector("setDelegate:");
void
void app.NSWindow.makeKeyAndOrderFront(app.NSObject sender)
makeKeyAndOrderFront
(
(class) app.NSObject
NSObject
(parameter) app.NSObject sender
sender
) @selector("makeKeyAndOrderFront:");
double
double app.NSWindow.backingScaleFactor()
backingScaleFactor
() @selector("backingScaleFactor");
} // --- The custom NSView subclass, defined in D ---------------------------------- // Same recipe as the scaffold: bodied @selector methods are the implementation; // selector-only callbacks (timer fires, delegate methods, the live-resize // notifications) need no base declaration — Objective-C dispatch is by selector. class
(class) app.ColorView
ColorView
:
(class) app.NSView
NSView
class `app.ColorView` Objective-C classes not supported
{ static
(class) app.ColorView
ColorView
app.ColorView app.ColorView.alloc()
alloc
() @selector("alloc");
(class) app.ColorView
ColorView
app.ColorView app.ColorView.initWithFrame(app.NSRect frame)
initWithFrame
(
(struct) app.NSRect
NSRect
(parameter) app.NSRect frame
frame
) @selector("initWithFrame:");
void
void app.ColorView.drawRect(app.NSRect dirtyRect)
drawRect
(
(struct) app.NSRect
NSRect
(parameter) app.NSRect dirtyRect
dirtyRect
) @selector("drawRect:")
{ onDrawRect(this.
this.bounds
bounds
(), this.
this.inLiveResize
inLiveResize
());
} // The control timer: default run-loop mode only. void
void app.ColorView.tickDefault(app.NSTimer timer)
tickDefault
(
(class) app.NSTimer
NSTimer
(parameter) app.NSTimer timer
timer
) @selector("tickDefault:")
{ onTimerFire(TimerId.
TimerId.defaultMode
defaultMode
);
} // The animation timer: NSRunLoopCommonModes; drives the color cycle. void
void app.ColorView.tickCommon(app.NSTimer timer)
tickCommon
(
(class) app.NSTimer
NSTimer
(parameter) app.NSTimer timer
timer
) @selector("tickCommon:")
{ onTimerFire(TimerId.
TimerId.commonModes
commonModes
);
++g_hueStep; this.
this.setNeedsDisplay
setNeedsDisplay
(true);
if (g_auto) onAutoExitCheck(); } // One-shot phase triggers (their own callouts, so neither measured timer is // blocked by NSTimer's no-re-entrant-fire rule while the nested loop runs). void
void app.ColorView.enterTracking(app.NSTimer timer)
enterTracking
(
(class) app.NSTimer
NSTimer
(parameter) app.NSTimer timer
timer
) @selector("enterTracking:")
{ runNestedPhase(Phase.
Phase.tracking
tracking
, g_modeTracking, "NSEventTrackingRunLoopMode");
} void
void app.ColorView.enterPanel(app.NSTimer timer)
enterPanel
(
(class) app.NSTimer
NSTimer
(parameter) app.NSTimer timer
timer
) @selector("enterPanel:")
{ runNestedPhase(Phase.
Phase.panel
panel
, g_modePanel, "NSModalPanelRunLoopMode");
} // AppKit's live-resize bracket — the platform's `modal_enter`/`modal_exit`. // Fires only for interactive border-drags (Tier C), never programmatically. void
void app.ColorView.viewWillStartLiveResize()
viewWillStartLiveResize
() @selector("viewWillStartLiveResize")
{ instr("modal_enter", "kind=live_resize"); g_phase = Phase.
Phase.tracking
tracking
; // live-resize IS NSEventTrackingRunLoopMode
} void
void app.ColorView.viewDidEndLiveResize()
viewDidEndLiveResize
() @selector("viewDidEndLiveResize")
{ instr("modal_exit", "kind=live_resize"); g_phase = Phase.
Phase.resumed
resumed
;
} void
void app.ColorView.windowWillClose(app.NSObject notification)
windowWillClose
(
(class) app.NSObject
NSObject
(parameter) app.NSObject notification
notification
) @selector("windowWillClose:")
{ instr("close_requested"); g_app.
g_app.terminate
terminate
(null);
} } extern (D): // back to D linkage for the rest of the module enum
(constant) int app.NSApplicationActivationPolicyRegular = 0
NSApplicationActivationPolicyRegular
= 0;
enum : ulong {
(enum value) app.NSWindowStyleMaskTitled = 1LU
NSWindowStyleMaskTitled
= 1,
(enum value) app.NSWindowStyleMaskClosable = 2LU
NSWindowStyleMaskClosable
= 2,
(enum value) app.NSWindowStyleMaskResizable = 8LU
NSWindowStyleMaskResizable
= 8,
} enum ulong
(constant) ulong app.NSBackingStoreBuffered = 2LU
NSBackingStoreBuffered
= 2;
enum long
(constant) long app.NSEventTypeApplicationDefined = 15L
NSEventTypeApplicationDefined
= 15;
// --- Demo state ----------------------------------------------------------------- enum
(enum) app.TimerId
TimerId
: int
{
(enum value) app.TimerId.defaultMode = 0
defaultMode
= 0, // control: starves in non-default modes
(enum value) app.TimerId.commonModes = 1
commonModes
= 1, // animation: survives them
} enum
(enum) app.Phase
Phase
: int
{
(enum value) app.Phase.defaultRun = 0
defaultRun
= 0, // [NSApp run] pumping the default mode
(enum value) app.Phase.tracking = 1
tracking
= 1, // nested NSEventTrackingRunLoopMode (== live-resize's mode)
(enum value) app.Phase.panel = 2
panel
= 2, // nested NSModalPanelRunLoopMode
(enum value) app.Phase.resumed = 3
resumed
= 3, // back in the default mode after a nested phase
} immutable
(alias) object.string = string
string
[2]
(immutable global) immutable(string[2]) app.timerNames
timerNames
= ["default", "common"];
immutable
(alias) object.string = string
string
[4]
(immutable global) immutable(string[4]) app.phaseNames
phaseNames
= ["default", "tracking", "panel", "resumed"];
__gshared
(class) app.NSApplication
NSApplication
(__gshared global) app.NSApplication app.g_app
g_app
;
__gshared
(class) app.NSWindow
NSWindow
(__gshared global) app.NSWindow app.g_win
g_win
;
__gshared
(class) app.NSRunLoop
NSRunLoop
(__gshared global) app.NSRunLoop app.g_runLoop
g_runLoop
;
__gshared
(class) app.NSString
NSString
(__gshared global) app.NSString app.g_modeTracking
g_modeTracking
,
(__gshared global) app.NSString app.g_modePanel
g_modePanel
;
__gshared uint*
(__gshared global) uint* app.g_buf
g_buf
;
__gshared
(alias) object.size_t = ulong
size_t
(__gshared global) ulong app.g_bufW
g_bufW
,
(__gshared global) ulong app.g_bufH
g_bufH
;
__gshared
(enum) app.Phase
Phase
(__gshared global) app.Phase app.g_phase
g_phase
= Phase.
Phase.defaultRun
defaultRun
;
__gshared bool
(__gshared global) bool app.g_auto
g_auto
;
__gshared int
(__gshared global) int app.g_hueStep
g_hueStep
,
(__gshared global) int app.g_draws
g_draws
;
// Per-timer fire accounting: last fire time, then fires/max-gap per phase. __gshared ulong[2]
(__gshared global) ulong[2] app.g_lastFireUs
g_lastFireUs
;
__gshared uint[2]
(__gshared global) uint[2] app.g_fireCount
g_fireCount
;
__gshared uint[4][2]
(__gshared global) uint[4][2] app.g_firesPerPhase
g_firesPerPhase
; // [timer][phase]
__gshared ulong[4][2]
(__gshared global) ulong[4][2] app.g_maxGapPerPhase
g_maxGapPerPhase
; // [timer][phase], µs
enum
(constant) int app.timerIntervalMs = 100
timerIntervalMs
= 100; // both timers; the color cycle advances per common tick
enum
(constant) int app.hueStepsPerCycle = 5
hueStepsPerCycle
= 5; // 5 × 100 ms = 500 ms per full cycle ≈ 2 Hz
enum
(constant) double app.trackingEnterSec = 3.0
trackingEnterSec
= 3.0; // ~3 s of phase `default` first
enum
(constant) double app.panelEnterSec = 7.0
panelEnterSec
= 7.0; // ~2 s `resumed` between the nested phases
enum
(constant) int app.nestedPhaseMs = 2000
nestedPhaseMs
= 2000; // ~2 s per nested mode
enum
(constant) int app.autoExitUs = 12000000
autoExitUs
= 12_000_000; // ~12 s total
void
void app.onTimerFire(app.TimerId id)
onTimerFire
(
(enum) app.TimerId
TimerId
(parameter) app.TimerId id
id
)
{ immutable
_error_ now
now
= instrNowUs();
immutable
_error_ gapUs
gapUs
= g_lastFireUs[id] != 0 ? now - g_lastFireUs[id] : 0;
g_lastFireUs[id] = now; ++g_fireCount[id]; ++g_firesPerPhase[id][g_phase]; if (gapUs > g_maxGapPerPhase[id][g_phase]) g_maxGapPerPhase[id][g_phase] = gapUs; instr("tick", "timer=%.*s n=%u gap_ms=%.1f phase=%.*s", cast(int) timerNames[id].length, timerNames[id].ptr, g_fireCount[id], gapUs / 1000.0, cast(int) phaseNames[g_phase].length, phaseNames[g_phase].ptr); } // The headline measurement: run the run loop nested in a non-default mode — // structurally what AppKit does for live-resize/menu tracking // (NSEventTrackingRunLoopMode) and modal panels (NSModalPanelRunLoopMode). The // common-modes timer keeps firing into the nested loop; the default-mode timer // cannot. Entered from a one-shot timer's callout so neither measured timer is // blocked by its own in-progress callout. void
void app.runNestedPhase(app.Phase phase, app.NSString mode, const(char)* modeName)
runNestedPhase
(
(enum) app.Phase
Phase
(parameter) app.Phase phase
phase
,
(class) app.NSString
NSString
(parameter) app.NSString mode
mode
, const(char)*
(parameter) const(char)* modeName
modeName
)
{ g_phase = phase; instr("phase_enter", "name=%.*s mode=%s dur_ms=%d", cast(int) phaseNames[phase].length, phaseNames[phase].ptr, modeName, nestedPhaseMs); immutable
_error_ deadline
deadline
= MonoTime.currTime + nestedPhaseMs.msecs;
while (MonoTime.currTime < deadline) { auto
_error_ pool
pool
= autoreleasepool_push();
immutable
_error_ ranSource
ranSource
= g_runLoop.
g_runLoop.runMode
runMode
(mode,
NSDate.
NSDate.dateWithTimeIntervalSinceNow
dateWithTimeIntervalSinceNow
(0.05));
autoreleasepool_pop(pool); if (!ranSource) usleep(10_000); // mode has no sources/timers: don't spin hot } g_phase = Phase.
Phase.resumed
resumed
;
instr("phase_exit", "name=%.*s", cast(int) phaseNames[phase].length, phaseNames[phase].ptr); } void
void app.onAutoExitCheck()
onAutoExitCheck
()
{ if (g_phase != Phase.
Phase.resumed
resumed
|| instrNowUs() < autoExitUs)
return; foreach (
(parameter) timer
timer
; 0 .. 2)
foreach (
(parameter) phase
phase
; 0 .. 4)
instr("gap_summary", "timer=%.*s phase=%.*s fires=%u max_gap_ms=%.1f", cast(int) timerNames[timer].length, timerNames[timer].ptr, cast(int) phaseNames[phase].length, phaseNames[phase].ptr, g_firesPerPhase[timer][phase], g_maxGapPerPhase[timer][phase] / 1000.0); instr("step", "name=NSApp_stop"); g_app.
g_app.stop
stop
(null);
// stop: is only checked after an event dispatch; post a synthetic event // so [NSApp run] wakes up and exits (scaffold finding).
(unresolved type) NSEvent
NSEvent
_error_ ev
ev
= NSEvent.
NSEvent.otherEventWithType
otherEventWithType
(NSEventTypeApplicationDefined,
NSPoint(0, 0), 0, 0, 0, null, 0, 0, 0); g_app.
g_app.postEvent
postEvent
(ev, true);
} void
void app.onDrawRect(app.NSRect bounds, bool live)
onDrawRect
(
(struct) app.NSRect
NSRect
(parameter) app.NSRect bounds
bounds
, bool
(parameter) bool live
live
)
{ immutable double
_error_ scale
scale
= g_win.
g_win.backingScaleFactor
backingScaleFactor
();
immutable
(unresolved type) size_t
size_t
_error_ pw
pw
= cast(
(unresolved type) size_t
size_t
) (bounds.
bounds.size
size
.
bounds.size.width
width
* scale);
immutable
(unresolved type) size_t
size_t
_error_ ph
ph
= cast(
(unresolved type) size_t
size_t
) (bounds.
bounds.size
size
.
bounds.size.height
height
* 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; } // Full-window solid color cycling through hues, one step per common tick // (~2 Hz full cycle). A frozen color = a starved animation timer. immutable
_error_ color
color
= hueColor(g_hueStep % hueStepsPerCycle, hueStepsPerCycle);
foreach (
(parameter) i
i
; 0 .. pw * ph)
g_buf[i] = color; void*
_error_ cs
cs
= CGColorSpaceCreateDeviceRGB();
void*
_error_ dp
dp
= CGDataProviderCreateWithData(null, g_buf, pw * ph * 4, null);
void*
_error_ img
img
= CGImageCreate(pw, ph, 8, 32, pw * 4, cs,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, dp, null, false, kCGRenderingIntentDefault); void*
_error_ ctx
ctx
= NSGraphicsContext.
NSGraphicsContext.currentContext
currentContext
().
NSGraphicsContext.currentContext().CGContext
CGContext
();
CGContextDrawImage(ctx, bounds, img); CGImageRelease(img); CGDataProviderRelease(dp); CGColorSpaceRelease(cs); ++g_draws; instr("draw", "n=%d hue_step=%d live_resize=%d phase=%.*s", g_draws, g_hueStep, live ? 1 : 0, cast(int) phaseNames[g_phase].length, phaseNames[g_phase].ptr); } uint
uint app.hueColor(int step, int steps) nothrow @nogc
hueColor
(int
(parameter) int step
step
, int
(parameter) int steps
steps
) nothrow @nogc
{ // Coarse hue wheel: interpolate R->G->B->R over `steps` positions. immutable
_error_ t
t
= step * 768 / steps; // 0..767
int
_error_ r
r
,
_error_ g
g
,
_error_ b
b
;
if (t < 256) { r = 255 - t; g = t; } else if (t < 512) { g = 255 - (t - 256); b = t - 256; } else { b = 255 - (t - 512); r = t - 512; } return 0xFF00_0000 | (cast(uint) r << 16) | (cast(uint) g << 8) | cast(uint) b; } int
int D main()
main
()
{ g_auto = getenv("WSI_AUTO_EXIT") !is null; instrInit("APPKIT_F03"); instr("init_start", "auto_exit=%d timer_interval_ms=%d", g_auto ? 1 : 0, timerIntervalMs); if (CGMainDisplayID() == 0) { printf("SKIP: no macOS window server (CGMainDisplayID == 0)\n"); return 0; } auto
_error_ pool
pool
= autoreleasepool_push();
scope (exit) autoreleasepool_pop(pool); g_app = NSApplication.
NSApplication.sharedApplication
sharedApplication
();
g_app.
g_app.setActivationPolicy
setActivationPolicy
(NSApplicationActivationPolicyRegular);
immutable
_error_ contentRect
contentRect
= NSRect(NSPoint(120, 120), NSSize(480, 320));
g_win = NSWindow.
NSWindow.alloc
alloc
().
NSWindow.alloc().initWithContentRect
initWithContentRect
(contentRect,
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable, NSBackingStoreBuffered, false); g_win.
g_win.setTitle
setTitle
(NSString.
NSString.alloc
alloc
().
NSString.alloc().initWithUTF8String
initWithUTF8String
("wsi-f03-modal-loop"));
instr("window_created", "scale=%.1f", g_win.
g_win.backingScaleFactor
backingScaleFactor
());
(unresolved type) ColorView
ColorView
_error_ view
view
= ColorView.
ColorView.alloc
alloc
().
ColorView.alloc().initWithFrame
initWithFrame
(contentRect);
g_win.
g_win.setContentView
setContentView
(view);
g_win.
g_win.setDelegate
setDelegate
(view);
g_win.
g_win.makeKeyAndOrderFront
makeKeyAndOrderFront
(null);
g_app.
g_app.activateIgnoringOtherApps
activateIgnoringOtherApps
(true);
g_runLoop = NSRunLoop.
NSRunLoop.currentRunLoop
currentRunLoop
();
g_modeTracking = NSString.
NSString.alloc
alloc
().
NSString.alloc().initWithUTF8String
initWithUTF8String
("NSEventTrackingRunLoopMode");
g_modePanel = NSString.
NSString.alloc
alloc
().
NSString.alloc().initWithUTF8String
initWithUTF8String
("NSModalPanelRunLoopMode");
(unresolved type) NSString
NSString
_error_ modeCommon
modeCommon
= NSString.
NSString.alloc
alloc
().
NSString.alloc().initWithUTF8String
initWithUTF8String
("kCFRunLoopCommonModes");
// Timer 1 — the control: scheduledTimerWithTimeInterval: puts it on the // current run loop in the DEFAULT mode only. This is the naive animation // timer that freezes during live-resize/menu tracking. instr("step", "name=timer_default api=scheduledTimerWithTimeInterval mode=default"); NSTimer.
NSTimer.scheduledTimerWithTimeInterval
scheduledTimerWithTimeInterval
(timerIntervalMs / 1000.0, view,
SEL.register("tickDefault:"), null, true); // Timer 2 — the fix: an unscheduled timer added explicitly for // NSRunLoopCommonModes, which AppKit's event-tracking and modal-panel modes // are members of. This one drives the color cycle. instr("step", "name=timer_common api=addTimer_forMode mode=NSRunLoopCommonModes");
(unresolved type) NSTimer
NSTimer
_error_ common
common
= NSTimer.
NSTimer.timerWithTimeInterval
timerWithTimeInterval
(timerIntervalMs / 1000.0, view,
SEL.register("tickCommon:"), null, true); g_runLoop.
g_runLoop.addTimer
addTimer
(common, modeCommon);
if (g_auto) { // One-shot phase triggers, themselves in common modes (so the tracking // trigger can still fire if anything else changes the mode underneath). instr("step", "name=schedule_nested tracking_at_s=%.1f panel_at_s=%.1f", trackingEnterSec, panelEnterSec);
(unresolved type) NSTimer
NSTimer
_error_ t1
t1
= NSTimer.
NSTimer.timerWithTimeInterval
timerWithTimeInterval
(trackingEnterSec, view,
SEL.register("enterTracking:"), null, false); g_runLoop.
g_runLoop.addTimer
addTimer
(t1, modeCommon);
(unresolved type) NSTimer
NSTimer
_error_ t2
t2
= NSTimer.
NSTimer.timerWithTimeInterval
timerWithTimeInterval
(panelEnterSec, view,
SEL.register("enterPanel:"), null, false); g_runLoop.
g_runLoop.addTimer
addTimer
(t2, modeCommon);
} instr("step", "name=NSApp_run"); g_app.
g_app.run
run
();
instr("loop_exit", "ticks_default=%u ticks_common=%u draws=%d", g_fireCount[TimerId.
TimerId.defaultMode
defaultMode
], g_fireCount[TimerId.
TimerId.commonModes
commonModes
], g_draws);
free(g_buf); return 0; }