@geastack/apple 0.2.8

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.
Files changed (113) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +54 -0
  3. package/dist/index.d.ts +127 -0
  4. package/dist/index.js +3076 -0
  5. package/generated/AVFoundation.d.ts +112 -0
  6. package/generated/ActivityKit.d.ts +7 -0
  7. package/generated/AppKit.d.ts +268 -0
  8. package/generated/CoreGraphics.d.ts +18 -0
  9. package/generated/CoreLocation.d.ts +28 -0
  10. package/generated/CoreMedia.d.ts +8 -0
  11. package/generated/Dispatch.d.ts +2 -0
  12. package/generated/Foundation.d.ts +13 -0
  13. package/generated/MapKit.d.ts +28 -0
  14. package/generated/Metal.d.ts +91 -0
  15. package/generated/MetalKit.d.ts +22 -0
  16. package/generated/Photos.d.ts +5 -0
  17. package/generated/QuartzCore.d.ts +12 -0
  18. package/generated/SwiftData.d.ts +11 -0
  19. package/generated/UIKit.d.ts +187 -0
  20. package/package.json +123 -0
  21. package/runtime/AVFoundation.js +136 -0
  22. package/runtime/ActivityKit.js +18 -0
  23. package/runtime/AppKit.js +313 -0
  24. package/runtime/CoreGraphics.js +15 -0
  25. package/runtime/CoreLocation.js +30 -0
  26. package/runtime/CoreMedia.js +7 -0
  27. package/runtime/Dispatch.js +11 -0
  28. package/runtime/Foundation.js +21 -0
  29. package/runtime/MapKit.js +22 -0
  30. package/runtime/Metal.js +126 -0
  31. package/runtime/MetalKit.js +15 -0
  32. package/runtime/Photos.js +9 -0
  33. package/runtime/QuartzCore.js +9 -0
  34. package/runtime/SwiftData.js +29 -0
  35. package/runtime/UIKit.js +242 -0
  36. package/runtime/empty.js +1 -0
  37. package/targets/ios/Info.plist.in +25 -0
  38. package/targets/ios/README.md +46 -0
  39. package/targets/ios/build-ios.sh +395 -0
  40. package/targets/ios/detect-development-team.mjs +109 -0
  41. package/targets/ios/generate-resident-entry.mjs +67 -0
  42. package/targets/ios/generate-resident-registry.mjs +162 -0
  43. package/targets/ios/generate-xcode-project.mjs +520 -0
  44. package/targets/ios/main/canvas_view.h +7 -0
  45. package/targets/ios/main/canvas_view.mm +94 -0
  46. package/targets/ios/main/font_registry.h +17 -0
  47. package/targets/ios/main/font_registry.mm +129 -0
  48. package/targets/ios/main/image_bridge.h +13 -0
  49. package/targets/ios/main/image_bridge.mm +53 -0
  50. package/targets/ios/main/ios_apps.c +28 -0
  51. package/targets/ios/main/ios_camera.mm +446 -0
  52. package/targets/ios/main/ios_display.mm +344 -0
  53. package/targets/ios/main/ios_main.mm +811 -0
  54. package/targets/ios/main/ios_memory.cpp +55 -0
  55. package/targets/ios/main/ios_renderer.h +20 -0
  56. package/targets/ios/main/ios_renderer.mm +27 -0
  57. package/targets/ios/main/ios_root_background.cpp +20 -0
  58. package/targets/ios/main/ios_root_background.h +11 -0
  59. package/targets/ios/main/ios_sensors.mm +244 -0
  60. package/targets/ios/main/ios_timers.mm +53 -0
  61. package/targets/ios/main/renderer/ios_renderer_internal.h +65 -0
  62. package/targets/ios/main/renderer/ios_renderer_support.mm +111 -0
  63. package/targets/ios/main/renderer/native_button.mm +179 -0
  64. package/targets/ios/main/renderer/native_label.mm +161 -0
  65. package/targets/ios/main/renderer/native_scroll_container.mm +279 -0
  66. package/targets/ios/main/renderer/view_reconciler.mm +274 -0
  67. package/targets/macos/Info.plist.in +26 -0
  68. package/targets/macos/README.md +131 -0
  69. package/targets/macos/build-child-lifecycle.sh +119 -0
  70. package/targets/macos/build-macos.sh +2156 -0
  71. package/targets/macos/check-module-graph-freshness.mjs +82 -0
  72. package/targets/macos/compiler-input-fingerprint.mjs +32 -0
  73. package/targets/macos/finalize-apple-native-output.mjs +77 -0
  74. package/targets/macos/generate-resident-entry.mjs +80 -0
  75. package/targets/macos/generate-resident-registry.mjs +141 -0
  76. package/targets/macos/heavy-build-lock.sh +176 -0
  77. package/targets/macos/main/canvas_view.h +9 -0
  78. package/targets/macos/main/canvas_view.mm +176 -0
  79. package/targets/macos/main/color_convert.h +18 -0
  80. package/targets/macos/main/color_convert.mm +39 -0
  81. package/targets/macos/main/font_registry.h +35 -0
  82. package/targets/macos/main/font_registry.mm +350 -0
  83. package/targets/macos/main/image_bridge.h +16 -0
  84. package/targets/macos/main/image_bridge.mm +52 -0
  85. package/targets/macos/main/macos_app_platform.mm +95 -0
  86. package/targets/macos/main/macos_apps.c +31 -0
  87. package/targets/macos/main/macos_device_control.mm +56 -0
  88. package/targets/macos/main/macos_display.mm +484 -0
  89. package/targets/macos/main/macos_host_device_control.mm +95 -0
  90. package/targets/macos/main/macos_main.mm +839 -0
  91. package/targets/macos/main/macos_memory.cpp +31 -0
  92. package/targets/macos/main/macos_native_shell.h +31 -0
  93. package/targets/macos/main/macos_native_shell.mm +396 -0
  94. package/targets/macos/main/macos_network.mm +253 -0
  95. package/targets/macos/main/macos_renderer.h +39 -0
  96. package/targets/macos/main/macos_renderer.mm +1969 -0
  97. package/targets/macos/main/macos_sensors.cpp +148 -0
  98. package/targets/macos/main/macos_smoke_app.cpp +65 -0
  99. package/targets/macos/main/macos_timers.mm +52 -0
  100. package/targets/macos/main/press_bridge.h +21 -0
  101. package/targets/macos/main/press_bridge.mm +72 -0
  102. package/targets/macos/main/thermalright_hid_display.h +14 -0
  103. package/targets/macos/main/thermalright_hid_display.mm +995 -0
  104. package/targets/macos/native-artifact-provenance.mjs +421 -0
  105. package/targets/macos/order-compile-edges.mjs +64 -0
  106. package/targets/macos/preflight-hard-muted-artifact.mjs +93 -0
  107. package/targets/macos/prune-generated-modules.mjs +147 -0
  108. package/targets/macos/sync-resources.mjs +153 -0
  109. package/targets/shared/analyze-audio-capture.mjs +131 -0
  110. package/targets/shared/apple_audio.mm +1194 -0
  111. package/targets/shared/apple_audio_selftest.mm +602 -0
  112. package/targets/shared/apple_audio_testing.h +34 -0
  113. package/targets/shared/build-audio-selftest.sh +50 -0
@@ -0,0 +1,148 @@
1
+ #include "imu.h"
2
+ #include "memory.h"
3
+ #include "power.h"
4
+ #include "touch.h"
5
+
6
+ #include <CoreFoundation/CoreFoundation.h>
7
+ #include <IOKit/ps/IOPSKeys.h>
8
+ #include <IOKit/ps/IOPowerSources.h>
9
+
10
+ #include <cstdint>
11
+
12
+ // macOS doesn't have an IMU; stubs let host/imu.cpp link. Tilt is fixed at 0.
13
+ namespace gea::platform::sensors {
14
+
15
+ void Accelerometer::init() {}
16
+ void Accelerometer::close() {}
17
+ void Accelerometer::calibrateBias() {}
18
+ int Accelerometer::tiltX() { return 0; }
19
+ int Accelerometer::tiltY() { return 0; }
20
+ double Accelerometer::accelerationX() { return 0.0; }
21
+ double Accelerometer::accelerationY() { return 0.0; }
22
+ double Accelerometer::accelerationZ() { return 9.80665; } // gravity, plate flat
23
+ double Accelerometer::gyroscopeX() { return 0.0; }
24
+ double Accelerometer::gyroscopeY() { return 0.0; }
25
+ double Accelerometer::gyroscopeZ() { return 0.0; }
26
+ void Accelerometer::setWebTilt(int, int) {}
27
+
28
+ } // namespace gea::platform::sensors
29
+
30
+ // Memory diagnostics — stub everything to zeros. macOS has plenty of RAM
31
+ // and the diagnostics views just show "0" for the embedded-only metrics.
32
+ namespace gea::platform::memory {
33
+
34
+ std::uint32_t Memory::internalFree() { return 0; }
35
+ std::uint32_t Memory::internalLargestFreeBlock() { return 0; }
36
+ std::uint32_t Memory::internalMinimumFree() { return 0; }
37
+ std::uint32_t Memory::psramFree() { return 0; }
38
+ std::uint32_t Memory::currentTaskStackHighWaterMark() { return 0; }
39
+ std::uint32_t Memory::geaMainStackBytes() { return 0; }
40
+ std::uint32_t Memory::geaInitStackBytes() { return 0; }
41
+ std::uint32_t Memory::appFrameStackWords() { return 0; }
42
+ std::uint32_t Memory::appFrameStackBytes() { return 0; }
43
+ std::uint32_t Memory::displayFlushConfiguredRows() { return 0; }
44
+ std::uint32_t Memory::displayFlushConfiguredDepth() { return 0; }
45
+ std::uint32_t Memory::displayFlushBufferMaxBytes() { return 0; }
46
+ std::uint32_t Memory::displayFlushRows() { return 0; }
47
+ std::uint32_t Memory::displayFlushDepth() { return 0; }
48
+ std::uint32_t Memory::displayFlushBufferBytes() { return 0; }
49
+
50
+ // No internal/external split here, so there is nothing to hold back for the
51
+ // display; the caller treats nullptr as "no reserve" and carries on.
52
+ void *Memory::reserveInternalDma(std::size_t) { return nullptr; }
53
+ void Memory::releaseInternalDma(void *) {}
54
+ } // namespace gea::platform::memory
55
+
56
+ // Touch is driven by AppKit mouse events (GeaCanvasView dispatches them as
57
+ // touch events, mirroring the iOS renderer's gea_ios_touch_set_state flow).
58
+ // The mouse handler keeps this cache current so the frame loop's Move
59
+ // dispatch — which re-reads coordinates via consumeLatestMove — and
60
+ // immediate-mode apps polling read()/readCached() see the real pointer.
61
+ // Coordinates are PANEL-NATIVE, matching the hardware touch controllers
62
+ // (TouchRuntime::transformTouchToLogical maps them back to logical space).
63
+ namespace gea::platform::touch {
64
+
65
+ namespace {
66
+ bool g_touching = false;
67
+ int g_touch_x = 0;
68
+ int g_touch_y = 0;
69
+ } // namespace
70
+
71
+ extern "C" void gea_macos_touch_set_state(int touching, int x, int y)
72
+ {
73
+ g_touching = touching != 0;
74
+ g_touch_x = x;
75
+ g_touch_y = y;
76
+ }
77
+
78
+ void Touchscreen::setObserver(Observer) {}
79
+ bool Touchscreen::init() { return true; }
80
+ int Touchscreen::read(int *x, int *y)
81
+ {
82
+ if (x) *x = g_touch_x;
83
+ if (y) *y = g_touch_y;
84
+ return g_touching ? 1 : 0;
85
+ }
86
+ int Touchscreen::readCached(int *x, int *y)
87
+ {
88
+ if (x) *x = g_touch_x;
89
+ if (y) *y = g_touch_y;
90
+ return g_touching ? 1 : 0;
91
+ }
92
+ void Touchscreen::consumeLatestMove(int *x, int *y)
93
+ {
94
+ if (x) *x = g_touch_x;
95
+ if (y) *y = g_touch_y;
96
+ }
97
+
98
+ } // namespace gea::platform::touch
99
+
100
+ // Battery. `gea::platform::power::Power` had no macOS implementation at all,
101
+ // so `host/battery.h`'s inline `batteryPercent()` left an undefined symbol and
102
+ // every app that shows a battery level failed to LINK (`watch`, `watch-date`:
103
+ // "gea::platform::power::Power::batteryPercent()", referenced from ...).
104
+ //
105
+ // A stub returning a constant would link and lie. macOS publishes the real
106
+ // figure through IOKit's power-sources API, and the target already links
107
+ // -framework IOKit (targets/macos/build-macos.sh LINK_FRAMEWORKS), so the
108
+ // honest implementation costs nothing the build was not already paying.
109
+ // A desktop with no battery reports 100: "not running on battery" is the
110
+ // truthful answer there, and it is what the embedded API's callers expect
111
+ // when the device is on external power.
112
+ namespace gea::platform::power {
113
+
114
+ bool Power::init() { return true; }
115
+
116
+ int Power::batteryPercent()
117
+ {
118
+ CFTypeRef blob = IOPSCopyPowerSourcesInfo();
119
+ if (blob == nullptr) return 100;
120
+ CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
121
+ if (sources == nullptr) {
122
+ CFRelease(blob);
123
+ return 100;
124
+ }
125
+ int percent = 100;
126
+ const CFIndex count = CFArrayGetCount(sources);
127
+ for (CFIndex i = 0; i < count; ++i) {
128
+ CFDictionaryRef description = IOPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i));
129
+ if (description == nullptr) continue;
130
+ CFNumberRef current = static_cast<CFNumberRef>(CFDictionaryGetValue(description, CFSTR(kIOPSCurrentCapacityKey)));
131
+ CFNumberRef maximum = static_cast<CFNumberRef>(CFDictionaryGetValue(description, CFSTR(kIOPSMaxCapacityKey)));
132
+ int currentValue = 0;
133
+ int maximumValue = 0;
134
+ if (current == nullptr || maximum == nullptr) continue;
135
+ if (!CFNumberGetValue(current, kCFNumberIntType, &currentValue)) continue;
136
+ if (!CFNumberGetValue(maximum, kCFNumberIntType, &maximumValue)) continue;
137
+ if (maximumValue <= 0) continue;
138
+ percent = static_cast<int>((static_cast<double>(currentValue) / maximumValue) * 100.0 + 0.5);
139
+ break;
140
+ }
141
+ CFRelease(sources);
142
+ CFRelease(blob);
143
+ if (percent < 0) return 0;
144
+ if (percent > 100) return 100;
145
+ return percent;
146
+ }
147
+
148
+ } // namespace gea::platform::power
@@ -0,0 +1,65 @@
1
+ // Phase B smoke app: exercises View / Text / Button / event dispatch
2
+ // without the JSX → C++ pipeline. Real apps generated by geatsc will
3
+ // drop into targets/macos/generated/<app>/ and supersede this.
4
+
5
+ #include "ui/document.h"
6
+ #include "events.h"
7
+ #include <cstdio>
8
+
9
+ namespace {
10
+ gea::embedded::ui::TextElement g_counterLabel;
11
+ int g_counterValue = 0;
12
+
13
+ void refreshCounterLabel()
14
+ {
15
+ char buf[32];
16
+ std::snprintf(buf, sizeof(buf), "Clicked %d", g_counterValue);
17
+ g_counterLabel.setText(buf);
18
+ }
19
+ } // namespace
20
+
21
+ extern "C" {
22
+
23
+ void gea_embedded_app_init(int width, int height)
24
+ {
25
+ using namespace gea::embedded::ui;
26
+ using gea::framework::events::PointerEvent;
27
+
28
+ auto &doc = Document::instance();
29
+ doc.clear();
30
+ auto root = doc.createView();
31
+ root.style().backgroundColor(0x33DE); // RGB565 ~ #3478F6
32
+ root.style().set(Property::FlexDirection, 0); // column
33
+ root.style().set(Property::JustifyContent, 1); // center
34
+ root.style().set(Property::AlignItems, 1); // center
35
+ root.style().set(Property::Gap, 16);
36
+
37
+ auto title = doc.createText("Hello, native Mac!");
38
+ title.style().color(0xFFFF); // white
39
+ title.style().set(Property::FontSize, 24);
40
+ root.appendChild(title);
41
+
42
+ g_counterLabel = doc.createText("Clicked 0");
43
+ g_counterLabel.style().color(0xFFFF);
44
+ g_counterLabel.style().set(Property::FontSize, 16);
45
+ root.appendChild(g_counterLabel);
46
+ g_counterValue = 0;
47
+
48
+ auto button = doc.createButton();
49
+ auto buttonLabel = doc.createText("Click me");
50
+ button.appendChild(buttonLabel);
51
+ button.addEventListener("click", [](PointerEvent &) {
52
+ g_counterValue++;
53
+ refreshCounterLabel();
54
+ });
55
+ root.appendChild(button);
56
+
57
+ doc.mount(root, width, height);
58
+ }
59
+
60
+ void gea_embedded_app_frame(int timestampMs)
61
+ {
62
+ (void)timestampMs;
63
+ }
64
+
65
+ } // extern "C"
@@ -0,0 +1,52 @@
1
+ #import <Foundation/Foundation.h>
2
+ #include "services/frame_scheduler.h"
3
+
4
+ #include <mach/mach_time.h>
5
+
6
+ namespace {
7
+
8
+ int monotonicMillis()
9
+ {
10
+ static mach_timebase_info_data_t tb = {0, 0};
11
+ if (tb.denom == 0) mach_timebase_info(&tb);
12
+ static const uint64_t start = mach_absolute_time();
13
+ uint64_t ns = (mach_absolute_time() - start) * tb.numer / tb.denom;
14
+ return static_cast<int>(ns / 1000000ULL);
15
+ }
16
+
17
+ int g_frame_interval_ms = gea::framework::services::FrameScheduler::kDefaultFrameIntervalMs;
18
+
19
+ } // namespace
20
+
21
+ extern "C" int gea_embedded_now_ms(void)
22
+ {
23
+ return monotonicMillis();
24
+ }
25
+
26
+ namespace gea::framework::services {
27
+
28
+ EventQueue FrameScheduler::createEventQueue() { return EventQueue{}; }
29
+ EventQueue FrameScheduler::eventQueue() { return EventQueue{}; }
30
+ bool FrameScheduler::sendEvent(const gea::framework::events::Event &, int) { return true; }
31
+ bool FrameScheduler::receiveEvent(gea::framework::events::Event *) { return false; }
32
+ void FrameScheduler::start(EventQueue) {}
33
+ void FrameScheduler::runFrame(const FrameCallbacks &callbacks)
34
+ {
35
+ if (callbacks.frame) callbacks.frame(monotonicMillis(), callbacks.context);
36
+ }
37
+ void FrameScheduler::setFrameIntervalMs(int intervalMs)
38
+ {
39
+ if (intervalMs < kMinFrameIntervalMs) intervalMs = kMinFrameIntervalMs;
40
+ if (intervalMs > kMaxFrameIntervalMs) intervalMs = kMaxFrameIntervalMs;
41
+ g_frame_interval_ms = intervalMs;
42
+ }
43
+ int FrameScheduler::frameIntervalMs() { return g_frame_interval_ms; }
44
+ void FrameScheduler::setFrameRate(double fps)
45
+ {
46
+ if (fps <= 0.0) return;
47
+ setFrameIntervalMs(static_cast<int>(1000.0 / fps + 0.5));
48
+ }
49
+ double FrameScheduler::frameRate() { return 1000.0 / static_cast<double>(g_frame_interval_ms); }
50
+ int FrameScheduler::nowMs() { return monotonicMillis(); }
51
+
52
+ } // namespace gea::framework::services
@@ -0,0 +1,21 @@
1
+ #pragma once
2
+
3
+ #ifdef __OBJC__
4
+ #import <Foundation/Foundation.h>
5
+
6
+ @interface PressBridge : NSObject
7
+ @property(nonatomic, assign) int nodeId;
8
+ - (void)fire:(id)sender;
9
+ @end
10
+ #endif
11
+
12
+ #ifdef __cplusplus
13
+ extern "C" {
14
+ #endif
15
+
16
+ // Dispatches a Click + Press event to the given node id via Tree::dispatchEvent.
17
+ void gea_macos_fire_press_for_node(int nodeId);
18
+
19
+ #ifdef __cplusplus
20
+ }
21
+ #endif
@@ -0,0 +1,72 @@
1
+ #import "press_bridge.h"
2
+
3
+ #include "ui/tree_internal.h"
4
+ #include "events.h"
5
+
6
+ #include <cstring>
7
+
8
+ extern "C" void gea_macos_fire_press_for_node(int nodeId)
9
+ {
10
+ using gea::framework::events::PointerEvent;
11
+ using gea::framework::events::PointerEventType;
12
+ if (nodeId < 0) return;
13
+ auto &tree = gea::embedded::ui::Tree::instance();
14
+ if (nodeId >= tree.nodeCount()) return;
15
+
16
+ // A native click on macOS corresponds to a full press-and-release cycle.
17
+ // Apps may listen for any of these — the browser equivalent fires the
18
+ // whole sequence too — so dispatch them in browser order:
19
+ // touchstart → touchend → click
20
+ // This way apps written for the ESP32 touchscreen (which only sees
21
+ // touchstart/touchend) still respond to mouse clicks, and JSX onClick
22
+ // handlers fire consistently with the web target.
23
+ auto fire = [&](PointerEventType type) {
24
+ PointerEvent ev;
25
+ ev.type = type;
26
+ ev.targetId = nodeId;
27
+ tree.dispatchEvent(ev);
28
+ };
29
+ fire(PointerEventType::TouchStart);
30
+ fire(PointerEventType::TouchEnd);
31
+ fire(PointerEventType::Click);
32
+ }
33
+
34
+ // Headless equivalent of a keystroke into the first `<input>` / `<textarea>`:
35
+ // write the text into the node's `value` attribute and dispatch
36
+ // `PointerEventType::Input`, which is exactly what `GeaTextAreaView
37
+ // textDidChange:` / `GeaTextFieldView controlTextDidChange:` do for a real key
38
+ // event (macos_renderer.mm). Driven by GEA_MACOS_SYNTH_INPUT so the text-input
39
+ // path can be exercised in a shell with no Accessibility permission — posting
40
+ // synthetic key events through CGEvent needs one, so without this there is no
41
+ // way to regression-test "typing does not crash" from a script.
42
+ // Returns the node it targeted, or -1 when the tree has no text input.
43
+ extern "C" int gea_macos_fire_input_for_node(int nodeId, const char *text)
44
+ {
45
+ using gea::framework::events::PointerEvent;
46
+ using gea::framework::events::PointerEventType;
47
+ auto &tree = gea::embedded::ui::Tree::instance();
48
+ int target = nodeId;
49
+ if (target < 0) {
50
+ for (int i = 0; i < tree.nodeCount(); i++) {
51
+ const char *tag = tree.tagName(i);
52
+ if (!tag) continue;
53
+ if (std::strcmp(tag, "input") == 0 || std::strcmp(tag, "textarea") == 0) { target = i; break; }
54
+ }
55
+ }
56
+ if (target < 0 || target >= tree.nodeCount()) return -1;
57
+ tree.setAttribute(target, "value", text ? text : "");
58
+ PointerEvent ev;
59
+ ev.type = PointerEventType::Input;
60
+ ev.targetId = target;
61
+ ev.keyCode = 0;
62
+ tree.dispatchEvent(ev);
63
+ return target;
64
+ }
65
+
66
+ @implementation PressBridge
67
+ - (void)fire:(id)sender
68
+ {
69
+ (void)sender;
70
+ gea_macos_fire_press_for_node(self.nodeId);
71
+ }
72
+ @end
@@ -0,0 +1,14 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+
5
+ namespace gea::macos::thermalright {
6
+
7
+ bool enabled();
8
+ int width();
9
+ int height();
10
+ int fps();
11
+ bool submitRgb565(const std::uint16_t *pixels, int width, int height);
12
+ void shutdown();
13
+
14
+ } // namespace gea::macos::thermalright