@geastack/apple 0.2.8 → 0.2.9
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/package.json +9 -9
- package/targets/ios/README.md +19 -4
- package/targets/ios/build-ios.sh +72 -56
- package/targets/ios/generate-xcode-project.mjs +11 -30
- package/targets/ios/main/ios_main.mm +1 -95
- package/targets/ios/generate-resident-entry.mjs +0 -67
- package/targets/ios/generate-resident-registry.mjs +0 -162
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geastack/apple",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Generated Apple SDK bindings plus the macOS and iOS native build targets for Gea apps.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -102,14 +102,14 @@
|
|
|
102
102
|
"access": "public"
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
|
-
"@geastack/compiler": "^1.0.
|
|
106
|
-
"@geastack/core": "^0.1.
|
|
107
|
-
"@geastack/elements": "^0.1.
|
|
108
|
-
"@geastack/engine": "^0.1.
|
|
109
|
-
"@geastack/geaos": "^0.1.
|
|
110
|
-
"@geastack/geatsc-plugin-apple-native": "^0.1.
|
|
111
|
-
"@geastack/geatsc-plugin-gea": "^0.1.
|
|
112
|
-
"@geastack/host": "^0.1.
|
|
105
|
+
"@geastack/compiler": "^1.0.18",
|
|
106
|
+
"@geastack/core": "^0.1.23",
|
|
107
|
+
"@geastack/elements": "^0.1.2",
|
|
108
|
+
"@geastack/engine": "^0.1.5",
|
|
109
|
+
"@geastack/geaos": "^0.1.3",
|
|
110
|
+
"@geastack/geatsc-plugin-apple-native": "^0.1.3",
|
|
111
|
+
"@geastack/geatsc-plugin-gea": "^0.1.6",
|
|
112
|
+
"@geastack/host": "^0.1.8"
|
|
113
113
|
},
|
|
114
114
|
"scripts": {
|
|
115
115
|
"prepublishOnly": "npm run build",
|
package/targets/ios/README.md
CHANGED
|
@@ -2,12 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
Build a gea-embedded JSX app as a native UIKit app.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
From an app that depends on `@geastack/apple` (every iOS example does, and
|
|
6
|
+
`gea create --targets ios` adds it), the CLI drives this target:
|
|
6
7
|
|
|
7
8
|
```bash
|
|
8
|
-
|
|
9
|
+
npx gea build --target ios # simulator .app, no launch
|
|
10
|
+
npx gea build --target ios --mode device # unsigned iphoneos .app
|
|
11
|
+
npx gea run --target ios # build, install and launch on a simulator
|
|
12
|
+
npx gea run --target ios --mode device # build, sign, install and launch on an iPhone
|
|
9
13
|
```
|
|
10
14
|
|
|
15
|
+
The same script can be run directly from the app folder; the CLI passes the
|
|
16
|
+
app id and destination through unchanged:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
node_modules/@geastack/apple/targets/ios/build-ios.sh <app-id> simulator
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The script resolves `@geastack/core`, `@geastack/compiler`, the apple-native
|
|
23
|
+
geatsc plugin and `@geastack/cli` by walking up `node_modules` from the app
|
|
24
|
+
folder, so it works on a hoisted npm install and on a linked checkout alike.
|
|
25
|
+
|
|
11
26
|
The simulator path auto-picks an available iPhone simulator. Set
|
|
12
27
|
`GEA_IOS_SIMULATOR_UDID` to force a specific device. By default, the script
|
|
13
28
|
also opens Simulator.app for the selected device; set
|
|
@@ -18,7 +33,7 @@ team when it can find one. You can also set your Apple development team
|
|
|
18
33
|
explicitly:
|
|
19
34
|
|
|
20
35
|
```bash
|
|
21
|
-
GEA_IOS_DEVELOPMENT_TEAM=ABCDE12345
|
|
36
|
+
GEA_IOS_DEVELOPMENT_TEAM=ABCDE12345 npx gea run --target ios --mode device
|
|
22
37
|
```
|
|
23
38
|
|
|
24
39
|
To see the automatically detected team id:
|
|
@@ -37,7 +52,7 @@ To only verify that the app compiles for the iPhone device SDK, skip launch
|
|
|
37
52
|
without a development team:
|
|
38
53
|
|
|
39
54
|
```bash
|
|
40
|
-
|
|
55
|
+
npx gea build --target ios --mode device
|
|
41
56
|
```
|
|
42
57
|
|
|
43
58
|
The Xcode project is generated under
|
package/targets/ios/build-ios.sh
CHANGED
|
@@ -4,32 +4,84 @@ set -euo pipefail
|
|
|
4
4
|
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
5
5
|
IOS_DIR="$ROOT_DIR/targets/ios"
|
|
6
6
|
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
# The project is the directory this script was started in -- `gea build
|
|
8
|
+
# --target ios` spawns it with the app's own folder as cwd, and a direct run is
|
|
9
|
+
# made from the app folder. Captured once, before anything can move. Every
|
|
10
|
+
# nested `gea` call inherits the same cwd and resolves the same project, so
|
|
11
|
+
# none carry --project.
|
|
12
|
+
BUILD_INVOCATION_CWD="$(pwd -P)"
|
|
13
|
+
|
|
14
|
+
# Resolve the gea framework through npm plus the shared manifest, the same way
|
|
15
|
+
# build-macos.sh does. `apple` is a native npm package whose @geastack/* deps
|
|
16
|
+
# npm HOISTS to the app's node_modules, one or more levels above this package,
|
|
17
|
+
# while a linked checkout has them under its own. Looking one level below this
|
|
18
|
+
# package -- what this script did before -- finds nothing in either installed
|
|
19
|
+
# layout, so walk the node_modules chain from the app first, then from here.
|
|
20
|
+
resolve_gea_package_from() {
|
|
21
|
+
node -e '
|
|
22
|
+
const fs = require("node:fs")
|
|
23
|
+
const path = require("node:path")
|
|
24
|
+
let dir = process.argv[1]
|
|
25
|
+
while (true) {
|
|
26
|
+
const candidate = path.join(dir, "node_modules", process.argv[2])
|
|
27
|
+
if (fs.existsSync(path.join(candidate, "package.json"))) {
|
|
28
|
+
process.stdout.write(fs.realpathSync(candidate))
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
const parent = path.dirname(dir)
|
|
32
|
+
if (parent === dir) break
|
|
33
|
+
dir = parent
|
|
34
|
+
}
|
|
35
|
+
' "$1" "$2" 2>/dev/null || true
|
|
36
|
+
}
|
|
37
|
+
resolve_gea_package() {
|
|
38
|
+
local start found
|
|
39
|
+
for start in "${2:-$BUILD_INVOCATION_CWD}" "${2:-$ROOT_DIR}"; do
|
|
40
|
+
found="$(resolve_gea_package_from "$start" "$1")"
|
|
41
|
+
if [[ -n "$found" ]]; then
|
|
42
|
+
printf '%s' "$found"
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
}
|
|
47
|
+
GEA_CORE="$(resolve_gea_package @geastack/core)"
|
|
48
|
+
[ -n "$GEA_CORE" ] && [ -f "$GEA_CORE/package.json" ] || { echo "Cannot resolve @geastack/core from $BUILD_INVOCATION_CWD — add @geastack/apple to the app's dependencies and run 'npm install' there" >&2; exit 1; }
|
|
49
|
+
GEA_COMPILER="$(resolve_gea_package @geastack/compiler)"
|
|
50
|
+
[ -n "$GEA_COMPILER" ] && [ -f "$GEA_COMPILER/package.json" ] || { echo "Cannot resolve @geastack/compiler from $BUILD_INVOCATION_CWD — add @geastack/apple to the app's dependencies and run 'npm install' there" >&2; exit 1; }
|
|
51
|
+
# An app that installs @geastack/apple gets the plugin from node_modules; inside
|
|
52
|
+
# this repository it is a sibling package that nothing links, so name it there.
|
|
53
|
+
GEA_APPLE_NATIVE_PLUGIN="$(resolve_gea_package @geastack/geatsc-plugin-apple-native)"
|
|
54
|
+
if [[ -z "$GEA_APPLE_NATIVE_PLUGIN" && -d "$ROOT_DIR/../geatsc-plugin-apple-native" ]]; then
|
|
55
|
+
GEA_APPLE_NATIVE_PLUGIN="$(cd "$ROOT_DIR/../geatsc-plugin-apple-native" && pwd)"
|
|
56
|
+
fi
|
|
57
|
+
[ -n "$GEA_APPLE_NATIVE_PLUGIN" ] && [ -f "$GEA_APPLE_NATIVE_PLUGIN/dist/index.js" ] || { echo "Cannot resolve @geastack/geatsc-plugin-apple-native from $BUILD_INVOCATION_CWD" >&2; exit 1; }
|
|
12
58
|
GEA_HOST_DIR="${GEA_HOST_DIR:-$GEA_CORE/../host}"
|
|
13
59
|
GEA_ENGINE_DIR="${GEA_ENGINE_DIR:-$GEA_CORE/../engine}"
|
|
14
60
|
GEA_ELEMENTS_DIR="${GEA_ELEMENTS_DIR:-$GEA_CORE/../elements}"
|
|
15
61
|
GEA_GEAOS_PACKAGE_DIR="${GEA_GEAOS_PACKAGE_DIR:-$GEA_CORE/../geaos}"
|
|
16
|
-
# The
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
|
|
62
|
+
# The source manifest reads these from the ENVIRONMENT: gea_sources.sh is a
|
|
63
|
+
# front end for gea_sources.mjs, which runs as a child process. A plain shell
|
|
64
|
+
# variable never reaches it and it reports "<name> unset" while the include
|
|
65
|
+
# roots come back empty.
|
|
66
|
+
export GEA_CORE GEA_HOST_DIR GEA_ENGINE_DIR GEA_ELEMENTS_DIR GEA_GEAOS_PACKAGE_DIR
|
|
21
67
|
# This script IS @geastack/apple, so the generator must bind against this
|
|
22
68
|
# working copy rather than whatever installed copy it would resolve from the app.
|
|
23
69
|
export GEA_APPLE_ROOT="$ROOT_DIR"
|
|
24
|
-
|
|
25
|
-
|
|
70
|
+
# Prefer an explicit override, then the package the app installed, then gea on PATH.
|
|
71
|
+
GEA_CLI="${GEA_CLI_BIN:-}"
|
|
72
|
+
if [[ -z "$GEA_CLI" ]]; then
|
|
73
|
+
GEA_CLI="$(node -e 'process.stdout.write(require("path").join(process.argv[1], "bin", "gea.mjs"))' "$(resolve_gea_package @geastack/cli)" 2>/dev/null || true)"
|
|
74
|
+
if [[ ! -f "$GEA_CLI" ]]; then
|
|
75
|
+
GEA_CLI="$(command -v gea || true)"
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
[ -n "$GEA_CLI" ] && [ -f "$GEA_CLI" ] || { echo "Cannot locate GeaStack CLI — set GEA_CLI_BIN to gea.mjs, install @geastack/cli locally, or add gea to PATH" >&2; exit 1; }
|
|
26
79
|
|
|
27
80
|
# Framework sources/includes from the shared manifest (iOS keeps camera — ios_camera.mm
|
|
28
|
-
# provides it — but has no
|
|
29
|
-
#
|
|
81
|
+
# provides it — but has no OTA/diagnostics services or single-app runtime
|
|
82
|
+
# shell, so exclude those). generate-xcode-project.mjs consumes these.
|
|
30
83
|
# shellcheck source=/dev/null
|
|
31
84
|
source "$GEA_CORE/gea_sources.sh"
|
|
32
|
-
export GEA_CORE
|
|
33
85
|
export GEA_FW_CXX_SOURCES="$(gea_fw_cxx_sources | grep -vE "/(runtime|services/[a-z_]+)\.cpp\$")"
|
|
34
86
|
export GEA_FW_C_SOURCES="$(gea_fw_c_sources)"
|
|
35
87
|
export GEA_FW_INCLUDE_DIRS="$(gea_fw_include_flags | sed "s/^-I//")"
|
|
@@ -83,7 +135,6 @@ build_font_args=(
|
|
|
83
135
|
generate_app() {
|
|
84
136
|
local app_id="$1"
|
|
85
137
|
local out_dir="$2"
|
|
86
|
-
local prefix="${3:-}"
|
|
87
138
|
local info
|
|
88
139
|
local root
|
|
89
140
|
local entry
|
|
@@ -91,7 +142,7 @@ generate_app() {
|
|
|
91
142
|
info="$(node "$GEA_CLI" apps inspect "$app_id" --format shell)" || return 1
|
|
92
143
|
IFS=$'\t' read -r root entry runtime _name <<< "$info"
|
|
93
144
|
if [[ "$runtime" != "gea" ]]; then
|
|
94
|
-
echo "
|
|
145
|
+
echo "iOS target only supports runtime=gea apps: $app_id is runtime=$runtime" >&2
|
|
95
146
|
return 1
|
|
96
147
|
fi
|
|
97
148
|
local args=(
|
|
@@ -103,10 +154,9 @@ generate_app() {
|
|
|
103
154
|
# function no iOS target defines. `build-macos.sh` passes `macos` for the
|
|
104
155
|
# same reason; iOS was simply never given its half.
|
|
105
156
|
--apple-platform ios
|
|
106
|
-
# The plugin resolves
|
|
107
|
-
#
|
|
108
|
-
|
|
109
|
-
--geatsc-apple-native-plugin "$ROOT_DIR/packages/geatsc-plugin-apple-native/dist/index.js"
|
|
157
|
+
# The plugin is resolved above the way build-macos.sh resolves it: from the
|
|
158
|
+
# app's node_modules, or the sibling package inside this repository.
|
|
159
|
+
--geatsc-apple-native-plugin "$GEA_APPLE_NATIVE_PLUGIN/dist/index.js"
|
|
110
160
|
--app-dir "$root"
|
|
111
161
|
--entry "$entry"
|
|
112
162
|
--out-dir "$out_dir"
|
|
@@ -116,14 +166,6 @@ generate_app() {
|
|
|
116
166
|
if [[ -f "$native_plugin" ]]; then
|
|
117
167
|
args+=(--extra-geatsc-plugin "$native_plugin")
|
|
118
168
|
fi
|
|
119
|
-
if [[ -n "$prefix" ]]; then
|
|
120
|
-
args+=(
|
|
121
|
-
--entry-symbol "${prefix}_top_level"
|
|
122
|
-
--cpp-prelude-symbol "${prefix}_register_styles"
|
|
123
|
-
--font-symbol-prefix "$prefix"
|
|
124
|
-
--isolate-symbols
|
|
125
|
-
)
|
|
126
|
-
fi
|
|
127
169
|
node "$GEA_CORE/scripts/build-gea-vite-geatsc.mjs" "${args[@]}"
|
|
128
170
|
}
|
|
129
171
|
|
|
@@ -214,33 +256,7 @@ pick_ios_device() {
|
|
|
214
256
|
rm -f "$output_json"
|
|
215
257
|
}
|
|
216
258
|
|
|
217
|
-
|
|
218
|
-
if [[ "$APP_ID" == "app-launcher" && "${GEA_IOS_RESIDENT_APPS:-auto}" != "none" ]]; then
|
|
219
|
-
if [[ -n "${GEA_IOS_RESIDENT_APPS:-}" && "${GEA_IOS_RESIDENT_APPS:-}" != "auto" ]]; then
|
|
220
|
-
read -r -a RESIDENT_IDS <<< "${GEA_IOS_RESIDENT_APPS//,/ }"
|
|
221
|
-
else
|
|
222
|
-
mapfile -t RESIDENT_IDS < <(
|
|
223
|
-
node "$GEA_CLI" apps list --target esp32 | grep -vx 'direct-psram-balls' || true
|
|
224
|
-
)
|
|
225
|
-
fi
|
|
226
|
-
fi
|
|
227
|
-
|
|
228
|
-
if [[ ${#RESIDENT_IDS[@]} -eq 0 ]]; then
|
|
229
|
-
generate_app "$APP_ID" "$GENERATED_DIR" ""
|
|
230
|
-
else
|
|
231
|
-
ACTUAL_RESIDENTS=()
|
|
232
|
-
for id in "${RESIDENT_IDS[@]}"; do
|
|
233
|
-
safe="${id//[^A-Za-z0-9_]/_}"
|
|
234
|
-
prefix="gea_resident_${safe}"
|
|
235
|
-
resident_dir="$GENERATED_DIR/residents/$id"
|
|
236
|
-
mkdir -p "$resident_dir"
|
|
237
|
-
generate_app "$id" "$resident_dir" "$prefix" || continue
|
|
238
|
-
node "$IOS_DIR/generate-resident-entry.mjs" "$prefix" "$resident_dir/entry.cpp"
|
|
239
|
-
ACTUAL_RESIDENTS+=("$id")
|
|
240
|
-
done
|
|
241
|
-
RESIDENT_IDS=("${ACTUAL_RESIDENTS[@]}")
|
|
242
|
-
node "$IOS_DIR/generate-resident-registry.mjs" "$GENERATED_DIR/resident_registry.cpp" "$APP_ID" "${RESIDENT_IDS[@]}"
|
|
243
|
-
fi
|
|
259
|
+
generate_app "$APP_ID" "$GENERATED_DIR"
|
|
244
260
|
|
|
245
261
|
if [[ ! -f "$GENERATED_DIR/gea_runtime.cpp" ]]; then
|
|
246
262
|
echo "#include \"$GEA_COMPILER/dist/targets/cpp/runtime/runtime.cpp\"" > "$GENERATED_DIR/gea_runtime.cpp"
|
|
@@ -40,6 +40,10 @@ if (!appId || !appName || !bundleId || !generatedDir || !projectPath) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const iosDir = scriptDir // apple/targets/ios — this script's own directory, not the apps repo
|
|
43
|
+
// The framework packages are wherever build-ios.sh resolved them (the app's
|
|
44
|
+
// hoisted node_modules, or a linked checkout); it exports the roots it found.
|
|
45
|
+
const geaCore = process.env.GEA_CORE || ''
|
|
46
|
+
if (!geaCore) fail('GEA_CORE is not set: run this generator through build-ios.sh, which resolves @geastack/core for it.')
|
|
43
47
|
const plistOut = path.join(projectPath, 'Info.plist')
|
|
44
48
|
let appMeta
|
|
45
49
|
try {
|
|
@@ -140,25 +144,6 @@ function findFontResources() {
|
|
|
140
144
|
.sort()
|
|
141
145
|
}
|
|
142
146
|
|
|
143
|
-
function findResidentSources() {
|
|
144
|
-
const residentsDir = path.join(generatedDir, 'residents')
|
|
145
|
-
if (!fs.existsSync(residentsDir)) return []
|
|
146
|
-
return fs.readdirSync(residentsDir, { withFileTypes: true })
|
|
147
|
-
.filter((entry) => entry.isDirectory())
|
|
148
|
-
.flatMap((entry) => {
|
|
149
|
-
const dir = path.join(residentsDir, entry.name)
|
|
150
|
-
return [
|
|
151
|
-
...readGeatscSources(dir),
|
|
152
|
-
source(path.join(dir, 'entry.cpp')),
|
|
153
|
-
source(path.join(dir, 'gea_embedded_font_generated.cpp')),
|
|
154
|
-
source(path.join(dir, 'gea_embedded_assets_generated.cpp')),
|
|
155
|
-
].filter(existing)
|
|
156
|
-
})
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const residentRegistry = source(path.join(generatedDir, 'resident_registry.cpp'))
|
|
160
|
-
const hasResidentRegistry = existing(residentRegistry)
|
|
161
|
-
const residentSources = hasResidentRegistry ? [residentRegistry, ...findResidentSources()] : []
|
|
162
147
|
const appleNativeBridgeSource = source(path.join(generatedDir, 'gea/apple/native_bridge.mm'), 'sourcecode.cpp.objcpp')
|
|
163
148
|
const generatedProgramSources = readGeatscSources(
|
|
164
149
|
generatedDir,
|
|
@@ -194,25 +179,21 @@ const sources = [
|
|
|
194
179
|
...appNativeSources,
|
|
195
180
|
// Framework C/C++ sources come from @geastack/core/gea_sources.sh,
|
|
196
181
|
// passed by build-ios.sh via env (iOS-curated: camera kept since ios_camera.mm
|
|
197
|
-
// provides it;
|
|
182
|
+
// provides it; OTA/diagnostics services + the single-app runtime
|
|
198
183
|
// shell excluded — iOS uses its own UIKit run loop). Single source of truth.
|
|
199
184
|
...(process.env.GEA_FW_C_SOURCES || '').split('\n').filter(Boolean).map((f) => source(f, 'sourcecode.c.c')),
|
|
200
185
|
...(process.env.GEA_FW_CXX_SOURCES || '').split('\n').filter(Boolean).map((f) => source(f)),
|
|
201
|
-
// gea_app_entry /
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
source(path.join(geaCore, 'gea_app_entry.cpp')),
|
|
206
|
-
source(path.join(geaCore, '../geaos/resident_apps.cpp')),
|
|
207
|
-
]),
|
|
208
|
-
...(hasResidentRegistry ? residentSources : generatedProgramSources),
|
|
186
|
+
// gea_app_entry.cpp provides Application::init/frame, which calls the one
|
|
187
|
+
// __gea_top_level geatsc emitted (deliberately not in the manifest).
|
|
188
|
+
source(path.join(geaCore, 'gea_app_entry.cpp')),
|
|
189
|
+
...generatedProgramSources,
|
|
209
190
|
appleNativeBridgeSource,
|
|
210
191
|
].filter(existing)
|
|
211
192
|
|
|
212
193
|
const fontGenerated = source(path.join(generatedDir, 'gea_embedded_font_generated.cpp'))
|
|
213
|
-
if (
|
|
194
|
+
if (existing(fontGenerated)) sources.push(fontGenerated)
|
|
214
195
|
const assetsGenerated = source(path.join(generatedDir, 'gea_embedded_assets_generated.cpp'))
|
|
215
|
-
if (
|
|
196
|
+
if (existing(assetsGenerated)) sources.push(assetsGenerated)
|
|
216
197
|
const hasGeneratedFonts = sources.some((entry) => path.basename(entry.file) === 'gea_embedded_font_generated.cpp')
|
|
217
198
|
|
|
218
199
|
const fontResources = findFontResources().map((file) => resource(file))
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
#include "font_registry.h"
|
|
11
11
|
#include "image.h"
|
|
12
12
|
#include "ios_renderer.h"
|
|
13
|
-
#include "resident_apps.h"
|
|
14
13
|
#include "ios_root_background.h"
|
|
15
14
|
#include "pixel.h"
|
|
16
15
|
#include "ui/tree_internal.h"
|
|
@@ -60,19 +59,6 @@ NSString *NSStringFromAttr(const char *value)
|
|
|
60
59
|
return [NSString stringWithUTF8String:value ? value : ""] ?: @"";
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
void queueInitialResidentAppFromProcessArguments()
|
|
64
|
-
{
|
|
65
|
-
if (!gea::framework::apps::ResidentApps::isEnabled()) return;
|
|
66
|
-
NSArray<NSString *> *arguments = NSProcessInfo.processInfo.arguments;
|
|
67
|
-
for (NSUInteger i = 0; i + 1 < arguments.count; ++i) {
|
|
68
|
-
if (![arguments[i] isEqualToString:@"--gea-initial-app"]) continue;
|
|
69
|
-
NSString *appId = arguments[i + 1];
|
|
70
|
-
if (appId.length > 0) gea::framework::apps::ResidentApps::requestLaunch(appId.UTF8String);
|
|
71
|
-
}
|
|
72
|
-
const char *envAppId = std::getenv("GEA_IOS_INITIAL_APP");
|
|
73
|
-
if (envAppId && envAppId[0]) gea::framework::apps::ResidentApps::requestLaunch(envAppId);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
62
|
NSTextAlignment textAlignmentForStyle(int align)
|
|
77
63
|
{
|
|
78
64
|
switch (align) {
|
|
@@ -567,49 +553,12 @@ bool attributedStringHasTextDecoration(NSAttributedString *value)
|
|
|
567
553
|
@property(nonatomic, strong) UIView *rootView;
|
|
568
554
|
@property(nonatomic, strong) GeaDisplayView *displayView;
|
|
569
555
|
@property(nonatomic, strong) UIView *nativeRootView;
|
|
570
|
-
@property(nonatomic, strong) UIButton *launcherButton;
|
|
571
556
|
@property(nonatomic, strong) CADisplayLink *displayLink;
|
|
572
557
|
- (void)installNativeRootView:(UIView *)view;
|
|
573
558
|
@end
|
|
574
559
|
|
|
575
560
|
@implementation GeaAppDelegate
|
|
576
561
|
|
|
577
|
-
- (BOOL)shouldShowLauncherButton
|
|
578
|
-
{
|
|
579
|
-
if (!gea::framework::apps::ResidentApps::isEnabled()) return NO;
|
|
580
|
-
const char *activeId = gea::framework::apps::ResidentApps::activeId();
|
|
581
|
-
return activeId && std::strcmp(activeId, gea::framework::apps::AppManager::launcherAppId()) != 0;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
- (void)syncLauncherButton
|
|
585
|
-
{
|
|
586
|
-
if (!self.launcherButton || !self.rootView) return;
|
|
587
|
-
const BOOL show = [self shouldShowLauncherButton];
|
|
588
|
-
UIEdgeInsets safeInsets = self.rootView.safeAreaInsets;
|
|
589
|
-
const CGRect bounds = self.rootView.bounds;
|
|
590
|
-
const CGFloat size = 52.0;
|
|
591
|
-
const CGFloat bottomMargin = 12.0;
|
|
592
|
-
const CGFloat x = (bounds.size.width - size) * 0.5;
|
|
593
|
-
const CGFloat y = bounds.size.height - safeInsets.bottom - bottomMargin - size;
|
|
594
|
-
self.launcherButton.frame = CGRectMake(std::max<CGFloat>(safeInsets.left, x),
|
|
595
|
-
std::max<CGFloat>(safeInsets.top, y),
|
|
596
|
-
size,
|
|
597
|
-
size);
|
|
598
|
-
self.launcherButton.layer.cornerRadius = size * 0.5;
|
|
599
|
-
self.launcherButton.hidden = !show;
|
|
600
|
-
self.launcherButton.userInteractionEnabled = show;
|
|
601
|
-
if (show) [self.rootView bringSubviewToFront:self.launcherButton];
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
- (void)returnToLauncher:(id)sender
|
|
605
|
-
{
|
|
606
|
-
(void)sender;
|
|
607
|
-
if (gea::framework::apps::AppManager::returnRunningAppToLauncher("iOS launcher button")) {
|
|
608
|
-
self.launcherButton.hidden = YES;
|
|
609
|
-
self.launcherButton.userInteractionEnabled = NO;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
562
|
- (void)layoutDisplayViewInSafeArea
|
|
614
563
|
{
|
|
615
564
|
if (!self.rootView || !self.displayView) return;
|
|
@@ -620,7 +569,6 @@ bool attributedStringHasTextDecoration(NSAttributedString *value)
|
|
|
620
569
|
if (frame.size.width <= 0 || frame.size.height <= 0) frame = self.rootView.bounds;
|
|
621
570
|
self.displayView.frame = frame;
|
|
622
571
|
if (self.nativeRootView) self.nativeRootView.frame = self.rootView.bounds;
|
|
623
|
-
[self syncLauncherButton];
|
|
624
572
|
}
|
|
625
573
|
|
|
626
574
|
- (void)installNativeRootView:(UIView *)view
|
|
@@ -636,13 +584,8 @@ bool attributedStringHasTextDecoration(NSAttributedString *value)
|
|
|
636
584
|
view.userInteractionEnabled = YES;
|
|
637
585
|
self.displayView.hidden = YES;
|
|
638
586
|
self.displayView.userInteractionEnabled = NO;
|
|
639
|
-
|
|
640
|
-
[self.rootView insertSubview:view belowSubview:self.launcherButton];
|
|
641
|
-
} else {
|
|
642
|
-
[self.rootView addSubview:view];
|
|
643
|
-
}
|
|
587
|
+
[self.rootView addSubview:view];
|
|
644
588
|
[view setNeedsLayout];
|
|
645
|
-
[self syncLauncherButton];
|
|
646
589
|
}
|
|
647
590
|
|
|
648
591
|
- (CGSize)viewportSize
|
|
@@ -686,23 +629,6 @@ bool attributedStringHasTextDecoration(NSAttributedString *value)
|
|
|
686
629
|
self.displayView = [[GeaDisplayView alloc] initWithFrame:CGRectZero];
|
|
687
630
|
self.displayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
688
631
|
[self.rootView addSubview:self.displayView];
|
|
689
|
-
self.launcherButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
690
|
-
self.launcherButton.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.62];
|
|
691
|
-
self.launcherButton.tintColor = UIColor.whiteColor;
|
|
692
|
-
self.launcherButton.layer.borderWidth = 1.0;
|
|
693
|
-
self.launcherButton.layer.borderColor = [UIColor colorWithWhite:1.0 alpha:0.22].CGColor;
|
|
694
|
-
self.launcherButton.clipsToBounds = YES;
|
|
695
|
-
self.launcherButton.hidden = YES;
|
|
696
|
-
self.launcherButton.accessibilityLabel = @"App Launcher";
|
|
697
|
-
if (@available(iOS 13.0, *)) {
|
|
698
|
-
UIImage *image = [UIImage systemImageNamed:@"square.grid.2x2"];
|
|
699
|
-
[self.launcherButton setImage:image forState:UIControlStateNormal];
|
|
700
|
-
} else {
|
|
701
|
-
[self.launcherButton setTitle:@"Apps" forState:UIControlStateNormal];
|
|
702
|
-
self.launcherButton.titleLabel.font = [UIFont boldSystemFontOfSize:13.0];
|
|
703
|
-
}
|
|
704
|
-
[self.launcherButton addTarget:self action:@selector(returnToLauncher:) forControlEvents:UIControlEventTouchUpInside];
|
|
705
|
-
[self.rootView addSubview:self.launcherButton];
|
|
706
632
|
controller.view = self.rootView;
|
|
707
633
|
self.window.rootViewController = controller;
|
|
708
634
|
[self.window makeKeyAndVisible];
|
|
@@ -731,7 +657,6 @@ bool attributedStringHasTextDecoration(NSAttributedString *value)
|
|
|
731
657
|
// ImageStore decodes straight to full-colour RGBA8888 native pixels (no 565
|
|
732
658
|
// quantization, no separate retained buffer) for native UIImageView.
|
|
733
659
|
gea::framework::app::Application::init(viewportWidth, viewportHeight, devicePixelRatio);
|
|
734
|
-
queueInitialResidentAppFromProcessArguments();
|
|
735
660
|
[self syncAppBackgroundColor];
|
|
736
661
|
[self tick:nil];
|
|
737
662
|
|
|
@@ -748,27 +673,8 @@ bool attributedStringHasTextDecoration(NSAttributedString *value)
|
|
|
748
673
|
- (void)tick:(CADisplayLink *)link
|
|
749
674
|
{
|
|
750
675
|
(void)link;
|
|
751
|
-
{
|
|
752
|
-
char pendingId[64] = "";
|
|
753
|
-
if (gea::framework::apps::ResidentApps::consumeLaunch(pendingId, sizeof(pendingId)) &&
|
|
754
|
-
gea::framework::apps::ResidentApps::select(pendingId)) {
|
|
755
|
-
CGSize viewport = [self viewportSize];
|
|
756
|
-
const CGFloat viewportScale = [self viewportScale];
|
|
757
|
-
self.displayView.contentScaleFactor = viewportScale;
|
|
758
|
-
const int viewportWidth = std::max(1, static_cast<int>(std::ceil(viewport.width)));
|
|
759
|
-
const int viewportHeight = std::max(1, static_cast<int>(std::ceil(viewport.height)));
|
|
760
|
-
// gea's internal CSS device-pixel-ratio stays 1 (see init above): the
|
|
761
|
-
// layout is logical points; UIKit handles retina via contentScaleFactor.
|
|
762
|
-
const int devicePixelRatio = 1;
|
|
763
|
-
gea::ios::IosRenderer::instance().teardown();
|
|
764
|
-
gea_ios_display_set_viewport_size(viewportWidth, viewportHeight);
|
|
765
|
-
gea::platform::display::Display::init();
|
|
766
|
-
gea::framework::app::Application::init(viewportWidth, viewportHeight, devicePixelRatio);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
676
|
gea::framework::app::Application::frame(gea_embedded_now_ms());
|
|
770
677
|
[self syncAppBackgroundColor];
|
|
771
|
-
[self syncLauncherButton];
|
|
772
678
|
auto &tree = gea::embedded::ui::Tree::instance();
|
|
773
679
|
const int root = tree.mountedRoot();
|
|
774
680
|
if (!self.nativeRootView && root >= 0) {
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Per-resident-app entry.cpp generator for the iOS in-process app launcher.
|
|
3
|
-
|
|
4
|
-
import { writeFileSync } from 'node:fs'
|
|
5
|
-
|
|
6
|
-
const [, , prefix, outPath] = process.argv
|
|
7
|
-
if (!prefix || !outPath) {
|
|
8
|
-
console.error('Usage: generate-resident-entry.mjs <prefix> <out-cpp>')
|
|
9
|
-
process.exit(1)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const code = `// Auto-generated by targets/ios/generate-resident-entry.mjs. Do not edit.
|
|
13
|
-
#include "app.h"
|
|
14
|
-
#include "gea/embedded.h"
|
|
15
|
-
#include "graphics/font.h"
|
|
16
|
-
#include "host/rtc.h"
|
|
17
|
-
#include "host/timers.h"
|
|
18
|
-
#include "host/websocket.h"
|
|
19
|
-
#include "ui/document.h"
|
|
20
|
-
#include "ui/style.h"
|
|
21
|
-
|
|
22
|
-
extern void ${prefix}_top_level();
|
|
23
|
-
extern void ${prefix}_register_styles();
|
|
24
|
-
extern void gea_cpp_clear_microtasks();
|
|
25
|
-
|
|
26
|
-
namespace gea::framework::app::generated::${prefix} {
|
|
27
|
-
void drainMicrotasks();
|
|
28
|
-
} // namespace gea::framework::app::generated::${prefix}
|
|
29
|
-
|
|
30
|
-
void __attribute__((weak)) ${prefix}_register_styles() {}
|
|
31
|
-
|
|
32
|
-
void ${prefix}_init(int width, int height, double devicePixelRatio)
|
|
33
|
-
{
|
|
34
|
-
\tgea::embedded::ui::Document::setPreferredMountSize(width, height);
|
|
35
|
-
\tgea::embedded::ui::setViewportMetrics(width, height, devicePixelRatio);
|
|
36
|
-
\tgea::host::resetAnimationFrameCallbacks();
|
|
37
|
-
\tgea::host::resetScheduledTimers();
|
|
38
|
-
\tgea_cpp_clear_microtasks();
|
|
39
|
-
\tgea::embedded::ui::StyleSheet::instance().clear();
|
|
40
|
-
\t${prefix}_register_styles();
|
|
41
|
-
\tgea::embedded::ui::Document::instance().clear();
|
|
42
|
-
\t${prefix}_top_level();
|
|
43
|
-
\tgea::embedded::ui::Document::instance().refreshMountedIfDirty();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
void ${prefix}_frame(int timestampMs)
|
|
47
|
-
{
|
|
48
|
-
\tgea::framework::app::generated::${prefix}::drainMicrotasks();
|
|
49
|
-
\tgea::host::runAnimationFrameCallbacks(static_cast<double>(timestampMs));
|
|
50
|
-
\tgea::framework::app::generated::${prefix}::drainMicrotasks();
|
|
51
|
-
\tgea::host::websocket::runCallbacks();
|
|
52
|
-
\tgea::host::rtc::runCallbacks();
|
|
53
|
-
\tgea::embedded::ui::Document::instance().frame(timestampMs);
|
|
54
|
-
\tgea::embedded::ui::Document::instance().refreshMountedIfDirty();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
void ${prefix}_settings_toggle() {}
|
|
58
|
-
int ${prefix}_mirror_begin_snapshot() { return 0; }
|
|
59
|
-
int ${prefix}_mirror_begin_diff() { return 0; }
|
|
60
|
-
int ${prefix}_mirror_next_record(unsigned char *, int) { return 0; }
|
|
61
|
-
void ${prefix}_mirror_clear_dirty() {}
|
|
62
|
-
void ${prefix}_ble_connected() {}
|
|
63
|
-
void ${prefix}_ble_disconnected() {}
|
|
64
|
-
void ${prefix}_ble_bound() {}
|
|
65
|
-
`
|
|
66
|
-
|
|
67
|
-
writeFileSync(outPath, code)
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Generates the iOS resident-app registry used by app-launcher simulator builds.
|
|
3
|
-
|
|
4
|
-
import { writeFileSync } from 'node:fs'
|
|
5
|
-
|
|
6
|
-
const [, , outPath, launcherId, ...appIds] = process.argv
|
|
7
|
-
if (!outPath || !launcherId || appIds.length === 0) {
|
|
8
|
-
console.error('Usage: generate-resident-registry.mjs <out-cpp> <launcher-id> <app-id...>')
|
|
9
|
-
process.exit(1)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const safe = (id) => id.replace(/[^A-Za-z0-9_]/g, '_')
|
|
13
|
-
const prefix = (id) => `gea_resident_${safe(id)}`
|
|
14
|
-
const quote = (s) => s.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
|
15
|
-
|
|
16
|
-
const lines = []
|
|
17
|
-
lines.push('// Auto-generated by targets/ios/generate-resident-registry.mjs.')
|
|
18
|
-
lines.push('// Do not edit.')
|
|
19
|
-
lines.push('#include "app.h"')
|
|
20
|
-
lines.push('#include "resident_apps.h"')
|
|
21
|
-
lines.push('#include "graphics/font.h"')
|
|
22
|
-
lines.push('')
|
|
23
|
-
lines.push('#include <cstdio>')
|
|
24
|
-
lines.push('#include <cstring>')
|
|
25
|
-
lines.push('#include <mutex>')
|
|
26
|
-
lines.push('')
|
|
27
|
-
|
|
28
|
-
for (const id of appIds) {
|
|
29
|
-
const p = prefix(id)
|
|
30
|
-
lines.push(`extern void ${p}_init(int width, int height, double devicePixelRatio);`)
|
|
31
|
-
lines.push(`extern void ${p}_frame(int timestampMs);`)
|
|
32
|
-
lines.push(`extern void ${p}_settings_toggle();`)
|
|
33
|
-
lines.push(`extern const gea::framework::graphics::RasterizedFontData *${p}_lookup_font(int fontId);`)
|
|
34
|
-
lines.push(`extern const gea::framework::graphics::RasterizedFontData *${p}_lookup_font_for_family(int familyId, int sizePx);`)
|
|
35
|
-
lines.push(`extern int ${p}_lookup_font_family(const char *family);`)
|
|
36
|
-
lines.push(`extern const char *${p}_lookup_font_family_name(int familyId);`)
|
|
37
|
-
}
|
|
38
|
-
lines.push('')
|
|
39
|
-
|
|
40
|
-
lines.push('namespace gea::framework::apps {')
|
|
41
|
-
lines.push('namespace {')
|
|
42
|
-
lines.push(`constexpr const char *kLauncherAppId = "${quote(launcherId)}";`)
|
|
43
|
-
lines.push('std::mutex &pendingLock() { static std::mutex lock; return lock; }')
|
|
44
|
-
lines.push('char pendingLaunchAppId[64] = "";')
|
|
45
|
-
lines.push('bool pendingLaunchValid = false;')
|
|
46
|
-
lines.push('')
|
|
47
|
-
lines.push('const ResidentApp residentApps[] = {')
|
|
48
|
-
for (const id of appIds) {
|
|
49
|
-
const p = prefix(id)
|
|
50
|
-
lines.push('\t{')
|
|
51
|
-
lines.push(`\t\t.id = "${quote(id)}",`)
|
|
52
|
-
lines.push('\t\t.displayFlushChunkRows = 0,')
|
|
53
|
-
lines.push('\t\t.displayFlushQueueDepth = 0,')
|
|
54
|
-
lines.push(`\t\t.init = ${p}_init,`)
|
|
55
|
-
lines.push(`\t\t.frame = ${p}_frame,`)
|
|
56
|
-
lines.push(`\t\t.settingsToggle = ${p}_settings_toggle,`)
|
|
57
|
-
lines.push(`\t\t.lookupFont = ${p}_lookup_font,`)
|
|
58
|
-
lines.push(`\t\t.lookupFontForFamily = ${p}_lookup_font_for_family,`)
|
|
59
|
-
lines.push(`\t\t.lookupFontFamily = ${p}_lookup_font_family,`)
|
|
60
|
-
lines.push(`\t\t.lookupFontFamilyName = ${p}_lookup_font_family_name,`)
|
|
61
|
-
lines.push('\t},')
|
|
62
|
-
}
|
|
63
|
-
lines.push('};')
|
|
64
|
-
lines.push(`constexpr int kResidentAppCount = ${appIds.length};`)
|
|
65
|
-
lines.push('const ResidentApp *activeApp = &residentApps[0];')
|
|
66
|
-
lines.push('')
|
|
67
|
-
lines.push('const ResidentApp *findApp(const char *appId)')
|
|
68
|
-
lines.push('{')
|
|
69
|
-
lines.push("\tif (!appId || appId[0] == '\\0') return nullptr;")
|
|
70
|
-
lines.push('\tfor (int i = 0; i < kResidentAppCount; i++) {')
|
|
71
|
-
lines.push('\t\tif (std::strcmp(residentApps[i].id, appId) == 0) return &residentApps[i];')
|
|
72
|
-
lines.push('\t}')
|
|
73
|
-
lines.push('\treturn nullptr;')
|
|
74
|
-
lines.push('}')
|
|
75
|
-
lines.push('} // namespace')
|
|
76
|
-
lines.push('')
|
|
77
|
-
lines.push('namespace generated {')
|
|
78
|
-
lines.push('const ResidentApp *activeResidentApp() { return activeApp; }')
|
|
79
|
-
lines.push('} // namespace generated')
|
|
80
|
-
lines.push('')
|
|
81
|
-
lines.push('bool ResidentApps::isEnabled() { return kResidentAppCount > 0; }')
|
|
82
|
-
lines.push('const char *ResidentApps::activeId() { return activeApp ? activeApp->id : nullptr; }')
|
|
83
|
-
lines.push('')
|
|
84
|
-
lines.push('bool ResidentApps::select(const char *appId)')
|
|
85
|
-
lines.push('{')
|
|
86
|
-
lines.push('\tconst ResidentApp *next = findApp(appId);')
|
|
87
|
-
lines.push('\tif (!next) return false;')
|
|
88
|
-
lines.push('\tactiveApp = next;')
|
|
89
|
-
lines.push('\treturn true;')
|
|
90
|
-
lines.push('}')
|
|
91
|
-
lines.push('')
|
|
92
|
-
lines.push('bool ResidentApps::requestLaunch(const char *appId)')
|
|
93
|
-
lines.push('{')
|
|
94
|
-
lines.push('\tif (!findApp(appId)) return false;')
|
|
95
|
-
lines.push('\tstd::lock_guard guard(pendingLock());')
|
|
96
|
-
lines.push('\tstd::snprintf(pendingLaunchAppId, sizeof(pendingLaunchAppId), "%s", appId);')
|
|
97
|
-
lines.push('\tpendingLaunchValid = true;')
|
|
98
|
-
lines.push('\treturn true;')
|
|
99
|
-
lines.push('}')
|
|
100
|
-
lines.push('')
|
|
101
|
-
lines.push('bool ResidentApps::consumeLaunch(char *dst, std::size_t cap)')
|
|
102
|
-
lines.push('{')
|
|
103
|
-
lines.push('\tstd::lock_guard guard(pendingLock());')
|
|
104
|
-
lines.push('\tif (!pendingLaunchValid) return false;')
|
|
105
|
-
lines.push('\tif (dst && cap > 0) std::snprintf(dst, cap, "%s", pendingLaunchAppId);')
|
|
106
|
-
lines.push('\tpendingLaunchValid = false;')
|
|
107
|
-
lines.push("\tpendingLaunchAppId[0] = '\\0';")
|
|
108
|
-
lines.push('\treturn true;')
|
|
109
|
-
lines.push('}')
|
|
110
|
-
lines.push('')
|
|
111
|
-
lines.push('bool ResidentApps::returnToLauncher(const char *trigger)')
|
|
112
|
-
lines.push('{')
|
|
113
|
-
lines.push('\t(void)trigger;')
|
|
114
|
-
lines.push('\tif (!activeApp || std::strcmp(activeApp->id, kLauncherAppId) == 0) return false;')
|
|
115
|
-
lines.push('\treturn ResidentApps::requestLaunch(kLauncherAppId);')
|
|
116
|
-
lines.push('}')
|
|
117
|
-
lines.push('')
|
|
118
|
-
lines.push('} // namespace gea::framework::apps')
|
|
119
|
-
lines.push('')
|
|
120
|
-
lines.push('namespace gea::framework::app {')
|
|
121
|
-
lines.push('void Application::init(int width, int height, double devicePixelRatio)')
|
|
122
|
-
lines.push('{')
|
|
123
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
124
|
-
lines.push('\tif (active && active->init) active->init(width, height, devicePixelRatio);')
|
|
125
|
-
lines.push('}')
|
|
126
|
-
lines.push('void Application::frame(int timestampMs)')
|
|
127
|
-
lines.push('{')
|
|
128
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
129
|
-
lines.push('\tif (active && active->frame) active->frame(timestampMs);')
|
|
130
|
-
lines.push('}')
|
|
131
|
-
lines.push('void Application::toggleSettings()')
|
|
132
|
-
lines.push('{')
|
|
133
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
134
|
-
lines.push('\tif (active && active->settingsToggle) active->settingsToggle();')
|
|
135
|
-
lines.push('}')
|
|
136
|
-
lines.push('} // namespace gea::framework::app')
|
|
137
|
-
lines.push('')
|
|
138
|
-
lines.push('namespace gea::framework::graphics::generated {')
|
|
139
|
-
lines.push('void ensureLinked() {}')
|
|
140
|
-
lines.push('const RasterizedFontData *lookupFont(int fontId)')
|
|
141
|
-
lines.push('{')
|
|
142
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
143
|
-
lines.push('\treturn active && active->lookupFont ? active->lookupFont(fontId) : nullptr;')
|
|
144
|
-
lines.push('}')
|
|
145
|
-
lines.push('const RasterizedFontData *lookupFontForFamily(int familyId, int sizePx)')
|
|
146
|
-
lines.push('{')
|
|
147
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
148
|
-
lines.push('\treturn active && active->lookupFontForFamily ? active->lookupFontForFamily(familyId, sizePx) : nullptr;')
|
|
149
|
-
lines.push('}')
|
|
150
|
-
lines.push('int lookupFontFamily(const char *family)')
|
|
151
|
-
lines.push('{')
|
|
152
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
153
|
-
lines.push('\treturn active && active->lookupFontFamily ? active->lookupFontFamily(family) : -1;')
|
|
154
|
-
lines.push('}')
|
|
155
|
-
lines.push('const char *lookupFontFamilyName(int familyId)')
|
|
156
|
-
lines.push('{')
|
|
157
|
-
lines.push('\tconst auto *active = gea::framework::apps::generated::activeResidentApp();')
|
|
158
|
-
lines.push('\treturn active && active->lookupFontFamilyName ? active->lookupFontFamilyName(familyId) : nullptr;')
|
|
159
|
-
lines.push('}')
|
|
160
|
-
lines.push('} // namespace gea::framework::graphics::generated')
|
|
161
|
-
|
|
162
|
-
writeFileSync(outPath, lines.join('\n') + '\n')
|