nomen-lang 0.7.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/audit_runtime.c +12 -2
- package/core/System/Arena.nm +8 -1
- package/core/System/Buffer.nm +397 -8
- package/core/System/ClassBuffer.nm +156 -0
- package/core/System/Controls/Alert.nm +326 -0
- package/core/System/Controls/App.nm +147 -0
- package/core/System/Controls/Button.nm +119 -1
- package/core/System/Controls/CheckBox.nm +25 -1
- package/core/System/Controls/ColorPicker.nm +307 -0
- package/core/System/Controls/ComboBox.nm +430 -0
- package/core/System/Controls/Container.nm +843 -9
- package/core/System/Controls/Control.nm +443 -0
- package/core/System/Controls/DatePicker.nm +288 -0
- package/core/System/Controls/Form.nm +70 -0
- package/core/System/Controls/GroupBox.nm +267 -0
- package/core/System/Controls/ImageView.nm +311 -0
- package/core/System/Controls/LevelIndicator.nm +305 -0
- package/core/System/Controls/ListView.nm +633 -0
- package/core/System/Controls/Menu.nm +428 -0
- package/core/System/Controls/NumberInput.nm +56 -0
- package/core/System/Controls/OtpInput.nm +50 -0
- package/core/System/Controls/OutlineView.nm +598 -0
- package/core/System/Controls/Pagination.nm +142 -0
- package/core/System/Controls/Popover.nm +296 -0
- package/core/System/Controls/Progress.nm +348 -0
- package/core/System/Controls/Radio.nm +292 -0
- package/core/System/Controls/Scrollable.nm +584 -0
- package/core/System/Controls/SearchField.nm +326 -0
- package/core/System/Controls/SecureField.nm +344 -0
- package/core/System/Controls/Segmented.nm +380 -0
- package/core/System/Controls/Select.nm +340 -0
- package/core/System/Controls/Separator.nm +198 -0
- package/core/System/Controls/Sheet.nm +329 -0
- package/core/System/Controls/Slider.nm +315 -0
- package/core/System/Controls/Spinner.nm +287 -0
- package/core/System/Controls/SplitView.nm +509 -0
- package/core/System/Controls/Stepper.nm +349 -0
- package/core/System/Controls/Switch.nm +259 -0
- package/core/System/Controls/Table.nm +833 -0
- package/core/System/Controls/Tabs.nm +500 -0
- package/core/System/Controls/Text.nm +108 -11
- package/core/System/Controls/TextBox.nm +113 -2
- package/core/System/Controls/TextView.nm +329 -0
- package/core/System/Controls/Toggle.nm +346 -0
- package/core/System/Controls/Toolbar.nm +501 -0
- package/core/System/Controls/Tooltip.nm +76 -0
- package/core/System/Controls/Window.nm +1548 -91
- package/core/System/LinkedList.nm +8 -1
- package/core/System/List.nm +97 -7
- package/core/System/Map.nm +191 -18
- package/core/System/Mutex.nm +4 -4
- package/core/System/Random.nm +3 -4
- package/core/System/Set.nm +101 -13
- package/core/System/StableList.nm +371 -0
- package/core/System/Stream/Directory.nm +2 -2
- package/core/System/Stream/File.nm +2 -2
- package/core/System/Stream/Http.nm +2 -2
- package/core/System/String.nm +10 -5
- package/core/System/StringBuilder.nm +213 -2
- package/core/System/Text/CharIndex.nm +9 -9
- package/core/System/Text/Json.nm +60 -46
- package/core/System/Text/JsonTree.nm +120 -92
- package/core/System/Text/Regex.nm +23 -18
- package/core/System/Text/Utf8.nm +5 -5
- package/core/System/float.nm +36 -22
- package/core/System/int.nm +80 -28
- package/core/System/int16.nm +11 -0
- package/core/System/int32.nm +11 -0
- package/core/System/int64.nm +11 -0
- package/core/System/int8.nm +11 -0
- package/core/System/uint.nm +11 -0
- package/core/System/uint16.nm +11 -0
- package/core/System/uint32.nm +11 -0
- package/core/System/uint64.nm +11 -0
- package/core/System/uint8.nm +11 -0
- package/core/docs/System/StringBuilder.md +6 -0
- package/core/docs/System/Text/JsonTree.md +3 -2
- package/dist/index.mjs +38332 -30604
- package/package.json +1 -1
- package/src/bench_loop.nm +9 -9
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* pointer form); the constructor's `self` is the inline instance (the `.`
|
|
9
9
|
* accessor).
|
|
10
10
|
**/
|
|
11
|
-
pub mv struct Window
|
|
11
|
+
pub mv struct Window: Control {
|
|
12
12
|
var uint64 handle = 0
|
|
13
13
|
|
|
14
14
|
pub func #init = (self, string title, int width, int height) {
|
|
@@ -160,18 +160,290 @@ pub mv struct Window : Control {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
// Process pending events without blocking. Returns 1 if a left-mouse-down
|
|
163
|
-
// was among the events (i.e. a click happened),
|
|
164
|
-
// manual event loop detect clicks
|
|
165
|
-
//
|
|
163
|
+
// was among the events (i.e. a click happened), 2 if a right-mouse-down
|
|
164
|
+
// was, 0 otherwise. This lets a manual event loop detect clicks (and
|
|
165
|
+
// right-clicks) for hit-testing without target/action. The click's
|
|
166
|
+
// coordinates are captured here (see click_x/click_y), and the click's
|
|
167
|
+
// button kind is stamped for the drains (nomen_last_click_kind —
|
|
168
|
+
// Container.take_right_click reads it). Also runs the run
|
|
169
|
+
// loop briefly to process Apple Events (e.g. dock Quit).
|
|
166
170
|
pub func process_events = (out int) {
|
|
167
171
|
```
|
|
168
172
|
#arch: c
|
|
169
173
|
#platform: macos
|
|
174
|
+
#scope: file
|
|
175
|
+
// The most recent mouse-down (NSLeftMouseDown = 1 or NSRightMouseDown = 3)
|
|
176
|
+
// among the events the latest process_events call pumped, in the event
|
|
177
|
+
// window's content coordinates (top-left origin). Written by the pump;
|
|
178
|
+
// read by click_x/click_y. click_x/click_y deliberately do NOT read the
|
|
179
|
+
// live currentEvent: any event after the click in the same batch (a
|
|
180
|
+
// mouse-move, drag, or key) would make the coordinates stale or missing,
|
|
181
|
+
// so hit-tests would intermittently miss.
|
|
182
|
+
static int nomen_last_click_x = -1;
|
|
183
|
+
static int nomen_last_click_y = -1;
|
|
184
|
+
// The same record's button kind (0 none / 1 left / 2 right), stamped
|
|
185
|
+
// by every pump — a quiet pump stamps 0, so the edge expires with
|
|
186
|
+
// the frame. External linkage (NOT static, unlike the coordinates):
|
|
187
|
+
// Container's take_right_click drain externs it from another TU —
|
|
188
|
+
// the focus snapshot's sharing pattern (nomen_window_focus_poll).
|
|
189
|
+
int nomen_last_click_kind = 0;
|
|
190
|
+
// The full mouse-down record for THIS pump (the exhaustive input
|
|
191
|
+
// surface — every button, not just left/right): 1-based button
|
|
192
|
+
// number (0 = no mouse-down this frame), AppKit clickCount, and the
|
|
193
|
+
// device-independent modifier flags (Command = 0x100000, Option =
|
|
194
|
+
// 0x80000, Control = 0x40000, Shift = 0x20000). Zeroed by every
|
|
195
|
+
// pump, so the edge expires with the frame. External linkage:
|
|
196
|
+
// Container.take_mouse_down externs the button from another TU.
|
|
197
|
+
int nomen_last_click_button = 0;
|
|
198
|
+
int nomen_last_click_count = 0;
|
|
199
|
+
int nomen_last_click_modifiers = 0;
|
|
200
|
+
// Scroll-wheel deltas accumulated across this pump's events
|
|
201
|
+
// (trackpads emit many small events per frame; momentum counts).
|
|
202
|
+
// Zeroed by every pump. External linkage: Scrollable.take_scroll
|
|
203
|
+
// externs them from another TU.
|
|
204
|
+
double nomen_scroll_dx_acc = 0.0;
|
|
205
|
+
double nomen_scroll_dy_acc = 0.0;
|
|
206
|
+
// The keyboard record for THIS pump: the hardware keycode of the
|
|
207
|
+
// last key-down (NSEventTypeKeyDown = 10) and key-up (type 11),
|
|
208
|
+
// -1 = none this frame; the modifiers at key-down; and whether the
|
|
209
|
+
// key-down was an auto-repeat (a held key). Zeroed by every pump.
|
|
210
|
+
// External linkage: Container.take_key_down / take_key_up extern
|
|
211
|
+
// them from another TU. Text entry does NOT flow here (the field
|
|
212
|
+
// editor feeds TextBox.on_input) — this record is for shortcuts and
|
|
213
|
+
// raw key handling.
|
|
214
|
+
int nomen_last_key_code = -1;
|
|
215
|
+
int nomen_last_key_modifiers = 0;
|
|
216
|
+
int nomen_last_key_repeat = 0;
|
|
217
|
+
int nomen_last_key_up_code = -1;
|
|
218
|
+
// The pointer-MOVE record for THIS pump (NSEventTypeMouseMoved = 5,
|
|
219
|
+
// plus the dragged variants 6/7/26 while a button is held): the last
|
|
220
|
+
// seen position, -1 = no move this frame. Zeroed by every pump.
|
|
221
|
+
// External linkage: Container.take_mouse_move externs it. Requires
|
|
222
|
+
// setAcceptsMouseMovedEvents (armed by every pump below) — without
|
|
223
|
+
// it AppKit delivers no move events at all.
|
|
224
|
+
int nomen_last_mouse_move_x = -1;
|
|
225
|
+
int nomen_last_mouse_move_y = -1;
|
|
226
|
+
// Frame time: the pump's wall-clock interval, persisted across
|
|
227
|
+
// pumps (NOT zeroed — the first frame reports 0). Read by win.dt().
|
|
228
|
+
double nomen_last_pump_time = 0.0;
|
|
229
|
+
double nomen_last_dt_ms = 0.0;
|
|
230
|
+
// The window-resize record for THIS frame, stamped by Window.run's
|
|
231
|
+
// resize detection (not by the pump). External linkage:
|
|
232
|
+
// Container.take_resize externs the edge from another TU; the size
|
|
233
|
+
// getters (resize_width/resize_height) are Window methods reading
|
|
234
|
+
// these directly.
|
|
235
|
+
int nomen_last_resized = 0;
|
|
236
|
+
int nomen_last_resize_w = 0;
|
|
237
|
+
int nomen_last_resize_h = 0;
|
|
238
|
+
```
|
|
239
|
+
```
|
|
240
|
+
#arch: aarch64_use_c
|
|
241
|
+
#platform: macos
|
|
242
|
+
#scope: file
|
|
243
|
+
// The most recent mouse-down (NSLeftMouseDown = 1 or NSRightMouseDown = 3)
|
|
244
|
+
// among the events the latest process_events call pumped, in the event
|
|
245
|
+
// window's content coordinates (top-left origin). Written by the pump;
|
|
246
|
+
// read by click_x/click_y. click_x/click_y deliberately do NOT read the
|
|
247
|
+
// live currentEvent: any event after the click in the same batch (a
|
|
248
|
+
// mouse-move, drag, or key) would make the coordinates stale or missing,
|
|
249
|
+
// so hit-tests would intermittently miss.
|
|
250
|
+
static int nomen_last_click_x = -1;
|
|
251
|
+
static int nomen_last_click_y = -1;
|
|
252
|
+
// The same record's button kind (0 none / 1 left / 2 right), stamped
|
|
253
|
+
// by every pump — a quiet pump stamps 0, so the edge expires with
|
|
254
|
+
// the frame. External linkage (NOT static, unlike the coordinates):
|
|
255
|
+
// Container's take_right_click drain externs it from another TU —
|
|
256
|
+
// the focus snapshot's sharing pattern (nomen_window_focus_poll).
|
|
257
|
+
int nomen_last_click_kind = 0;
|
|
258
|
+
// The full mouse-down record for THIS pump (the exhaustive input
|
|
259
|
+
// surface — every button, not just left/right): 1-based button
|
|
260
|
+
// number (0 = no mouse-down this frame), AppKit clickCount, and the
|
|
261
|
+
// device-independent modifier flags (Command = 0x100000, Option =
|
|
262
|
+
// 0x80000, Control = 0x40000, Shift = 0x20000). Zeroed by every
|
|
263
|
+
// pump, so the edge expires with the frame. External linkage:
|
|
264
|
+
// Container.take_mouse_down externs the button from another TU.
|
|
265
|
+
int nomen_last_click_button = 0;
|
|
266
|
+
int nomen_last_click_count = 0;
|
|
267
|
+
int nomen_last_click_modifiers = 0;
|
|
268
|
+
// Scroll-wheel deltas accumulated across this pump's events
|
|
269
|
+
// (trackpads emit many small events per frame; momentum counts).
|
|
270
|
+
// Zeroed by every pump. External linkage: Scrollable.take_scroll
|
|
271
|
+
// externs them from another TU.
|
|
272
|
+
double nomen_scroll_dx_acc = 0.0;
|
|
273
|
+
double nomen_scroll_dy_acc = 0.0;
|
|
274
|
+
// The keyboard record for THIS pump: the hardware keycode of the
|
|
275
|
+
// last key-down (NSEventTypeKeyDown = 10) and key-up (type 11),
|
|
276
|
+
// -1 = none this frame; the modifiers at key-down; and whether the
|
|
277
|
+
// key-down was an auto-repeat (a held key). Zeroed by every pump.
|
|
278
|
+
// External linkage: Container.take_key_down / take_key_up extern
|
|
279
|
+
// them from another TU. Text entry does NOT flow here (the field
|
|
280
|
+
// editor feeds TextBox.on_input) — this record is for shortcuts and
|
|
281
|
+
// raw key handling.
|
|
282
|
+
int nomen_last_key_code = -1;
|
|
283
|
+
int nomen_last_key_modifiers = 0;
|
|
284
|
+
int nomen_last_key_repeat = 0;
|
|
285
|
+
int nomen_last_key_up_code = -1;
|
|
286
|
+
// The pointer-MOVE record for THIS pump (NSEventTypeMouseMoved = 5,
|
|
287
|
+
// plus the dragged variants 6/7/26 while a button is held): the last
|
|
288
|
+
// seen position, -1 = no move this frame. Zeroed by every pump.
|
|
289
|
+
// External linkage: Container.take_mouse_move externs it. Requires
|
|
290
|
+
// setAcceptsMouseMovedEvents (armed by every pump below) — without
|
|
291
|
+
// it AppKit delivers no move events at all.
|
|
292
|
+
int nomen_last_mouse_move_x = -1;
|
|
293
|
+
int nomen_last_mouse_move_y = -1;
|
|
294
|
+
// Frame time: the pump's wall-clock interval, persisted across
|
|
295
|
+
// pumps (NOT zeroed — the first frame reports 0). Read by win.dt().
|
|
296
|
+
double nomen_last_pump_time = 0.0;
|
|
297
|
+
double nomen_last_dt_ms = 0.0;
|
|
298
|
+
// The window-resize record for THIS frame, stamped by Window.run's
|
|
299
|
+
// resize detection (not by the pump). External linkage:
|
|
300
|
+
// Container.take_resize externs the edge from another TU; the size
|
|
301
|
+
// getters (resize_width/resize_height) are Window methods reading
|
|
302
|
+
// these directly.
|
|
303
|
+
int nomen_last_resized = 0;
|
|
304
|
+
int nomen_last_resize_w = 0;
|
|
305
|
+
int nomen_last_resize_h = 0;
|
|
306
|
+
```
|
|
307
|
+
```
|
|
308
|
+
#arch: c
|
|
309
|
+
#platform: macos
|
|
310
|
+
// A manual event loop has no autorelease pool of its own: AppKit
|
|
311
|
+
// autoreleases objects on every pump (events, strings, cell caches)
|
|
312
|
+
// and without a pool they accumulate for the process lifetime — the
|
|
313
|
+
// loop leaked tens of MB per second and a busy window eventually
|
|
314
|
+
// died. One pool per pump; the returned had_click is a plain int.
|
|
315
|
+
id pool = ((id(*)(id, SEL))objc_msgSend)(
|
|
316
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")),
|
|
317
|
+
sel_registerName("init"));
|
|
318
|
+
id app = ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
|
|
319
|
+
id distant_past = ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSDate"), sel_registerName("distantPast"));
|
|
320
|
+
id default_mode = ((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
321
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "kCFRunLoopDefaultMode");
|
|
322
|
+
int had_click = 0;
|
|
323
|
+
// This pump's mouse record: zeroed first, so a quiet pump expires
|
|
324
|
+
// the previous frame's edge — the getters and drains read these,
|
|
325
|
+
// and 0 means "no mouse-down / no scroll this frame".
|
|
326
|
+
nomen_last_click_button = 0;
|
|
327
|
+
nomen_last_click_count = 0;
|
|
328
|
+
nomen_last_click_modifiers = 0;
|
|
329
|
+
nomen_scroll_dx_acc = 0.0;
|
|
330
|
+
nomen_scroll_dy_acc = 0.0;
|
|
331
|
+
nomen_last_key_code = -1;
|
|
332
|
+
nomen_last_key_modifiers = 0;
|
|
333
|
+
nomen_last_key_repeat = 0;
|
|
334
|
+
nomen_last_key_up_code = -1;
|
|
335
|
+
nomen_last_mouse_move_x = -1;
|
|
336
|
+
nomen_last_mouse_move_y = -1;
|
|
337
|
+
while (1) {
|
|
338
|
+
id event = ((id(*)(id, SEL, unsigned long long, id, id, BOOL))objc_msgSend)(
|
|
339
|
+
app, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
|
|
340
|
+
0xFFFFFFFFFFFFFFFFULL, // NSEventMaskAny
|
|
341
|
+
distant_past, // untilDate — returns immediately if no events
|
|
342
|
+
default_mode, // inMode
|
|
343
|
+
1); // dequeue
|
|
344
|
+
if (!event) break;
|
|
345
|
+
((void(*)(id, SEL, id))objc_msgSend)(app, sel_registerName("sendEvent:"), event);
|
|
346
|
+
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
347
|
+
// A mouse-down (left = 1, right = 3, other/middle/extra = 25):
|
|
348
|
+
// record where it landed and which button. locationInWindow is
|
|
349
|
+
// in the event's own window's coordinates (bottom-left origin);
|
|
350
|
+
// flip y against that window's content height to match the
|
|
351
|
+
// layout's top-left origin. buttonNumber is 0-based (0 left, 1
|
|
352
|
+
// right, 2 middle, 3+ extras) — stored 1-based to match
|
|
353
|
+
// FrameEvents.click's 1 = left / 2 = right contract. clickCount
|
|
354
|
+
// gives double/triple clicks; modifierFlags are masked to the
|
|
355
|
+
// device-independent bits.
|
|
356
|
+
if (type == 1 || type == 3 || type == 25) {
|
|
357
|
+
id evwin = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("window"));
|
|
358
|
+
id cv = ((id(*)(id, SEL))objc_msgSend)(evwin, sel_registerName("contentView"));
|
|
359
|
+
CGRect frame = ((CGRect(*)(id, SEL))objc_msgSend)(cv, sel_registerName("frame"));
|
|
360
|
+
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
361
|
+
nomen_last_click_x = (int)loc.x;
|
|
362
|
+
nomen_last_click_y = (int)(frame.size.height - loc.y);
|
|
363
|
+
nomen_last_click_button = (int)(((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"))) + 1;
|
|
364
|
+
nomen_last_click_count = (int)((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("clickCount"));
|
|
365
|
+
nomen_last_click_modifiers = (int)(((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")) & 0xFFF00000ULL);
|
|
366
|
+
}
|
|
367
|
+
// A scroll-wheel event (NSEventTypeScrollWheel = 22): accumulate
|
|
368
|
+
// the deltas for this frame. AppKit deltaY is positive scrolling
|
|
369
|
+
// up/away from the user; deltaX is positive scrolling right.
|
|
370
|
+
if (type == 22) {
|
|
371
|
+
nomen_scroll_dy_acc += ((double(*)(id, SEL))objc_msgSend)(event, sel_registerName("deltaY"));
|
|
372
|
+
nomen_scroll_dx_acc += ((double(*)(id, SEL))objc_msgSend)(event, sel_registerName("deltaX"));
|
|
373
|
+
}
|
|
374
|
+
// A key-down (NSEventTypeKeyDown = 10): record the hardware
|
|
375
|
+
// keycode (Space = 49, Return = 36, Delete = 51, Esc = 53,
|
|
376
|
+
// arrows = 123–126, letters a…z = 0–25), the modifiers, and
|
|
377
|
+
// whether this is an auto-repeat (a held key — filter it for
|
|
378
|
+
// first-press-only shortcuts).
|
|
379
|
+
if (type == 10) {
|
|
380
|
+
nomen_last_key_code = (int)((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
|
|
381
|
+
nomen_last_key_modifiers = (int)(((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")) & 0xFFF00000ULL);
|
|
382
|
+
nomen_last_key_repeat = ((BOOL(*)(id, SEL))objc_msgSend)(event, sel_registerName("isARepeat")) ? 1 : 0;
|
|
383
|
+
}
|
|
384
|
+
// A key-up (NSEventTypeKeyUp = 11): press-and-hold handling.
|
|
385
|
+
if (type == 11) {
|
|
386
|
+
nomen_last_key_up_code = (int)((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
|
|
387
|
+
}
|
|
388
|
+
// A pointer move (NSMouseMoved = 5; the dragged variants 6/7/26
|
|
389
|
+
// while a button is held): record where the pointer is now.
|
|
390
|
+
if (type == 5 || type == 6 || type == 7 || type == 26) {
|
|
391
|
+
id evwin = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("window"));
|
|
392
|
+
id cv = ((id(*)(id, SEL))objc_msgSend)(evwin, sel_registerName("contentView"));
|
|
393
|
+
CGRect frame = ((CGRect(*)(id, SEL))objc_msgSend)(cv, sel_registerName("frame"));
|
|
394
|
+
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
395
|
+
nomen_last_mouse_move_x = (int)loc.x;
|
|
396
|
+
nomen_last_mouse_move_y = (int)(frame.size.height - loc.y);
|
|
397
|
+
}
|
|
398
|
+
if (type == 1) had_click = 1; // NSLeftMouseDown = 1
|
|
399
|
+
if (type == 3) had_click = 2; // NSRightMouseDown = 3 (reported as 2)
|
|
400
|
+
}
|
|
401
|
+
// Process run loop sources (Apple Events, timers) so that dock Quit
|
|
402
|
+
// and other system interactions work without NSApplication.run().
|
|
403
|
+
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, 1);
|
|
404
|
+
// Frame time: the interval since the previous pump (0 on the first).
|
|
405
|
+
double now = CFAbsoluteTimeGetCurrent();
|
|
406
|
+
if (nomen_last_pump_time != 0.0) {
|
|
407
|
+
nomen_last_dt_ms = (now - nomen_last_pump_time) * 1000.0;
|
|
408
|
+
}
|
|
409
|
+
nomen_last_pump_time = now;
|
|
410
|
+
int result = had_click;
|
|
411
|
+
// Stamp the kind for the drains (Container.take_right_click reads
|
|
412
|
+
// it in the handle_events pass that follows this pump).
|
|
413
|
+
nomen_last_click_kind = had_click;
|
|
414
|
+
((void(*)(id, SEL))objc_msgSend)(pool, sel_registerName("drain"));
|
|
415
|
+
return result;
|
|
416
|
+
```
|
|
417
|
+
```
|
|
418
|
+
#arch: aarch64_use_c
|
|
419
|
+
#platform: macos
|
|
420
|
+
// A manual event loop has no autorelease pool of its own: AppKit
|
|
421
|
+
// autoreleases objects on every pump (events, strings, cell caches)
|
|
422
|
+
// and without a pool they accumulate for the process lifetime — the
|
|
423
|
+
// loop leaked tens of MB per second and a busy window eventually
|
|
424
|
+
// died. One pool per pump; the returned had_click is a plain int.
|
|
425
|
+
id pool = ((id(*)(id, SEL))objc_msgSend)(
|
|
426
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")),
|
|
427
|
+
sel_registerName("init"));
|
|
170
428
|
id app = ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
|
|
171
429
|
id distant_past = ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSDate"), sel_registerName("distantPast"));
|
|
172
430
|
id default_mode = ((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
173
431
|
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "kCFRunLoopDefaultMode");
|
|
174
432
|
int had_click = 0;
|
|
433
|
+
// This pump's mouse record: zeroed first, so a quiet pump expires
|
|
434
|
+
// the previous frame's edge — the getters and drains read these,
|
|
435
|
+
// and 0 means "no mouse-down / no scroll this frame".
|
|
436
|
+
nomen_last_click_button = 0;
|
|
437
|
+
nomen_last_click_count = 0;
|
|
438
|
+
nomen_last_click_modifiers = 0;
|
|
439
|
+
nomen_scroll_dx_acc = 0.0;
|
|
440
|
+
nomen_scroll_dy_acc = 0.0;
|
|
441
|
+
nomen_last_key_code = -1;
|
|
442
|
+
nomen_last_key_modifiers = 0;
|
|
443
|
+
nomen_last_key_repeat = 0;
|
|
444
|
+
nomen_last_key_up_code = -1;
|
|
445
|
+
nomen_last_mouse_move_x = -1;
|
|
446
|
+
nomen_last_mouse_move_y = -1;
|
|
175
447
|
while (1) {
|
|
176
448
|
id event = ((id(*)(id, SEL, unsigned long long, id, id, BOOL))objc_msgSend)(
|
|
177
449
|
app, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
|
|
@@ -182,37 +454,540 @@ pub mv struct Window : Control {
|
|
|
182
454
|
if (!event) break;
|
|
183
455
|
((void(*)(id, SEL, id))objc_msgSend)(app, sel_registerName("sendEvent:"), event);
|
|
184
456
|
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
457
|
+
// A mouse-down (left = 1, right = 3, other/middle/extra = 25):
|
|
458
|
+
// record where it landed and which button. locationInWindow is
|
|
459
|
+
// in the event's own window's coordinates (bottom-left origin);
|
|
460
|
+
// flip y against that window's content height to match the
|
|
461
|
+
// layout's top-left origin. buttonNumber is 0-based (0 left, 1
|
|
462
|
+
// right, 2 middle, 3+ extras) — stored 1-based to match
|
|
463
|
+
// FrameEvents.click's 1 = left / 2 = right contract. clickCount
|
|
464
|
+
// gives double/triple clicks; modifierFlags are masked to the
|
|
465
|
+
// device-independent bits.
|
|
466
|
+
if (type == 1 || type == 3 || type == 25) {
|
|
467
|
+
id evwin = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("window"));
|
|
468
|
+
id cv = ((id(*)(id, SEL))objc_msgSend)(evwin, sel_registerName("contentView"));
|
|
469
|
+
CGRect frame = ((CGRect(*)(id, SEL))objc_msgSend)(cv, sel_registerName("frame"));
|
|
470
|
+
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
471
|
+
nomen_last_click_x = (int)loc.x;
|
|
472
|
+
nomen_last_click_y = (int)(frame.size.height - loc.y);
|
|
473
|
+
nomen_last_click_button = (int)(((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"))) + 1;
|
|
474
|
+
nomen_last_click_count = (int)((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("clickCount"));
|
|
475
|
+
nomen_last_click_modifiers = (int)(((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")) & 0xFFF00000ULL);
|
|
476
|
+
}
|
|
477
|
+
// A scroll-wheel event (NSEventTypeScrollWheel = 22): accumulate
|
|
478
|
+
// the deltas for this frame. AppKit deltaY is positive scrolling
|
|
479
|
+
// up/away from the user; deltaX is positive scrolling right.
|
|
480
|
+
if (type == 22) {
|
|
481
|
+
nomen_scroll_dy_acc += ((double(*)(id, SEL))objc_msgSend)(event, sel_registerName("deltaY"));
|
|
482
|
+
nomen_scroll_dx_acc += ((double(*)(id, SEL))objc_msgSend)(event, sel_registerName("deltaX"));
|
|
483
|
+
}
|
|
484
|
+
// A key-down (NSEventTypeKeyDown = 10): record the hardware
|
|
485
|
+
// keycode (Space = 49, Return = 36, Delete = 51, Esc = 53,
|
|
486
|
+
// arrows = 123–126, letters a…z = 0–25), the modifiers, and
|
|
487
|
+
// whether this is an auto-repeat (a held key — filter it for
|
|
488
|
+
// first-press-only shortcuts).
|
|
489
|
+
if (type == 10) {
|
|
490
|
+
nomen_last_key_code = (int)((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
|
|
491
|
+
nomen_last_key_modifiers = (int)(((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")) & 0xFFF00000ULL);
|
|
492
|
+
nomen_last_key_repeat = ((BOOL(*)(id, SEL))objc_msgSend)(event, sel_registerName("isARepeat")) ? 1 : 0;
|
|
493
|
+
}
|
|
494
|
+
// A key-up (NSEventTypeKeyUp = 11): press-and-hold handling.
|
|
495
|
+
if (type == 11) {
|
|
496
|
+
nomen_last_key_up_code = (int)((unsigned long(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
|
|
497
|
+
}
|
|
498
|
+
// A pointer move (NSMouseMoved = 5; the dragged variants 6/7/26
|
|
499
|
+
// while a button is held): record where the pointer is now.
|
|
500
|
+
if (type == 5 || type == 6 || type == 7 || type == 26) {
|
|
501
|
+
id evwin = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("window"));
|
|
502
|
+
id cv = ((id(*)(id, SEL))objc_msgSend)(evwin, sel_registerName("contentView"));
|
|
503
|
+
CGRect frame = ((CGRect(*)(id, SEL))objc_msgSend)(cv, sel_registerName("frame"));
|
|
504
|
+
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
505
|
+
nomen_last_mouse_move_x = (int)loc.x;
|
|
506
|
+
nomen_last_mouse_move_y = (int)(frame.size.height - loc.y);
|
|
507
|
+
}
|
|
185
508
|
if (type == 1) had_click = 1; // NSLeftMouseDown = 1
|
|
509
|
+
if (type == 3) had_click = 2; // NSRightMouseDown = 3 (reported as 2)
|
|
510
|
+
}
|
|
511
|
+
// Process run loop sources (Apple Events, timers) so that dock Quit
|
|
512
|
+
// and other system interactions work without NSApplication.run().
|
|
513
|
+
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, 1);
|
|
514
|
+
// Frame time: the interval since the previous pump (0 on the first).
|
|
515
|
+
double now = CFAbsoluteTimeGetCurrent();
|
|
516
|
+
if (nomen_last_pump_time != 0.0) {
|
|
517
|
+
nomen_last_dt_ms = (now - nomen_last_pump_time) * 1000.0;
|
|
518
|
+
}
|
|
519
|
+
nomen_last_pump_time = now;
|
|
520
|
+
int result = had_click;
|
|
521
|
+
// Stamp the kind for the drains (Container.take_right_click reads
|
|
522
|
+
// it in the handle_events pass that follows this pump).
|
|
523
|
+
nomen_last_click_kind = had_click;
|
|
524
|
+
((void(*)(id, SEL))objc_msgSend)(pool, sel_registerName("drain"));
|
|
525
|
+
return result;
|
|
526
|
+
```
|
|
527
|
+
```
|
|
528
|
+
#arch: c
|
|
529
|
+
#platform: ios
|
|
530
|
+
return 0;
|
|
531
|
+
```
|
|
532
|
+
```
|
|
533
|
+
#arch: aarch64_use_c
|
|
534
|
+
#platform: ios
|
|
535
|
+
return 0;
|
|
536
|
+
```
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Returns true if the window is still on screen. Use this to exit a
|
|
540
|
+
// manual event loop when the user closes the window.
|
|
541
|
+
pub func is_visible = (self, out bool) {
|
|
542
|
+
```
|
|
543
|
+
#arch: c
|
|
544
|
+
#platform: macos
|
|
545
|
+
BOOL vis = ((BOOL(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("isVisible"));
|
|
546
|
+
return vis;
|
|
547
|
+
```
|
|
548
|
+
```
|
|
549
|
+
#arch: aarch64_use_c
|
|
550
|
+
#platform: macos
|
|
551
|
+
BOOL vis = ((BOOL(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("isVisible"));
|
|
552
|
+
return vis;
|
|
553
|
+
```
|
|
554
|
+
```
|
|
555
|
+
#arch: c
|
|
556
|
+
#platform: ios
|
|
557
|
+
BOOL vis = ((BOOL(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("isKeyWindow"));
|
|
558
|
+
return vis;
|
|
559
|
+
```
|
|
560
|
+
```
|
|
561
|
+
#arch: aarch64_use_c
|
|
562
|
+
#platform: ios
|
|
563
|
+
BOOL vis = ((BOOL(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("isKeyWindow"));
|
|
564
|
+
return vis;
|
|
565
|
+
```
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Returns the x coordinate (in the window's content view) of the most
|
|
569
|
+
// recent mouse-down (left or right). The pump (process_events) captures
|
|
570
|
+
// the coordinates when the event is handled, so drag/move events that
|
|
571
|
+
// follow in the same batch cannot make them stale. Call after
|
|
572
|
+
// process_events returned 1 or 2 (-1 before any click was ever seen).
|
|
573
|
+
pub func click_x = (self, out int) {
|
|
574
|
+
```
|
|
575
|
+
#arch: c
|
|
576
|
+
#platform: macos
|
|
577
|
+
return nomen_last_click_x;
|
|
578
|
+
```
|
|
579
|
+
```
|
|
580
|
+
#arch: aarch64_use_c
|
|
581
|
+
#platform: macos
|
|
582
|
+
return nomen_last_click_x;
|
|
583
|
+
```
|
|
584
|
+
```
|
|
585
|
+
#arch: c
|
|
586
|
+
#platform: ios
|
|
587
|
+
return -1;
|
|
588
|
+
```
|
|
589
|
+
```
|
|
590
|
+
#arch: aarch64_use_c
|
|
591
|
+
#platform: ios
|
|
592
|
+
return -1;
|
|
593
|
+
```
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Returns the y coordinate (flipped to top-left origin) of the most
|
|
597
|
+
// recent mouse-down, in the window's content view. Captured by the pump;
|
|
598
|
+
// see click_x.
|
|
599
|
+
pub func click_y = (self, out int) {
|
|
600
|
+
```
|
|
601
|
+
#arch: c
|
|
602
|
+
#platform: macos
|
|
603
|
+
return nomen_last_click_y;
|
|
604
|
+
```
|
|
605
|
+
```
|
|
606
|
+
#arch: aarch64_use_c
|
|
607
|
+
#platform: macos
|
|
608
|
+
return nomen_last_click_y;
|
|
609
|
+
```
|
|
610
|
+
```
|
|
611
|
+
#arch: c
|
|
612
|
+
#platform: ios
|
|
613
|
+
return -1;
|
|
614
|
+
```
|
|
615
|
+
```
|
|
616
|
+
#arch: aarch64_use_c
|
|
617
|
+
#platform: ios
|
|
618
|
+
return -1;
|
|
619
|
+
```
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// ── The full mouse record (this frame's pump) ──
|
|
623
|
+
// The exhaustive input surface beside click_x/click_y: EVERY button
|
|
624
|
+
// (middle, mouse 4+), the click count (double/triple), and the modifier
|
|
625
|
+
// flags. All five are per-frame: stamped by the pump that saw the
|
|
626
|
+
// events, zeroed by the next — so a handler registered on
|
|
627
|
+
// `on_mouse_down` (Container.take_mouse_down) or a `frame` reading
|
|
628
|
+
// FrameEvents sees exactly this frame's record. `mouse_button` is
|
|
629
|
+
// 1-based (1 left, 2 right, 3 middle, 4+ extra buttons), 0 on a quiet
|
|
630
|
+
// frame — the same contract as FrameEvents.mouse_button.
|
|
631
|
+
//
|
|
632
|
+
// Modifier bits (NSEventModifierFlagDeviceIndependentFlagsMask, already
|
|
633
|
+
// applied by the pump): Command = 0x100000, Option = 0x80000,
|
|
634
|
+
// Control = 0x40000, Shift = 0x20000, Function = 0x800000.
|
|
635
|
+
|
|
636
|
+
pub func mouse_button = (self, out int) {
|
|
637
|
+
```
|
|
638
|
+
#arch: c
|
|
639
|
+
#platform: macos
|
|
640
|
+
return nomen_last_click_button;
|
|
641
|
+
```
|
|
642
|
+
```
|
|
643
|
+
#arch: aarch64_use_c
|
|
644
|
+
#platform: macos
|
|
645
|
+
return nomen_last_click_button;
|
|
646
|
+
```
|
|
647
|
+
```
|
|
648
|
+
#arch: c
|
|
649
|
+
#platform: ios
|
|
650
|
+
return 0;
|
|
651
|
+
```
|
|
652
|
+
```
|
|
653
|
+
#arch: aarch64_use_c
|
|
654
|
+
#platform: ios
|
|
655
|
+
return 0;
|
|
656
|
+
```
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
pub func mouse_click_count = (self, out int) {
|
|
660
|
+
```
|
|
661
|
+
#arch: c
|
|
662
|
+
#platform: macos
|
|
663
|
+
return nomen_last_click_count;
|
|
664
|
+
```
|
|
665
|
+
```
|
|
666
|
+
#arch: aarch64_use_c
|
|
667
|
+
#platform: macos
|
|
668
|
+
return nomen_last_click_count;
|
|
669
|
+
```
|
|
670
|
+
```
|
|
671
|
+
#arch: c
|
|
672
|
+
#platform: ios
|
|
673
|
+
return 0;
|
|
674
|
+
```
|
|
675
|
+
```
|
|
676
|
+
#arch: aarch64_use_c
|
|
677
|
+
#platform: ios
|
|
678
|
+
return 0;
|
|
679
|
+
```
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
pub func mouse_modifiers = (self, out int) {
|
|
683
|
+
```
|
|
684
|
+
#arch: c
|
|
685
|
+
#platform: macos
|
|
686
|
+
return nomen_last_click_modifiers;
|
|
687
|
+
```
|
|
688
|
+
```
|
|
689
|
+
#arch: aarch64_use_c
|
|
690
|
+
#platform: macos
|
|
691
|
+
return nomen_last_click_modifiers;
|
|
692
|
+
```
|
|
693
|
+
```
|
|
694
|
+
#arch: c
|
|
695
|
+
#platform: ios
|
|
696
|
+
return 0;
|
|
697
|
+
```
|
|
698
|
+
```
|
|
699
|
+
#arch: aarch64_use_c
|
|
700
|
+
#platform: ios
|
|
701
|
+
return 0;
|
|
702
|
+
```
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// This frame's accumulated scroll deltas (AppKit deltaY/deltaX: dy is
|
|
706
|
+
// positive scrolling up/away from the user, dx positive scrolling
|
|
707
|
+
// right), truncated to ints. Scroll events accumulate across the pump's
|
|
708
|
+
// batch — a trackpad frame sums every small event — and expire with the
|
|
709
|
+
// frame. `Scrollable.on_scroll` is the registered-handler form.
|
|
710
|
+
pub func scroll_dx = (self, out int) {
|
|
711
|
+
```
|
|
712
|
+
#arch: c
|
|
713
|
+
#platform: macos
|
|
714
|
+
return (int)nomen_scroll_dx_acc;
|
|
715
|
+
```
|
|
716
|
+
```
|
|
717
|
+
#arch: aarch64_use_c
|
|
718
|
+
#platform: macos
|
|
719
|
+
return (int)nomen_scroll_dx_acc;
|
|
720
|
+
```
|
|
721
|
+
```
|
|
722
|
+
#arch: c
|
|
723
|
+
#platform: ios
|
|
724
|
+
return 0;
|
|
725
|
+
```
|
|
726
|
+
```
|
|
727
|
+
#arch: aarch64_use_c
|
|
728
|
+
#platform: ios
|
|
729
|
+
return 0;
|
|
730
|
+
```
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
pub func scroll_dy = (self, out int) {
|
|
734
|
+
```
|
|
735
|
+
#arch: c
|
|
736
|
+
#platform: macos
|
|
737
|
+
return (int)nomen_scroll_dy_acc;
|
|
738
|
+
```
|
|
739
|
+
```
|
|
740
|
+
#arch: aarch64_use_c
|
|
741
|
+
#platform: macos
|
|
742
|
+
return (int)nomen_scroll_dy_acc;
|
|
743
|
+
```
|
|
744
|
+
```
|
|
745
|
+
#arch: c
|
|
746
|
+
#platform: ios
|
|
747
|
+
return 0;
|
|
748
|
+
```
|
|
749
|
+
```
|
|
750
|
+
#arch: aarch64_use_c
|
|
751
|
+
#platform: ios
|
|
752
|
+
return 0;
|
|
753
|
+
```
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// ── The keyboard record (this frame's pump) ──
|
|
757
|
+
// Hardware keycodes (NSEventKeyCode): Space = 49, Return = 36,
|
|
758
|
+
// Delete = 51, Esc = 53, arrows = 123–126, letters a…z = 0–25.
|
|
759
|
+
// `on_key_down` / `on_key_up` (Container.take_key_down / take_key_up)
|
|
760
|
+
// are the registered forms; FrameEvents carries the same record
|
|
761
|
+
// (key_code / key_modifiers / key_repeat / key_up_code). All per-frame:
|
|
762
|
+
// -1 = no key-down/key-up this frame.
|
|
763
|
+
|
|
764
|
+
pub func key_code = (self, out int) {
|
|
765
|
+
```
|
|
766
|
+
#arch: c
|
|
767
|
+
#platform: macos
|
|
768
|
+
return nomen_last_key_code;
|
|
769
|
+
```
|
|
770
|
+
```
|
|
771
|
+
#arch: aarch64_use_c
|
|
772
|
+
#platform: macos
|
|
773
|
+
return nomen_last_key_code;
|
|
774
|
+
```
|
|
775
|
+
```
|
|
776
|
+
#arch: c
|
|
777
|
+
#platform: ios
|
|
778
|
+
return -1;
|
|
779
|
+
```
|
|
780
|
+
```
|
|
781
|
+
#arch: aarch64_use_c
|
|
782
|
+
#platform: ios
|
|
783
|
+
return -1;
|
|
784
|
+
```
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
pub func key_modifiers = (self, out int) {
|
|
788
|
+
```
|
|
789
|
+
#arch: c
|
|
790
|
+
#platform: macos
|
|
791
|
+
return nomen_last_key_modifiers;
|
|
792
|
+
```
|
|
793
|
+
```
|
|
794
|
+
#arch: aarch64_use_c
|
|
795
|
+
#platform: macos
|
|
796
|
+
return nomen_last_key_modifiers;
|
|
797
|
+
```
|
|
798
|
+
```
|
|
799
|
+
#arch: c
|
|
800
|
+
#platform: ios
|
|
801
|
+
return 0;
|
|
802
|
+
```
|
|
803
|
+
```
|
|
804
|
+
#arch: aarch64_use_c
|
|
805
|
+
#platform: ios
|
|
806
|
+
return 0;
|
|
807
|
+
```
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
pub func key_repeat = (self, out bool) {
|
|
811
|
+
```
|
|
812
|
+
#arch: c
|
|
813
|
+
#platform: macos
|
|
814
|
+
return nomen_last_key_repeat != 0;
|
|
815
|
+
```
|
|
816
|
+
```
|
|
817
|
+
#arch: aarch64_use_c
|
|
818
|
+
#platform: macos
|
|
819
|
+
return nomen_last_key_repeat != 0;
|
|
820
|
+
```
|
|
821
|
+
```
|
|
822
|
+
#arch: c
|
|
823
|
+
#platform: ios
|
|
824
|
+
return 0;
|
|
825
|
+
```
|
|
826
|
+
```
|
|
827
|
+
#arch: aarch64_use_c
|
|
828
|
+
#platform: ios
|
|
829
|
+
return 0;
|
|
830
|
+
```
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
pub func key_up_code = (self, out int) {
|
|
834
|
+
```
|
|
835
|
+
#arch: c
|
|
836
|
+
#platform: macos
|
|
837
|
+
return nomen_last_key_up_code;
|
|
838
|
+
```
|
|
839
|
+
```
|
|
840
|
+
#arch: aarch64_use_c
|
|
841
|
+
#platform: macos
|
|
842
|
+
return nomen_last_key_up_code;
|
|
843
|
+
```
|
|
844
|
+
```
|
|
845
|
+
#arch: c
|
|
846
|
+
#platform: ios
|
|
847
|
+
return -1;
|
|
848
|
+
```
|
|
849
|
+
```
|
|
850
|
+
#arch: aarch64_use_c
|
|
851
|
+
#platform: ios
|
|
852
|
+
return -1;
|
|
853
|
+
```
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// ── The pointer-move record (this frame's pump) ──
|
|
857
|
+
// The current pointer position — moves (and drags) stamped by the pump,
|
|
858
|
+
// -1 on a frame with no movement. `on_mouse_move`
|
|
859
|
+
// (Container.take_mouse_move) is the registered-handler form; hover,
|
|
860
|
+
// cursors, and tooltips hit-test this against Container.contains.
|
|
861
|
+
|
|
862
|
+
pub func mouse_x = (self, out int) {
|
|
863
|
+
```
|
|
864
|
+
#arch: c
|
|
865
|
+
#platform: macos
|
|
866
|
+
return nomen_last_mouse_move_x;
|
|
867
|
+
```
|
|
868
|
+
```
|
|
869
|
+
#arch: aarch64_use_c
|
|
870
|
+
#platform: macos
|
|
871
|
+
return nomen_last_mouse_move_x;
|
|
872
|
+
```
|
|
873
|
+
```
|
|
874
|
+
#arch: c
|
|
875
|
+
#platform: ios
|
|
876
|
+
return -1;
|
|
877
|
+
```
|
|
878
|
+
```
|
|
879
|
+
#arch: aarch64_use_c
|
|
880
|
+
#platform: ios
|
|
881
|
+
return -1;
|
|
882
|
+
```
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
pub func mouse_y = (self, out int) {
|
|
886
|
+
```
|
|
887
|
+
#arch: c
|
|
888
|
+
#platform: macos
|
|
889
|
+
return nomen_last_mouse_move_y;
|
|
890
|
+
```
|
|
891
|
+
```
|
|
892
|
+
#arch: aarch64_use_c
|
|
893
|
+
#platform: macos
|
|
894
|
+
return nomen_last_mouse_move_y;
|
|
895
|
+
```
|
|
896
|
+
```
|
|
897
|
+
#arch: c
|
|
898
|
+
#platform: ios
|
|
899
|
+
return -1;
|
|
900
|
+
```
|
|
901
|
+
```
|
|
902
|
+
#arch: aarch64_use_c
|
|
903
|
+
#platform: ios
|
|
904
|
+
return -1;
|
|
905
|
+
```
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// ── Frame time ──
|
|
909
|
+
// Milliseconds since the previous pump (0 on the first frame) — the
|
|
910
|
+
// animation clock. `FrameEvents.dt` carries the same value.
|
|
911
|
+
|
|
912
|
+
pub func dt = (self, out int) {
|
|
913
|
+
```
|
|
914
|
+
#arch: c
|
|
915
|
+
#platform: macos
|
|
916
|
+
return (int)nomen_last_dt_ms;
|
|
917
|
+
```
|
|
918
|
+
```
|
|
919
|
+
#arch: aarch64_use_c
|
|
920
|
+
#platform: macos
|
|
921
|
+
return (int)nomen_last_dt_ms;
|
|
922
|
+
```
|
|
923
|
+
```
|
|
924
|
+
#arch: c
|
|
925
|
+
#platform: ios
|
|
926
|
+
return 0;
|
|
927
|
+
```
|
|
928
|
+
```
|
|
929
|
+
#arch: aarch64_use_c
|
|
930
|
+
#platform: ios
|
|
931
|
+
return 0;
|
|
932
|
+
```
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// ── Window resize ──
|
|
936
|
+
// `on_resize` (Container.take_resize) fires on the frame whose content
|
|
937
|
+
// rect changed; the new size rides the dispatch window via these
|
|
938
|
+
// getters. The framework has ALREADY re-laid-out the registered roots
|
|
939
|
+
// (the delegate + the relayout pass) — handlers re-layout app-owned
|
|
940
|
+
// panes (tab pages, split panes). FrameEvents.resized / width / height
|
|
941
|
+
// carry the same record for `frame`.
|
|
942
|
+
|
|
943
|
+
// Stamp the resize record — run's resize detection calls this (the
|
|
944
|
+
// record lives in C statics shared with Container.take_resize; params
|
|
945
|
+
// because raw blocks in deep control flow can only address them).
|
|
946
|
+
func stamp_resize = (self, bool on, int w, int h) {
|
|
947
|
+
```
|
|
948
|
+
#arch: c
|
|
949
|
+
#platform: macos
|
|
950
|
+
extern int nomen_last_resized;
|
|
951
|
+
extern int nomen_last_resize_w;
|
|
952
|
+
extern int nomen_last_resize_h;
|
|
953
|
+
nomen_last_resized = on ? 1 : 0;
|
|
954
|
+
if (on) {
|
|
955
|
+
nomen_last_resize_w = w;
|
|
956
|
+
nomen_last_resize_h = h;
|
|
186
957
|
}
|
|
187
|
-
// Process run loop sources (Apple Events, timers) so that dock Quit
|
|
188
|
-
// and other system interactions work without NSApplication.run().
|
|
189
|
-
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, 1);
|
|
190
|
-
return had_click;
|
|
191
958
|
```
|
|
192
959
|
```
|
|
193
960
|
#arch: aarch64_use_c
|
|
194
961
|
#platform: macos
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
app, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
|
|
203
|
-
0xFFFFFFFFFFFFFFFFULL, // NSEventMaskAny
|
|
204
|
-
distant_past, // untilDate — returns immediately if no events
|
|
205
|
-
default_mode, // inMode
|
|
206
|
-
1); // dequeue
|
|
207
|
-
if (!event) break;
|
|
208
|
-
((void(*)(id, SEL, id))objc_msgSend)(app, sel_registerName("sendEvent:"), event);
|
|
209
|
-
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
210
|
-
if (type == 1) had_click = 1; // NSLeftMouseDown = 1
|
|
962
|
+
extern int nomen_last_resized;
|
|
963
|
+
extern int nomen_last_resize_w;
|
|
964
|
+
extern int nomen_last_resize_h;
|
|
965
|
+
nomen_last_resized = on ? 1 : 0;
|
|
966
|
+
if (on) {
|
|
967
|
+
nomen_last_resize_w = w;
|
|
968
|
+
nomen_last_resize_h = h;
|
|
211
969
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
970
|
+
```
|
|
971
|
+
```
|
|
972
|
+
#arch: c
|
|
973
|
+
#platform: ios
|
|
974
|
+
```
|
|
975
|
+
```
|
|
976
|
+
#arch: aarch64_use_c
|
|
977
|
+
#platform: ios
|
|
978
|
+
```
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
pub func resize_width = (self, out int) {
|
|
982
|
+
```
|
|
983
|
+
#arch: c
|
|
984
|
+
#platform: macos
|
|
985
|
+
return nomen_last_resize_w;
|
|
986
|
+
```
|
|
987
|
+
```
|
|
988
|
+
#arch: aarch64_use_c
|
|
989
|
+
#platform: macos
|
|
990
|
+
return nomen_last_resize_w;
|
|
216
991
|
```
|
|
217
992
|
```
|
|
218
993
|
#arch: c
|
|
@@ -226,114 +1001,80 @@ pub mv struct Window : Control {
|
|
|
226
1001
|
```
|
|
227
1002
|
}
|
|
228
1003
|
|
|
229
|
-
|
|
230
|
-
// manual event loop when the user closes the window.
|
|
231
|
-
pub func is_visible = (self, out bool) {
|
|
1004
|
+
pub func resize_height = (self, out int) {
|
|
232
1005
|
```
|
|
233
1006
|
#arch: c
|
|
234
1007
|
#platform: macos
|
|
235
|
-
|
|
236
|
-
return vis;
|
|
1008
|
+
return nomen_last_resize_h;
|
|
237
1009
|
```
|
|
238
1010
|
```
|
|
239
1011
|
#arch: aarch64_use_c
|
|
240
1012
|
#platform: macos
|
|
241
|
-
|
|
242
|
-
return vis;
|
|
1013
|
+
return nomen_last_resize_h;
|
|
243
1014
|
```
|
|
244
1015
|
```
|
|
245
1016
|
#arch: c
|
|
246
1017
|
#platform: ios
|
|
247
|
-
|
|
248
|
-
return vis;
|
|
1018
|
+
return 0;
|
|
249
1019
|
```
|
|
250
1020
|
```
|
|
251
1021
|
#arch: aarch64_use_c
|
|
252
1022
|
#platform: ios
|
|
253
|
-
|
|
254
|
-
return vis;
|
|
1023
|
+
return 0;
|
|
255
1024
|
```
|
|
256
1025
|
}
|
|
257
1026
|
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
|
|
1027
|
+
// ── Close interception ──
|
|
1028
|
+
// The red button routes through the App's `close_requested` (which may
|
|
1029
|
+
// refuse — the unsaved-changes pattern): the delegate refuses the
|
|
1030
|
+
// native close and sets a pending flag, and run consults the app on the
|
|
1031
|
+
// next frame. Programmatic `close()` is forced and bypasses this.
|
|
1032
|
+
|
|
1033
|
+
pub func close_pending = (self, out bool) {
|
|
261
1034
|
```
|
|
262
1035
|
#arch: c
|
|
263
1036
|
#platform: macos
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (!event) return -1;
|
|
267
|
-
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
268
|
-
if (type != 1) return -1; // NSLeftMouseDown = 1
|
|
269
|
-
// locationInWindow is a CGPoint inside the event; read it via struct-return
|
|
270
|
-
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
271
|
-
return (int)loc.x;
|
|
1037
|
+
extern int nomen_close_pending;
|
|
1038
|
+
return nomen_close_pending != 0;
|
|
272
1039
|
```
|
|
273
1040
|
```
|
|
274
1041
|
#arch: aarch64_use_c
|
|
275
1042
|
#platform: macos
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (!event) return -1;
|
|
279
|
-
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
280
|
-
if (type != 1) return -1; // NSLeftMouseDown = 1
|
|
281
|
-
// locationInWindow is a CGPoint inside the event; read it via struct-return
|
|
282
|
-
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
283
|
-
return (int)loc.x;
|
|
1043
|
+
extern int nomen_close_pending;
|
|
1044
|
+
return nomen_close_pending != 0;
|
|
284
1045
|
```
|
|
285
1046
|
```
|
|
286
1047
|
#arch: c
|
|
287
1048
|
#platform: ios
|
|
288
|
-
return
|
|
1049
|
+
return 0;
|
|
289
1050
|
```
|
|
290
1051
|
```
|
|
291
1052
|
#arch: aarch64_use_c
|
|
292
1053
|
#platform: ios
|
|
293
|
-
return
|
|
1054
|
+
return 0;
|
|
294
1055
|
```
|
|
295
1056
|
}
|
|
296
1057
|
|
|
297
|
-
|
|
298
|
-
// recent mouse-down, in the window's content view.
|
|
299
|
-
pub func click_y = (self, out int) {
|
|
1058
|
+
pub func clear_close_pending = (self) {
|
|
300
1059
|
```
|
|
301
1060
|
#arch: c
|
|
302
1061
|
#platform: macos
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (!event) return -1;
|
|
306
|
-
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
307
|
-
if (type != 1) return -1; // NSLeftMouseDown = 1
|
|
308
|
-
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
309
|
-
id cv = ((id(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("contentView"));
|
|
310
|
-
CGRect frame = ((CGRect(*)(id, SEL))objc_msgSend)(cv, sel_registerName("frame"));
|
|
311
|
-
// NSWindow coords are bottom-left origin; flip to top-left for layout math
|
|
312
|
-
return (int)(frame.size.height - loc.y);
|
|
1062
|
+
extern int nomen_close_pending;
|
|
1063
|
+
nomen_close_pending = 0;
|
|
313
1064
|
```
|
|
314
1065
|
```
|
|
315
1066
|
#arch: aarch64_use_c
|
|
316
1067
|
#platform: macos
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (!event) return -1;
|
|
320
|
-
long type = ((long(*)(id, SEL))objc_msgSend)(event, sel_registerName("type"));
|
|
321
|
-
if (type != 1) return -1; // NSLeftMouseDown = 1
|
|
322
|
-
CGPoint loc = ((CGPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
|
|
323
|
-
id cv = ((id(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("contentView"));
|
|
324
|
-
CGRect frame = ((CGRect(*)(id, SEL))objc_msgSend)(cv, sel_registerName("frame"));
|
|
325
|
-
// NSWindow coords are bottom-left origin; flip to top-left for layout math
|
|
326
|
-
return (int)(frame.size.height - loc.y);
|
|
1068
|
+
extern int nomen_close_pending;
|
|
1069
|
+
nomen_close_pending = 0;
|
|
327
1070
|
```
|
|
328
1071
|
```
|
|
329
1072
|
#arch: c
|
|
330
1073
|
#platform: ios
|
|
331
|
-
return -1;
|
|
332
1074
|
```
|
|
333
1075
|
```
|
|
334
1076
|
#arch: aarch64_use_c
|
|
335
1077
|
#platform: ios
|
|
336
|
-
return -1;
|
|
337
1078
|
```
|
|
338
1079
|
}
|
|
339
1080
|
|
|
@@ -409,6 +1150,270 @@ pub mv struct Window : Control {
|
|
|
409
1150
|
```
|
|
410
1151
|
}
|
|
411
1152
|
|
|
1153
|
+
// Resize the window's content area to width x height (displayed). The
|
|
1154
|
+
// programmatic stand-in for a user drag: it fires the same
|
|
1155
|
+
// windowDidResize: notifications (and the Container resize delegate), so
|
|
1156
|
+
// tests can exercise resize relayout headlessly.
|
|
1157
|
+
pub func set_size = (self, int width, int height) {
|
|
1158
|
+
```
|
|
1159
|
+
#arch: c
|
|
1160
|
+
#platform: macos
|
|
1161
|
+
((void(*)(id, SEL, double, double))objc_msgSend)(
|
|
1162
|
+
(id)self->handle, sel_registerName("setContentSize:"), (double)width, (double)height);
|
|
1163
|
+
```
|
|
1164
|
+
```
|
|
1165
|
+
#arch: aarch64_use_c
|
|
1166
|
+
#platform: macos
|
|
1167
|
+
((void(*)(id, SEL, double, double))objc_msgSend)(
|
|
1168
|
+
(id)self->handle, sel_registerName("setContentSize:"), (double)width, (double)height);
|
|
1169
|
+
```
|
|
1170
|
+
```
|
|
1171
|
+
#arch: c
|
|
1172
|
+
#platform: ios
|
|
1173
|
+
((void(*)(id, SEL, CGRect))objc_msgSend)(
|
|
1174
|
+
(id)self->handle, sel_registerName("setFrame:"),
|
|
1175
|
+
((CGRect(*)(double, double, double, double))CGRectMake)(0, 0, (double)width, (double)height));
|
|
1176
|
+
```
|
|
1177
|
+
```
|
|
1178
|
+
#arch: aarch64_use_c
|
|
1179
|
+
#platform: ios
|
|
1180
|
+
((void(*)(id, SEL, CGRect))objc_msgSend)(
|
|
1181
|
+
(id)self->handle, sel_registerName("setFrame:"),
|
|
1182
|
+
((CGRect(*)(double, double, double, double))CGRectMake)(0, 0, (double)width, (double)height));
|
|
1183
|
+
```
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// ── The App run loop (see App.nm) ──
|
|
1187
|
+
|
|
1188
|
+
// Register the layout root for Window.run: the root Container's layout
|
|
1189
|
+
// re-runs on start, on every live-resize delegate tick, and on each
|
|
1190
|
+
// frame where the content rect changed. The grid must outlive the run
|
|
1191
|
+
// (an app field — registration stores its address). Call from
|
|
1192
|
+
// App.start; also arms the resize delegate's target pair.
|
|
1193
|
+
pub func set_content = (ref self, ref Container grid) {
|
|
1194
|
+
```
|
|
1195
|
+
#arch: c
|
|
1196
|
+
#platform: macos
|
|
1197
|
+
#scope: file
|
|
1198
|
+
static void *nomen_run_root_grid = 0;
|
|
1199
|
+
static void *nomen_run_root_win = 0;
|
|
1200
|
+
```
|
|
1201
|
+
```
|
|
1202
|
+
#arch: aarch64_use_c
|
|
1203
|
+
#platform: macos
|
|
1204
|
+
#scope: file
|
|
1205
|
+
static void *nomen_run_root_grid = 0;
|
|
1206
|
+
static void *nomen_run_root_win = 0;
|
|
1207
|
+
```
|
|
1208
|
+
```
|
|
1209
|
+
#arch: c
|
|
1210
|
+
#platform: macos
|
|
1211
|
+
extern void nomen_set_resize_target(void *, void *);
|
|
1212
|
+
nomen_run_root_grid = (void *)grid;
|
|
1213
|
+
nomen_run_root_win = (void *)self;
|
|
1214
|
+
nomen_set_resize_target((void *)grid, (void *)self);
|
|
1215
|
+
```
|
|
1216
|
+
```
|
|
1217
|
+
#arch: aarch64_use_c
|
|
1218
|
+
#platform: macos
|
|
1219
|
+
extern void nomen_set_resize_target(void *, void *);
|
|
1220
|
+
nomen_run_root_grid = (void *)grid;
|
|
1221
|
+
nomen_run_root_win = (void *)self;
|
|
1222
|
+
nomen_set_resize_target((void *)grid, (void *)self);
|
|
1223
|
+
```
|
|
1224
|
+
```
|
|
1225
|
+
#arch: c
|
|
1226
|
+
#platform: ios
|
|
1227
|
+
/* TODO: iOS (see #init) */
|
|
1228
|
+
```
|
|
1229
|
+
```
|
|
1230
|
+
#arch: aarch64_use_c
|
|
1231
|
+
#platform: ios
|
|
1232
|
+
/* TODO: iOS (see #init) */
|
|
1233
|
+
```
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// One framework relayout pass: the registered root Container, then every
|
|
1237
|
+
// registered Scrollable's document dance (`first` drives its one-time
|
|
1238
|
+
// scroll_to_top), then every registered pane root's layout (tabs pages /
|
|
1239
|
+
// split panes re-frame when THIS pass frames their host view — the app
|
|
1240
|
+
// cannot know the moment, so registration hands the timing here).
|
|
1241
|
+
func relayout = (self, int first) {
|
|
1242
|
+
```
|
|
1243
|
+
#arch: c
|
|
1244
|
+
#platform: macos
|
|
1245
|
+
extern void nomen_layout_thunk(struct Container *, struct Window *);
|
|
1246
|
+
extern void nomen_scroll_relayout_all(void *, long);
|
|
1247
|
+
extern void nomen_pane_relayout_all(void);
|
|
1248
|
+
if (nomen_run_root_grid) {
|
|
1249
|
+
nomen_layout_thunk((struct Container *)nomen_run_root_grid, (struct Window *)self);
|
|
1250
|
+
}
|
|
1251
|
+
nomen_scroll_relayout_all((void *)self, first);
|
|
1252
|
+
nomen_pane_relayout_all();
|
|
1253
|
+
```
|
|
1254
|
+
```
|
|
1255
|
+
#arch: aarch64_use_c
|
|
1256
|
+
#platform: macos
|
|
1257
|
+
extern void nomen_layout_thunk(struct Container *, struct Window *);
|
|
1258
|
+
extern void nomen_scroll_relayout_all(void *, long);
|
|
1259
|
+
extern void nomen_pane_relayout_all(void);
|
|
1260
|
+
if (nomen_run_root_grid) {
|
|
1261
|
+
nomen_layout_thunk((struct Container *)nomen_run_root_grid, (struct Window *)self);
|
|
1262
|
+
}
|
|
1263
|
+
nomen_scroll_relayout_all((void *)self, first);
|
|
1264
|
+
nomen_pane_relayout_all();
|
|
1265
|
+
```
|
|
1266
|
+
```
|
|
1267
|
+
#arch: c
|
|
1268
|
+
#platform: ios
|
|
1269
|
+
/* TODO: iOS (see #init) */
|
|
1270
|
+
```
|
|
1271
|
+
```
|
|
1272
|
+
#arch: aarch64_use_c
|
|
1273
|
+
#platform: ios
|
|
1274
|
+
/* TODO: iOS (see #init) */
|
|
1275
|
+
```
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// Arm mouse-MOVED delivery. AppKit sends move events only when the
|
|
1279
|
+
// window opts in — run() arms it before the loop; manual-loop apps
|
|
1280
|
+
// pumping process_events directly call this once after creating the
|
|
1281
|
+
// window. Idempotent.
|
|
1282
|
+
pub func arm_mouse_moves = (self) {
|
|
1283
|
+
```
|
|
1284
|
+
#arch: c
|
|
1285
|
+
#platform: macos
|
|
1286
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
1287
|
+
(id)self->handle, sel_registerName("setAcceptsMouseMovedEvents:"), 1);
|
|
1288
|
+
```
|
|
1289
|
+
```
|
|
1290
|
+
#arch: aarch64_use_c
|
|
1291
|
+
#platform: macos
|
|
1292
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
1293
|
+
(id)self->handle, sel_registerName("setAcceptsMouseMovedEvents:"), 1);
|
|
1294
|
+
```
|
|
1295
|
+
```
|
|
1296
|
+
#arch: c
|
|
1297
|
+
#platform: ios
|
|
1298
|
+
```
|
|
1299
|
+
```
|
|
1300
|
+
#arch: aarch64_use_c
|
|
1301
|
+
#platform: ios
|
|
1302
|
+
```
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// Close the window (the programmatic stand-in for the red button) — the
|
|
1306
|
+
// run loop exits on the next `is_visible` check. Programmatic close is
|
|
1307
|
+
// FORCED: it bypasses the close_requested interception (the delegate's
|
|
1308
|
+
// windowShouldClose: sees nomen_close_forced and allows). Only the red
|
|
1309
|
+
// button routes through `close_requested`.
|
|
1310
|
+
pub func close = (self) {
|
|
1311
|
+
```
|
|
1312
|
+
#arch: c
|
|
1313
|
+
#platform: macos
|
|
1314
|
+
extern int nomen_close_forced;
|
|
1315
|
+
nomen_close_forced = 1;
|
|
1316
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)self->handle, sel_registerName("performClose:"), (id)0);
|
|
1317
|
+
```
|
|
1318
|
+
```
|
|
1319
|
+
#arch: aarch64_use_c
|
|
1320
|
+
#platform: macos
|
|
1321
|
+
extern int nomen_close_forced;
|
|
1322
|
+
nomen_close_forced = 1;
|
|
1323
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)self->handle, sel_registerName("performClose:"), (id)0);
|
|
1324
|
+
```
|
|
1325
|
+
```
|
|
1326
|
+
#arch: c
|
|
1327
|
+
#platform: ios
|
|
1328
|
+
/* TODO: iOS (see #init) */
|
|
1329
|
+
```
|
|
1330
|
+
```
|
|
1331
|
+
#arch: aarch64_use_c
|
|
1332
|
+
#platform: ios
|
|
1333
|
+
/* TODO: iOS (see #init) */
|
|
1334
|
+
```
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// Run the app: the framework owns everything from here until the window
|
|
1338
|
+
// closes. Order: `app.start` (the app registers its layout roots and its
|
|
1339
|
+
// click handlers while in final storage), the pre-show layout pass,
|
|
1340
|
+
// `show`, the post-show pass (the toolbar settles the content rect only
|
|
1341
|
+
// after show; this pass also performs the one-time scroll_to_top), then
|
|
1342
|
+
// the loop — pump events, detect resizes (framework relayout already
|
|
1343
|
+
// applied), drain the app's registered handlers (its synthesized
|
|
1344
|
+
// `handle_events` pump — the control-event desugars), and hand the app
|
|
1345
|
+
// a FrameEvents each frame.
|
|
1346
|
+
// The app is consumed: it is destroyed when the loop exits (controls
|
|
1347
|
+
// release, buffers free).
|
|
1348
|
+
pub func run = (ref self, mv App app) {
|
|
1349
|
+
app.start(ref self)
|
|
1350
|
+
Container.arm_resize_delegate(self)
|
|
1351
|
+
self.arm_mouse_moves()
|
|
1352
|
+
self.relayout(0)
|
|
1353
|
+
self.show()
|
|
1354
|
+
self.relayout(1)
|
|
1355
|
+
var int prev_w = self.content_width()
|
|
1356
|
+
var int prev_h = self.content_height()
|
|
1357
|
+
var ev = FrameEvents()
|
|
1358
|
+
while self.is_visible() {
|
|
1359
|
+
// Close interception: the delegate refused the native close and
|
|
1360
|
+
// set the pending flag; consult the app. Accept → forced close
|
|
1361
|
+
// (bypasses the delegate); decline → window stays, flag cleared.
|
|
1362
|
+
if self.close_pending() {
|
|
1363
|
+
if app.close_requested(ref self) {
|
|
1364
|
+
self.close()
|
|
1365
|
+
}
|
|
1366
|
+
self.clear_close_pending()
|
|
1367
|
+
}
|
|
1368
|
+
// An accepted close above releases the native window mid-frame;
|
|
1369
|
+
// skip the rest of this iteration (the while re-checks and
|
|
1370
|
+
// exits).
|
|
1371
|
+
if self.is_visible() {
|
|
1372
|
+
ev.click = Window.process_events()
|
|
1373
|
+
ev.click_x = self.click_x()
|
|
1374
|
+
ev.click_y = self.click_y()
|
|
1375
|
+
ev.mouse_button = self.mouse_button()
|
|
1376
|
+
ev.mouse_click_count = self.mouse_click_count()
|
|
1377
|
+
ev.mouse_modifiers = self.mouse_modifiers()
|
|
1378
|
+
ev.scroll_dx = self.scroll_dx()
|
|
1379
|
+
ev.scroll_dy = self.scroll_dy()
|
|
1380
|
+
ev.key_code = self.key_code()
|
|
1381
|
+
ev.key_modifiers = self.key_modifiers()
|
|
1382
|
+
ev.key_repeat = self.key_repeat()
|
|
1383
|
+
ev.key_up_code = self.key_up_code()
|
|
1384
|
+
ev.mouse_x = self.mouse_x()
|
|
1385
|
+
ev.mouse_y = self.mouse_y()
|
|
1386
|
+
ev.dt = self.dt()
|
|
1387
|
+
ev.resized = false
|
|
1388
|
+
self.stamp_resize(false, 0, 0)
|
|
1389
|
+
var int cur_w = self.content_width()
|
|
1390
|
+
var int cur_h = self.content_height()
|
|
1391
|
+
if cur_w != prev_w {
|
|
1392
|
+
ev.resized = true
|
|
1393
|
+
}
|
|
1394
|
+
if cur_h != prev_h {
|
|
1395
|
+
ev.resized = true
|
|
1396
|
+
}
|
|
1397
|
+
if ev.resized {
|
|
1398
|
+
prev_w = cur_w
|
|
1399
|
+
prev_h = cur_h
|
|
1400
|
+
ev.width = cur_w
|
|
1401
|
+
ev.height = cur_h
|
|
1402
|
+
self.stamp_resize(true, cur_w, cur_h)
|
|
1403
|
+
self.relayout(0)
|
|
1404
|
+
}
|
|
1405
|
+
// The window refreshes the per-frame event sources (the
|
|
1406
|
+
// first-responder snapshot feeds the focus/blur drains), then the
|
|
1407
|
+
// app's synthesized `handle_events` pump drains registered
|
|
1408
|
+
// handlers — conformers without registrations inherit the
|
|
1409
|
+
// trait's empty default. One arm per registered control.
|
|
1410
|
+
nomen_window_focus_poll(self.handle)
|
|
1411
|
+
app.handle_events(ref self)
|
|
1412
|
+
app.frame(ref self, ev)
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
412
1417
|
// ── Control trait conformance ──
|
|
413
1418
|
// The window is the layout root: it measures to its content-view size and
|
|
414
1419
|
// applies a frame to the native NSWindow/UIWindow.
|
|
@@ -431,16 +1436,22 @@ pub mv struct Window : Control {
|
|
|
431
1436
|
```
|
|
432
1437
|
#arch: c
|
|
433
1438
|
#platform: macos
|
|
434
|
-
(
|
|
435
|
-
|
|
436
|
-
|
|
1439
|
+
// NSWindow has no plain `setFrame:` (that is NSView's) — the window
|
|
1440
|
+
// API takes the display flag.
|
|
1441
|
+
((void(*)(id, SEL, CGRect, BOOL))objc_msgSend)(
|
|
1442
|
+
(id)self->handle, sel_registerName("setFrame:display:"),
|
|
1443
|
+
((CGRect(*)(double, double, double, double))CGRectMake)((double)x, (double)y, (double)width, (double)height),
|
|
1444
|
+
1);
|
|
437
1445
|
```
|
|
438
1446
|
```
|
|
439
1447
|
#arch: aarch64_use_c
|
|
440
1448
|
#platform: macos
|
|
441
|
-
(
|
|
442
|
-
|
|
443
|
-
|
|
1449
|
+
// NSWindow has no plain `setFrame:` (that is NSView's) — the window
|
|
1450
|
+
// API takes the display flag.
|
|
1451
|
+
((void(*)(id, SEL, CGRect, BOOL))objc_msgSend)(
|
|
1452
|
+
(id)self->handle, sel_registerName("setFrame:display:"),
|
|
1453
|
+
((CGRect(*)(double, double, double, double))CGRectMake)((double)x, (double)y, (double)width, (double)height),
|
|
1454
|
+
1);
|
|
444
1455
|
```
|
|
445
1456
|
```
|
|
446
1457
|
#arch: c
|
|
@@ -493,3 +1504,449 @@ pub mv struct Window : Control {
|
|
|
493
1504
|
```
|
|
494
1505
|
}
|
|
495
1506
|
}
|
|
1507
|
+
|
|
1508
|
+
// Arm click recording on a registered view. NSButton-family controls are
|
|
1509
|
+
// armed at construction (nomen_control_arm_clicks) and already push to the
|
|
1510
|
+
// ring; this re-arms those harmlessly and covers every OTHER view through
|
|
1511
|
+
// an NSClickGestureRecognizer whose handler records the recognized view —
|
|
1512
|
+
// the Nomen handle — into the same ring. Idempotent per handle (the armed
|
|
1513
|
+
// set below — a desugar dispatch arm calls this every frame, and a fresh
|
|
1514
|
+
// recognizer per call would accumulate); the recognizer target class is
|
|
1515
|
+
// still built once per process.
|
|
1516
|
+
// ── Registered control events (focus / blur / input) ──
|
|
1517
|
+
//
|
|
1518
|
+
// The desugar's control-carried events beyond clicks (docs/HANDLERS.md):
|
|
1519
|
+
// `self.<field>.on_focus / on_blur / on_input(func () { ... })`. The
|
|
1520
|
+
// window is the focus authority, so the snapshot lives here: the
|
|
1521
|
+
// synthesized focus dispatcher calls `nomen_window_focus_poll` ONCE per
|
|
1522
|
+
// frame (prev/cur first responder — the field editor maps back to the
|
|
1523
|
+
// editing control), then each arm is a pure snapshot compare via
|
|
1524
|
+
// `nomen_control_take_focus` / `take_blur` — order-independent across
|
|
1525
|
+
// arms, and both sides of a handoff (A's blur, B's focus) fire in the
|
|
1526
|
+
// same frame. Input edges are per-control text compares
|
|
1527
|
+
// (`nomen_control_take_input`): the field editor writes through to the
|
|
1528
|
+
// control's stringValue while typing, so each keystroke is one edge.
|
|
1529
|
+
|
|
1530
|
+
// Refresh the focus snapshot (prev/cur first responder of `window`).
|
|
1531
|
+
// Idempotent per frame; the synthesized focus dispatcher calls it once
|
|
1532
|
+
// before the arms.
|
|
1533
|
+
pub func nomen_window_focus_poll = (uint64 window) {
|
|
1534
|
+
```
|
|
1535
|
+
#arch: c
|
|
1536
|
+
#platform: macos
|
|
1537
|
+
#scope: file
|
|
1538
|
+
// Shared with the take_focus / take_blur drains (same TU): the snapshot
|
|
1539
|
+
// has external linkage and ONE definition (here); the drains declare it
|
|
1540
|
+
// extern.
|
|
1541
|
+
unsigned long long nomen_focus_prev = 0;
|
|
1542
|
+
unsigned long long nomen_focus_cur = 0;
|
|
1543
|
+
void *nomen_focus_window = 0;
|
|
1544
|
+
static id nomen_focus_responder(void *win) {
|
|
1545
|
+
id fr = ((id(*)(id, SEL))objc_msgSend)((id)win, sel_registerName("firstResponder"));
|
|
1546
|
+
// While a text control is being edited, the first responder is the
|
|
1547
|
+
// window's FIELD EDITOR — map it back to the editing control (the
|
|
1548
|
+
// editor's delegate) so focus edges name the control.
|
|
1549
|
+
if (((BOOL(*)(id, SEL, id))objc_msgSend)(fr, sel_registerName("isKindOfClass:"), (id)objc_getClass("NSTextView"))) {
|
|
1550
|
+
id d = ((id(*)(id, SEL))objc_msgSend)(fr, sel_registerName("delegate"));
|
|
1551
|
+
if (d) fr = d;
|
|
1552
|
+
}
|
|
1553
|
+
return fr;
|
|
1554
|
+
}
|
|
1555
|
+
```
|
|
1556
|
+
```
|
|
1557
|
+
#arch: aarch64_use_c
|
|
1558
|
+
#platform: macos
|
|
1559
|
+
#scope: file
|
|
1560
|
+
unsigned long long nomen_focus_prev = 0;
|
|
1561
|
+
unsigned long long nomen_focus_cur = 0;
|
|
1562
|
+
void *nomen_focus_window = 0;
|
|
1563
|
+
static id nomen_focus_responder(void *win) {
|
|
1564
|
+
id fr = ((id(*)(id, SEL))objc_msgSend)((id)win, sel_registerName("firstResponder"));
|
|
1565
|
+
if (((BOOL(*)(id, SEL, id))objc_msgSend)(fr, sel_registerName("isKindOfClass:"), (id)objc_getClass("NSTextView"))) {
|
|
1566
|
+
id d = ((id(*)(id, SEL))objc_msgSend)(fr, sel_registerName("delegate"));
|
|
1567
|
+
if (d) fr = d;
|
|
1568
|
+
}
|
|
1569
|
+
return fr;
|
|
1570
|
+
}
|
|
1571
|
+
```
|
|
1572
|
+
```
|
|
1573
|
+
#arch: c
|
|
1574
|
+
#platform: macos
|
|
1575
|
+
void *win = (void *)window;
|
|
1576
|
+
id fr = nomen_focus_responder(win);
|
|
1577
|
+
if (nomen_focus_window != win) {
|
|
1578
|
+
// A different window took the snapshot: re-baseline (no edge).
|
|
1579
|
+
nomen_focus_window = win;
|
|
1580
|
+
nomen_focus_cur = (unsigned long long)(void *)fr;
|
|
1581
|
+
nomen_focus_prev = nomen_focus_cur;
|
|
1582
|
+
} else {
|
|
1583
|
+
nomen_focus_prev = nomen_focus_cur;
|
|
1584
|
+
nomen_focus_cur = (unsigned long long)(void *)fr;
|
|
1585
|
+
}
|
|
1586
|
+
```
|
|
1587
|
+
```
|
|
1588
|
+
#arch: aarch64_use_c
|
|
1589
|
+
#platform: macos
|
|
1590
|
+
void *win = (void *)window;
|
|
1591
|
+
id fr = nomen_focus_responder(win);
|
|
1592
|
+
if (nomen_focus_window != win) {
|
|
1593
|
+
nomen_focus_window = win;
|
|
1594
|
+
nomen_focus_cur = (unsigned long long)(void *)fr;
|
|
1595
|
+
nomen_focus_prev = nomen_focus_cur;
|
|
1596
|
+
} else {
|
|
1597
|
+
nomen_focus_prev = nomen_focus_cur;
|
|
1598
|
+
nomen_focus_cur = (unsigned long long)(void *)fr;
|
|
1599
|
+
}
|
|
1600
|
+
```
|
|
1601
|
+
```
|
|
1602
|
+
#arch: c
|
|
1603
|
+
#platform: ios
|
|
1604
|
+
/* TODO: iOS (first responder via UITextField delegates) */
|
|
1605
|
+
```
|
|
1606
|
+
```
|
|
1607
|
+
#arch: aarch64_use_c
|
|
1608
|
+
#platform: ios
|
|
1609
|
+
/* TODO: iOS (see #arch: c) */
|
|
1610
|
+
```
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// Whether the most recent pump saw a right-mouse-down (the same record
|
|
1614
|
+
// FrameEvents.click reports as 2). Read by Container.take_right_click —
|
|
1615
|
+
// the on_right_click drain (docs/HANDLERS.md). The pump stamps the kind
|
|
1616
|
+
// on EVERY call — a quiet pump stamps 0 — so the edge expires with the
|
|
1617
|
+
// frame: the drains see it exactly in the handle_events pass that follows
|
|
1618
|
+
// the pump, and no clearing handshake is needed. The record is
|
|
1619
|
+
// window-level (one per process, like click_x/click_y): every registered
|
|
1620
|
+
// arm sees the edge (broadcast), and the HANDLER disambiguates — read the
|
|
1621
|
+
// click through the dispatch window (win.click_x()/click_y()), translate
|
|
1622
|
+
// for scrollables (content_click), hit-test children (contains).
|
|
1623
|
+
pub func nomen_window_had_right_click = (out bool) {
|
|
1624
|
+
```
|
|
1625
|
+
#arch: c
|
|
1626
|
+
#platform: macos
|
|
1627
|
+
// One definition lives in process_events' file-scope block (this file);
|
|
1628
|
+
// the extern keeps this function's TU-independent (split builds).
|
|
1629
|
+
extern int nomen_last_click_kind;
|
|
1630
|
+
return nomen_last_click_kind == 2;
|
|
1631
|
+
```
|
|
1632
|
+
```
|
|
1633
|
+
#arch: aarch64_use_c
|
|
1634
|
+
#platform: macos
|
|
1635
|
+
extern int nomen_last_click_kind;
|
|
1636
|
+
return nomen_last_click_kind == 2;
|
|
1637
|
+
```
|
|
1638
|
+
```
|
|
1639
|
+
#arch: c
|
|
1640
|
+
#platform: ios
|
|
1641
|
+
return 0;
|
|
1642
|
+
```
|
|
1643
|
+
```
|
|
1644
|
+
#arch: aarch64_use_c
|
|
1645
|
+
#platform: ios
|
|
1646
|
+
return 0;
|
|
1647
|
+
```
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// Focus EDGE drain: true when `handle` GAINED first-responder status this
|
|
1651
|
+
// frame. Pure snapshot compare — no state update, so any number of
|
|
1652
|
+
// focus/blur arms can poll the same frame in any order.
|
|
1653
|
+
pub func nomen_control_take_focus = (uint64 handle, out bool) {
|
|
1654
|
+
```
|
|
1655
|
+
#arch: c
|
|
1656
|
+
#platform: macos
|
|
1657
|
+
#scope: file
|
|
1658
|
+
extern unsigned long long nomen_focus_prev;
|
|
1659
|
+
extern unsigned long long nomen_focus_cur;
|
|
1660
|
+
extern void *nomen_focus_window;
|
|
1661
|
+
static id nomen_focus_responder(void *win);
|
|
1662
|
+
```
|
|
1663
|
+
```
|
|
1664
|
+
#arch: c
|
|
1665
|
+
#platform: macos
|
|
1666
|
+
int known = nomen_focus_window != 0;
|
|
1667
|
+
id fr = known ? nomen_focus_responder(nomen_focus_window) : 0;
|
|
1668
|
+
int gained =
|
|
1669
|
+
known && ((unsigned long long)(void *)fr == handle) && (nomen_focus_prev != handle);
|
|
1670
|
+
return gained;
|
|
1671
|
+
```
|
|
1672
|
+
```
|
|
1673
|
+
#arch: aarch64_use_c
|
|
1674
|
+
#platform: macos
|
|
1675
|
+
#scope: file
|
|
1676
|
+
extern unsigned long long nomen_focus_prev;
|
|
1677
|
+
extern unsigned long long nomen_focus_cur;
|
|
1678
|
+
extern void *nomen_focus_window;
|
|
1679
|
+
static id nomen_focus_responder(void *win);
|
|
1680
|
+
```
|
|
1681
|
+
```
|
|
1682
|
+
#arch: aarch64_use_c
|
|
1683
|
+
#platform: macos
|
|
1684
|
+
int known = nomen_focus_window != 0;
|
|
1685
|
+
id fr = known ? nomen_focus_responder(nomen_focus_window) : 0;
|
|
1686
|
+
int gained =
|
|
1687
|
+
known && ((unsigned long long)(void *)fr == handle) && (nomen_focus_prev != handle);
|
|
1688
|
+
return gained;
|
|
1689
|
+
```
|
|
1690
|
+
```
|
|
1691
|
+
#arch: c
|
|
1692
|
+
#platform: ios
|
|
1693
|
+
return 0;
|
|
1694
|
+
```
|
|
1695
|
+
```
|
|
1696
|
+
#arch: aarch64_use_c
|
|
1697
|
+
#platform: ios
|
|
1698
|
+
return 0;
|
|
1699
|
+
```
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// Blur EDGE drain: true when `handle` LOST first-responder status this
|
|
1703
|
+
// frame (it was focused on the previous poll and is not now).
|
|
1704
|
+
pub func nomen_control_take_blur = (uint64 handle, out bool) {
|
|
1705
|
+
```
|
|
1706
|
+
#arch: c
|
|
1707
|
+
#platform: macos
|
|
1708
|
+
#scope: file
|
|
1709
|
+
extern unsigned long long nomen_focus_prev;
|
|
1710
|
+
extern unsigned long long nomen_focus_cur;
|
|
1711
|
+
extern void *nomen_focus_window;
|
|
1712
|
+
static id nomen_focus_responder(void *win);
|
|
1713
|
+
```
|
|
1714
|
+
```
|
|
1715
|
+
#arch: c
|
|
1716
|
+
#platform: macos
|
|
1717
|
+
int known = nomen_focus_window != 0;
|
|
1718
|
+
id fr = known ? nomen_focus_responder(nomen_focus_window) : 0;
|
|
1719
|
+
int lost =
|
|
1720
|
+
known && (nomen_focus_prev == handle) && ((unsigned long long)(void *)fr != handle);
|
|
1721
|
+
return lost;
|
|
1722
|
+
```
|
|
1723
|
+
```
|
|
1724
|
+
#arch: aarch64_use_c
|
|
1725
|
+
#platform: macos
|
|
1726
|
+
#scope: file
|
|
1727
|
+
extern unsigned long long nomen_focus_prev;
|
|
1728
|
+
extern unsigned long long nomen_focus_cur;
|
|
1729
|
+
extern void *nomen_focus_window;
|
|
1730
|
+
static id nomen_focus_responder(void *win);
|
|
1731
|
+
```
|
|
1732
|
+
```
|
|
1733
|
+
#arch: aarch64_use_c
|
|
1734
|
+
#platform: macos
|
|
1735
|
+
int known = nomen_focus_window != 0;
|
|
1736
|
+
id fr = known ? nomen_focus_responder(nomen_focus_window) : 0;
|
|
1737
|
+
int lost =
|
|
1738
|
+
known && (nomen_focus_prev == handle) && ((unsigned long long)(void *)fr != handle);
|
|
1739
|
+
return lost;
|
|
1740
|
+
```
|
|
1741
|
+
```
|
|
1742
|
+
#arch: c
|
|
1743
|
+
#platform: ios
|
|
1744
|
+
return 0;
|
|
1745
|
+
```
|
|
1746
|
+
```
|
|
1747
|
+
#arch: aarch64_use_c
|
|
1748
|
+
#platform: ios
|
|
1749
|
+
return 0;
|
|
1750
|
+
```
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// Text-INPUT edge drain: true when the control's text changed since the
|
|
1754
|
+
// last drain for this handle (the field editor writes through to the
|
|
1755
|
+
// control's stringValue while typing, so each keystroke is one edge).
|
|
1756
|
+
// Last-seen text is tracked per handle.
|
|
1757
|
+
pub func nomen_control_take_input = (uint64 handle, out bool) {
|
|
1758
|
+
```
|
|
1759
|
+
#arch: c
|
|
1760
|
+
#platform: macos
|
|
1761
|
+
#scope: file
|
|
1762
|
+
struct nomen_input_seen {
|
|
1763
|
+
void *handle;
|
|
1764
|
+
char *last;
|
|
1765
|
+
};
|
|
1766
|
+
static struct nomen_input_seen nomen_input_seen[32];
|
|
1767
|
+
static int nomen_input_seen_count = 0;
|
|
1768
|
+
```
|
|
1769
|
+
```
|
|
1770
|
+
#arch: c
|
|
1771
|
+
#platform: macos
|
|
1772
|
+
struct nomen_input_seen *e = 0;
|
|
1773
|
+
for (int i = 0; i < nomen_input_seen_count; i++) {
|
|
1774
|
+
if (nomen_input_seen[i].handle == (void *)handle) {
|
|
1775
|
+
e = &nomen_input_seen[i];
|
|
1776
|
+
break;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
if (!e && nomen_input_seen_count < 32) {
|
|
1780
|
+
e = &nomen_input_seen[nomen_input_seen_count++];
|
|
1781
|
+
e->handle = (void *)handle;
|
|
1782
|
+
e->last = 0;
|
|
1783
|
+
}
|
|
1784
|
+
if (!e) return 0;
|
|
1785
|
+
// stringValue returns the live text (the field editor writes through to
|
|
1786
|
+
// it while typing); UTF8String goes through the returned NSString.
|
|
1787
|
+
id s = ((id(*)(id, SEL))objc_msgSend)((id)handle, sel_registerName("stringValue"));
|
|
1788
|
+
const char *cur = ((const char *(*)(id, SEL))objc_msgSend)(s, sel_registerName("UTF8String"));
|
|
1789
|
+
// First sight of a handle: record the baseline silently — no edge.
|
|
1790
|
+
if (!e->last) {
|
|
1791
|
+
e->last = strdup(cur);
|
|
1792
|
+
return 0;
|
|
1793
|
+
}
|
|
1794
|
+
int changed = strcmp(e->last, cur) != 0;
|
|
1795
|
+
if (changed) {
|
|
1796
|
+
free(e->last);
|
|
1797
|
+
e->last = strdup(cur);
|
|
1798
|
+
}
|
|
1799
|
+
return changed;
|
|
1800
|
+
```
|
|
1801
|
+
```
|
|
1802
|
+
#arch: aarch64_use_c
|
|
1803
|
+
#platform: macos
|
|
1804
|
+
#scope: file
|
|
1805
|
+
struct nomen_input_seen {
|
|
1806
|
+
void *handle;
|
|
1807
|
+
char *last;
|
|
1808
|
+
};
|
|
1809
|
+
static struct nomen_input_seen nomen_input_seen[32];
|
|
1810
|
+
static int nomen_input_seen_count = 0;
|
|
1811
|
+
```
|
|
1812
|
+
```
|
|
1813
|
+
#arch: aarch64_use_c
|
|
1814
|
+
#platform: macos
|
|
1815
|
+
struct nomen_input_seen *e = 0;
|
|
1816
|
+
for (int i = 0; i < nomen_input_seen_count; i++) {
|
|
1817
|
+
if (nomen_input_seen[i].handle == (void *)handle) {
|
|
1818
|
+
e = &nomen_input_seen[i];
|
|
1819
|
+
break;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
if (!e && nomen_input_seen_count < 32) {
|
|
1823
|
+
e = &nomen_input_seen[nomen_input_seen_count++];
|
|
1824
|
+
e->handle = (void *)handle;
|
|
1825
|
+
e->last = 0;
|
|
1826
|
+
}
|
|
1827
|
+
if (!e) return 0;
|
|
1828
|
+
// stringValue returns the live text (the field editor writes through to
|
|
1829
|
+
// it while typing); UTF8String goes through the returned NSString.
|
|
1830
|
+
id s = ((id(*)(id, SEL))objc_msgSend)((id)handle, sel_registerName("stringValue"));
|
|
1831
|
+
const char *cur = ((const char *(*)(id, SEL))objc_msgSend)(s, sel_registerName("UTF8String"));
|
|
1832
|
+
// First sight of a handle: record the baseline silently — no edge.
|
|
1833
|
+
if (!e->last) {
|
|
1834
|
+
e->last = strdup(cur);
|
|
1835
|
+
return 0;
|
|
1836
|
+
}
|
|
1837
|
+
int changed = strcmp(e->last, cur) != 0;
|
|
1838
|
+
if (changed) {
|
|
1839
|
+
free(e->last);
|
|
1840
|
+
e->last = strdup(cur);
|
|
1841
|
+
}
|
|
1842
|
+
return changed;
|
|
1843
|
+
```
|
|
1844
|
+
```
|
|
1845
|
+
#arch: c
|
|
1846
|
+
#platform: ios
|
|
1847
|
+
return 0;
|
|
1848
|
+
```
|
|
1849
|
+
```
|
|
1850
|
+
#arch: aarch64_use_c
|
|
1851
|
+
#platform: ios
|
|
1852
|
+
return 0;
|
|
1853
|
+
```
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
pub func nomen_window_clicks_init = (uint64 handle) {
|
|
1857
|
+
```
|
|
1858
|
+
#arch: c
|
|
1859
|
+
#platform: macos
|
|
1860
|
+
#scope: file
|
|
1861
|
+
// The armed set: handles this process already armed (a desugar dispatch
|
|
1862
|
+
// arm re-calls per frame; re-arming would stack recognizers).
|
|
1863
|
+
static unsigned long long nomen_armed_handles[128];
|
|
1864
|
+
static int nomen_armed_count = 0;
|
|
1865
|
+
// The shared gesture target (one class pair per process; the handler
|
|
1866
|
+
// reads the gesture's view — the Nomen handle — and pushes the same
|
|
1867
|
+
// ring the button family's target/action uses).
|
|
1868
|
+
static void nomen_view_click_gesture(id self, SEL cmd, id gesture) {
|
|
1869
|
+
(void)self; (void)cmd;
|
|
1870
|
+
id view = ((id(*)(id, SEL))objc_msgSend)(gesture, sel_registerName("view"));
|
|
1871
|
+
nomen_click_push((unsigned long long)(void *)view);
|
|
1872
|
+
}
|
|
1873
|
+
static void nomen_window_click_arm(unsigned long long handle) {
|
|
1874
|
+
for (int i = 0; i < nomen_armed_count; i++) {
|
|
1875
|
+
if (nomen_armed_handles[i] == handle) return;
|
|
1876
|
+
}
|
|
1877
|
+
if (nomen_armed_count < 128) nomen_armed_handles[nomen_armed_count++] = handle;
|
|
1878
|
+
Class Tc = objc_getClass("NomenViewClickTarget");
|
|
1879
|
+
if (!Tc) {
|
|
1880
|
+
Tc = objc_allocateClassPair(objc_getClass("NSObject"), "NomenViewClickTarget", 0);
|
|
1881
|
+
if (Tc) {
|
|
1882
|
+
class_addMethod(Tc, sel_registerName("viewClickGesture:"), (IMP)nomen_view_click_gesture, "v@:@");
|
|
1883
|
+
objc_registerClassPair(Tc);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
if (!Tc) return;
|
|
1887
|
+
id target = ((id(*)(id, SEL))objc_msgSend)((id)Tc, sel_registerName("new"));
|
|
1888
|
+
id rec = ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSClickGestureRecognizer"), sel_registerName("alloc"));
|
|
1889
|
+
rec = ((id(*)(id, SEL, id, SEL))objc_msgSend)(
|
|
1890
|
+
rec, sel_registerName("initWithTarget:action:"), (id)target, sel_registerName("viewClickGesture:"));
|
|
1891
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)handle, sel_registerName("addGestureRecognizer:"), (id)rec);
|
|
1892
|
+
}
|
|
1893
|
+
```
|
|
1894
|
+
```
|
|
1895
|
+
#arch: c
|
|
1896
|
+
#platform: macos
|
|
1897
|
+
nomen_window_click_arm(handle);
|
|
1898
|
+
```
|
|
1899
|
+
```
|
|
1900
|
+
#arch: aarch64_use_c
|
|
1901
|
+
#platform: macos
|
|
1902
|
+
#scope: file
|
|
1903
|
+
// The armed set: handles this process already armed (a desugar dispatch
|
|
1904
|
+
// arm re-calls per frame; re-arming would stack recognizers).
|
|
1905
|
+
static unsigned long long nomen_armed_handles[128];
|
|
1906
|
+
static int nomen_armed_count = 0;
|
|
1907
|
+
// Forward declaration: the ring lives in Control.nm's file-scope
|
|
1908
|
+
// block, whose carrier may hoist AFTER this one (build order, not
|
|
1909
|
+
// source order).
|
|
1910
|
+
static void nomen_click_push(unsigned long long h);
|
|
1911
|
+
static void nomen_view_click_gesture(id self, SEL cmd, id gesture) {
|
|
1912
|
+
(void)self; (void)cmd;
|
|
1913
|
+
id view = ((id(*)(id, SEL))objc_msgSend)(gesture, sel_registerName("view"));
|
|
1914
|
+
nomen_click_push((unsigned long long)(void *)view);
|
|
1915
|
+
}
|
|
1916
|
+
static void nomen_window_click_arm(unsigned long long handle) {
|
|
1917
|
+
for (int i = 0; i < nomen_armed_count; i++) {
|
|
1918
|
+
if (nomen_armed_handles[i] == handle) return;
|
|
1919
|
+
}
|
|
1920
|
+
if (nomen_armed_count < 128) nomen_armed_handles[nomen_armed_count++] = handle;
|
|
1921
|
+
Class Tc = objc_getClass("NomenViewClickTarget");
|
|
1922
|
+
if (!Tc) {
|
|
1923
|
+
Tc = objc_allocateClassPair(objc_getClass("NSObject"), "NomenViewClickTarget", 0);
|
|
1924
|
+
if (Tc) {
|
|
1925
|
+
class_addMethod(Tc, sel_registerName("viewClickGesture:"), (IMP)nomen_view_click_gesture, "v@:@");
|
|
1926
|
+
objc_registerClassPair(Tc);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
if (!Tc) return;
|
|
1930
|
+
id target = ((id(*)(id, SEL))objc_msgSend)((id)Tc, sel_registerName("new"));
|
|
1931
|
+
id rec = ((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSClickGestureRecognizer"), sel_registerName("alloc"));
|
|
1932
|
+
rec = ((id(*)(id, SEL, id, SEL))objc_msgSend)(
|
|
1933
|
+
rec, sel_registerName("initWithTarget:action:"), (id)target, sel_registerName("viewClickGesture:"));
|
|
1934
|
+
((void(*)(id, SEL, id))objc_msgSend)((id)handle, sel_registerName("addGestureRecognizer:"), (id)rec);
|
|
1935
|
+
}
|
|
1936
|
+
```
|
|
1937
|
+
```
|
|
1938
|
+
#arch: aarch64_use_c
|
|
1939
|
+
#platform: macos
|
|
1940
|
+
nomen_window_click_arm(handle);
|
|
1941
|
+
```
|
|
1942
|
+
```
|
|
1943
|
+
#arch: c
|
|
1944
|
+
#platform: ios
|
|
1945
|
+
/* TODO: iOS (UITapGestureRecognizer shape; see nomen_control_arm_clicks) */
|
|
1946
|
+
```
|
|
1947
|
+
```
|
|
1948
|
+
#arch: aarch64_use_c
|
|
1949
|
+
#platform: ios
|
|
1950
|
+
/* TODO: iOS (UITapGestureRecognizer shape; see nomen_control_arm_clicks) */
|
|
1951
|
+
```
|
|
1952
|
+
}
|