basalt-gtk 0.0.0-rc5
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/LICENSE +21 -0
- package/cli/runLinux.js +29 -0
- package/cli/shared.js +75 -0
- package/native/CMakeLists.txt +362 -0
- package/native/gtk/ColorSchemeGtk.cpp +58 -0
- package/native/gtk/ComponentRegistryGtk.cpp +101 -0
- package/native/gtk/FontRegistryFontconfig.cpp +127 -0
- package/native/gtk/GtkAnimationChoreographer.cpp +73 -0
- package/native/gtk/GtkAnimationChoreographer.h +49 -0
- package/native/gtk/GtkDropTarget.cpp +269 -0
- package/native/gtk/GtkDropTarget.h +40 -0
- package/native/gtk/GtkFocus.cpp +296 -0
- package/native/gtk/GtkFocus.h +113 -0
- package/native/gtk/GtkImageLoader.cpp +128 -0
- package/native/gtk/GtkImageLoader.h +87 -0
- package/native/gtk/GtkKeyEvents.cpp +91 -0
- package/native/gtk/GtkKeyEvents.h +21 -0
- package/native/gtk/GtkMenuBar.cpp +45 -0
- package/native/gtk/GtkMountingManager.cpp +1027 -0
- package/native/gtk/GtkMountingManager.h +146 -0
- package/native/gtk/GtkRunLoopObserver.cpp +77 -0
- package/native/gtk/GtkRunLoopObserver.h +41 -0
- package/native/gtk/GtkScrollView.cpp +626 -0
- package/native/gtk/GtkScrollView.h +209 -0
- package/native/gtk/GtkSkiaContext.cpp +248 -0
- package/native/gtk/GtkSkiaContext.h +62 -0
- package/native/gtk/GtkSkiaModule.cpp +80 -0
- package/native/gtk/GtkSkiaModule.h +51 -0
- package/native/gtk/GtkSkiaPeer.cpp +285 -0
- package/native/gtk/GtkSkiaPeer.h +63 -0
- package/native/gtk/GtkTextInput.cpp +428 -0
- package/native/gtk/GtkTextInput.h +123 -0
- package/native/gtk/GtkTextPeer.cpp +425 -0
- package/native/gtk/GtkTextPeer.h +87 -0
- package/native/gtk/GtkTitleBar.cpp +273 -0
- package/native/gtk/GtkTitleBar.h +96 -0
- package/native/gtk/GtkTitleBarLayout.cpp +45 -0
- package/native/gtk/GtkTitleBarLayout.h +36 -0
- package/native/gtk/GtkTouchDispatcher.cpp +671 -0
- package/native/gtk/GtkTouchDispatcher.h +139 -0
- package/native/gtk/GtkWindowControl.cpp +223 -0
- package/native/gtk/GtkWindowModule.cpp +194 -0
- package/native/gtk/GtkWindowModule.h +62 -0
- package/native/gtk/PangoTextLayout.cpp +295 -0
- package/native/gtk/PangoTextLayout.h +54 -0
- package/native/gtk/PangoTextLayoutManager.cpp +140 -0
- package/native/gtk/PlatformServicesGtk.cpp +583 -0
- package/native/gtk/RnView.cpp +1407 -0
- package/native/gtk/RnView.h +339 -0
- package/native/gtk/demo_layout_gtk.cpp +57 -0
- package/native/gtk/main_gtk.cpp +1981 -0
- package/native/gtk/mount_harness_gtk.cpp +143 -0
- package/native/tests/TestMainGtk.cpp +25 -0
- package/native/tests/notification_stub.cpp +103 -0
- package/native/tests/test_accessibility.cpp +251 -0
- package/native/tests/test_focus.cpp +194 -0
- package/native/tests/test_hittest.cpp +242 -0
- package/native/tests/test_image.cpp +135 -0
- package/native/tests/test_key_events_gtk.cpp +112 -0
- package/native/tests/test_mounting.cpp +415 -0
- package/native/tests/test_scrollview.cpp +258 -0
- package/native/tests/test_skia_texture.cpp +120 -0
- package/native/tests/test_text.cpp +147 -0
- package/native/tests/test_textinput.cpp +598 -0
- package/native/tests/test_titlebar.cpp +137 -0
- package/native/tests/test_titlebar_drag.cpp +138 -0
- package/native/tests/test_version.cpp +49 -0
- package/native/tests/test_view.cpp +162 -0
- package/native/tests/test_viewprops.cpp +254 -0
- package/package.json +26 -0
- package/react-native.config.js +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vince Vella
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/cli/runLinux.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `react-native run-linux`.
|
|
3
|
+
*
|
|
4
|
+
* Four strings and a path. Everything a desktop run actually does is in
|
|
5
|
+
* basalt-core's cli/desktop.js, shared with `run-macos` and
|
|
6
|
+
* `run-windows`, because none of it is about a toolkit -- see the note at the
|
|
7
|
+
* top of that file.
|
|
8
|
+
*
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// @ts-check
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const {shared, sharedPackageDir} = require('./shared');
|
|
18
|
+
|
|
19
|
+
const {makeRunCommand} = shared('cli/desktop');
|
|
20
|
+
|
|
21
|
+
module.exports = makeRunCommand({
|
|
22
|
+
platform: 'linux',
|
|
23
|
+
label: 'Linux',
|
|
24
|
+
command: 'run-linux',
|
|
25
|
+
binary: 'basalt_gtk',
|
|
26
|
+
nativeDir: path.resolve(__dirname, '..', 'native'),
|
|
27
|
+
coreDir: path.join(sharedPackageDir(), 'native'),
|
|
28
|
+
toolchain: 'a C++20 compiler and the GTK4 and Pango development packages',
|
|
29
|
+
});
|
package/cli/shared.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reaching basalt-core, the shared half, from this package.
|
|
3
|
+
*
|
|
4
|
+
* The one file in a platform package's CLI that cannot itself be shared,
|
|
5
|
+
* because it is what finds the thing everything else is shared through. Two
|
|
6
|
+
* layouts matter and only one of them resolves by name.
|
|
7
|
+
*
|
|
8
|
+
* Installed into an app, basalt-core is a sibling in node_modules and
|
|
9
|
+
* `require('basalt-core/...')` finds it. In a checkout of this
|
|
10
|
+
* repository the two packages are sibling directories with nothing installed
|
|
11
|
+
* between them -- deliberately, since this repo has no node_modules of its own
|
|
12
|
+
* -- and the same require fails. So: by name first, because that is the layout
|
|
13
|
+
* an app is in, and beside us second, because that is the layout it is
|
|
14
|
+
* developed in.
|
|
15
|
+
*
|
|
16
|
+
* Both reach the *built* package. basalt-core is TypeScript: by name
|
|
17
|
+
* resolves through its `exports` map, which points into `dist/`, and the
|
|
18
|
+
* sibling path has to say so itself. A checkout that has not run
|
|
19
|
+
* scripts/build_ts.sh has nothing here to find, which is what the error says.
|
|
20
|
+
*
|
|
21
|
+
* @format
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// @ts-check
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const path = require('path');
|
|
28
|
+
|
|
29
|
+
const SIBLING = path.resolve(__dirname, '..', '..', 'basalt-core');
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Where basalt-core is on disk. Same two layouts, same order.
|
|
33
|
+
* @returns {string}
|
|
34
|
+
*/
|
|
35
|
+
function sharedPackageDir() {
|
|
36
|
+
try {
|
|
37
|
+
return path.dirname(require.resolve('basalt-core/package.json'));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (/** @type {NodeJS.ErrnoException} */ (error).code !== 'MODULE_NOT_FOUND') {
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
return SIBLING;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* One of basalt-core's modules, by subpath.
|
|
48
|
+
* @param {string} subpath
|
|
49
|
+
* @returns {any}
|
|
50
|
+
*/
|
|
51
|
+
function shared(subpath) {
|
|
52
|
+
const name = `basalt-core/${subpath}`;
|
|
53
|
+
try {
|
|
54
|
+
return require(name);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (/** @type {NodeJS.ErrnoException} */ (error).code !== 'MODULE_NOT_FOUND') {
|
|
57
|
+
// The module was found and threw on its way up. Passing it through keeps
|
|
58
|
+
// a real error in that file from being reported as a missing package.
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
return require(path.join(SIBLING, 'dist', subpath));
|
|
63
|
+
} catch (siblingError) {
|
|
64
|
+
if (/** @type {NodeJS.ErrnoException} */ (siblingError).code === 'MODULE_NOT_FOUND') {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`could not load ${name}. In a checkout, basalt-core has to be ` +
|
|
67
|
+
'built first: run scripts/build_ts.sh.',
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
throw siblingError;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {shared, sharedPackageDir};
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# basalt-gtk — the Linux view layer, over GTK4.
|
|
2
|
+
#
|
|
3
|
+
# A view layer, a mounting manager and a host. Everything behind them is in
|
|
4
|
+
# basalt-core, which this adds as a subdirectory; nothing here is
|
|
5
|
+
# duplicated from it.
|
|
6
|
+
|
|
7
|
+
cmake_minimum_required(VERSION 3.13)
|
|
8
|
+
project(basalt_gtk CXX)
|
|
9
|
+
|
|
10
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
11
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
12
|
+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
13
|
+
|
|
14
|
+
# Executables at the top of the build tree whether this is configured directly
|
|
15
|
+
# or added by a wrapper, so `build/basalt_gtk` means the same thing either way.
|
|
16
|
+
# Every script and document here names that path.
|
|
17
|
+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Finding basalt-core, the shared half.
|
|
21
|
+
#
|
|
22
|
+
# The default works in both layouts this can be built from: a checkout of this
|
|
23
|
+
# repository, where the packages are siblings under packages/, and an app's
|
|
24
|
+
# node_modules, where npm hoists them side by side. `react-native run-linux --build`
|
|
25
|
+
# passes it explicitly anyway, because a pnpm store is neither.
|
|
26
|
+
#
|
|
27
|
+
# Guarded on the target rather than on the variable: a build that configures
|
|
28
|
+
# both platform packages would otherwise add the same directory twice, which
|
|
29
|
+
# CMake refuses.
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
if(NOT TARGET basalt_core)
|
|
32
|
+
if(NOT DEFINED BASALT_CORE_DIR)
|
|
33
|
+
set(BASALT_CORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../basalt-core/native)
|
|
34
|
+
endif()
|
|
35
|
+
get_filename_component(BASALT_CORE_DIR "${BASALT_CORE_DIR}" ABSOLUTE)
|
|
36
|
+
if(NOT EXISTS ${BASALT_CORE_DIR}/CMakeLists.txt)
|
|
37
|
+
message(FATAL_ERROR
|
|
38
|
+
"basalt-core not found at ${BASALT_CORE_DIR}.\n"
|
|
39
|
+
"Pass -DBASALT_CORE_DIR=<path to basalt-core/native>.")
|
|
40
|
+
endif()
|
|
41
|
+
# Capability packages first, and only here, because they contribute include
|
|
42
|
+
# directories to basalt_core and CMake resolves those when the target is
|
|
43
|
+
# created rather than afterwards.
|
|
44
|
+
#
|
|
45
|
+
# This used to live only in the repository's root CMakeLists, which is the
|
|
46
|
+
# entry point for a checkout and is not the entry point for an app: the CLI
|
|
47
|
+
# configures -S <host package>/native, so the loop never ran and
|
|
48
|
+
# core/portability_probe.cpp failed on a Notifications.h that nothing had
|
|
49
|
+
# put on the path. A checkout could not see it, because there the root added
|
|
50
|
+
# the packages first and the header was always there.
|
|
51
|
+
#
|
|
52
|
+
# Guarded on the property rather than the variable for the same reason the
|
|
53
|
+
# block around it is guarded on the target: a build configuring two host
|
|
54
|
+
# packages must not add the same directory twice.
|
|
55
|
+
get_property(basalt_packages_added GLOBAL PROPERTY BASALT_PACKAGES_ADDED)
|
|
56
|
+
if(NOT basalt_packages_added)
|
|
57
|
+
set_property(GLOBAL PROPERTY BASALT_PACKAGES_ADDED TRUE)
|
|
58
|
+
foreach(package ${BASALT_PACKAGES})
|
|
59
|
+
if(EXISTS ${package}/native/CMakeLists.txt)
|
|
60
|
+
get_filename_component(basalt_package_name ${package} NAME)
|
|
61
|
+
message(STATUS "basalt: capability package ${basalt_package_name}")
|
|
62
|
+
add_subdirectory(${package}/native basalt-package-${basalt_package_name})
|
|
63
|
+
endif()
|
|
64
|
+
endforeach()
|
|
65
|
+
endif()
|
|
66
|
+
|
|
67
|
+
add_subdirectory(${BASALT_CORE_DIR} basalt_core)
|
|
68
|
+
endif()
|
|
69
|
+
|
|
70
|
+
# What capability packages contributed for this host; see
|
|
71
|
+
# packages/basalt-notifications for what a package sets.
|
|
72
|
+
#
|
|
73
|
+
# Read *after* the block above, because that block is where the packages are
|
|
74
|
+
# added. It used to be read at the top of this file, which worked for a
|
|
75
|
+
# checkout -- the root CMakeLists adds the packages before it adds this one --
|
|
76
|
+
# and silently contributed nothing for an app, where this file is the entry
|
|
77
|
+
# point. The symptom was a link error naming every notification seam.
|
|
78
|
+
get_property(BASALT_PACKAGE_GTK_SOURCES GLOBAL PROPERTY BASALT_PACKAGE_GTK_SOURCES)
|
|
79
|
+
# And what those sources need linked. A package contributing an implementation
|
|
80
|
+
# that reaches for a library had no way to say so; see the same property in the
|
|
81
|
+
# AppKit package for what went missing.
|
|
82
|
+
get_property(BASALT_PACKAGE_GTK_LINK_LIBRARIES GLOBAL PROPERTY BASALT_PACKAGE_GTK_LINK_LIBRARIES)
|
|
83
|
+
# And a package's own unit tests, which run in this host's suite. A capability
|
|
84
|
+
# with a platform half has nowhere else to be tested: it is compiled into the
|
|
85
|
+
# host binary, so the host's suite is the only binary that has it.
|
|
86
|
+
get_property(BASALT_PACKAGE_TESTS GLOBAL PROPERTY BASALT_PACKAGE_TESTS)
|
|
87
|
+
|
|
88
|
+
# Found here rather than inherited from the shared half. find_package sets
|
|
89
|
+
# PKG_CONFIG_VERSION as an ordinary variable, which is scoped to the directory
|
|
90
|
+
# that ran it, so a package that only inherits it gets pkg_check_modules failing
|
|
91
|
+
# on a malformed `if` deep inside FindPkgConfig rather than on anything legible.
|
|
92
|
+
#
|
|
93
|
+
# Neither of the first two is REQUIRED, and that is the same courtesy the AppKit
|
|
94
|
+
# and Win32 packages extend: a checkout builds every package it finds, and on a
|
|
95
|
+
# machine with no GTK -- Windows, or a Mac without brew's gtk4 -- this one has
|
|
96
|
+
# nothing it could compile and should say so rather than fail the configure for
|
|
97
|
+
# the platform that machine *can* build. Everything after these two stays
|
|
98
|
+
# REQUIRED: a box with gtk4 and no pangoft2 is a broken installation, not an
|
|
99
|
+
# absent one.
|
|
100
|
+
find_package(PkgConfig QUIET)
|
|
101
|
+
if(NOT PKG_CONFIG_FOUND)
|
|
102
|
+
message(STATUS "basalt-gtk skipped: no pkg-config")
|
|
103
|
+
return()
|
|
104
|
+
endif()
|
|
105
|
+
|
|
106
|
+
pkg_check_modules(GTK4 IMPORTED_TARGET gtk4)
|
|
107
|
+
if(NOT GTK4_FOUND)
|
|
108
|
+
message(STATUS "basalt-gtk skipped: no gtk4")
|
|
109
|
+
return()
|
|
110
|
+
endif()
|
|
111
|
+
# For fonts an app loads at runtime. Pango finds fonts through fontconfig, so
|
|
112
|
+
# adding one to fontconfig is what makes it available to text this platform
|
|
113
|
+
# renders. See gtk/FontRegistryFontconfig.cpp.
|
|
114
|
+
pkg_check_modules(FONTCONFIG REQUIRED IMPORTED_TARGET fontconfig)
|
|
115
|
+
# pango_fc_font_map_config_changed lives here rather than in pango proper. It is
|
|
116
|
+
# how Pango is told that the set of fonts changed underneath it.
|
|
117
|
+
pkg_check_modules(PANGOFT2 REQUIRED IMPORTED_TARGET pangoft2)
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# basalt_gtk_view — the GTK4 widget layer.
|
|
121
|
+
#
|
|
122
|
+
# No React Native dependency, so it builds and runs on its own.
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
add_library(basalt_gtk_view STATIC gtk/RnView.cpp gtk/GtkTextPeer.cpp)
|
|
126
|
+
# This project's own sources are held to -Wall -Wextra. React Native's are not:
|
|
127
|
+
# its targets set their own flags, and these are PRIVATE so they never reach it.
|
|
128
|
+
target_compile_options(basalt_gtk_view PRIVATE -Wall -Wextra)
|
|
129
|
+
target_include_directories(basalt_gtk_view PUBLIC gtk)
|
|
130
|
+
# core/FocusRing.h and core/Backface.h, and nothing else from there. Both are
|
|
131
|
+
# header-only and have no React Native in them, so taking them does not make
|
|
132
|
+
# this target depend on the half that does -- and the alternative is a focus
|
|
133
|
+
# ring that is a different blue on each desktop, and three toolkits each with
|
|
134
|
+
# their own idea of which way a rotated card is facing.
|
|
135
|
+
#
|
|
136
|
+
# Header-only is the constraint, not a preference: this library links no core,
|
|
137
|
+
# so anything it takes from there has to be `inline`.
|
|
138
|
+
target_include_directories(basalt_gtk_view PUBLIC
|
|
139
|
+
${CMAKE_CURRENT_SOURCE_DIR}/../../basalt-core/native/core)
|
|
140
|
+
target_link_libraries(basalt_gtk_view PUBLIC PkgConfig::GTK4 PkgConfig::FONTCONFIG PkgConfig::PANGOFT2)
|
|
141
|
+
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
# basalt_notification_stub -- a stand-in for a desktop's notification daemon.
|
|
144
|
+
#
|
|
145
|
+
# Test infrastructure rather than a host: the end-to-end suite starts a session
|
|
146
|
+
# bus and this on it, so that the one thing about notifications that needs a
|
|
147
|
+
# service to be running can actually be asserted. Needs GIO and nothing else,
|
|
148
|
+
# which basalt_gtk_view already brings.
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
add_executable(basalt_notification_stub tests/notification_stub.cpp)
|
|
152
|
+
target_link_libraries(basalt_notification_stub PRIVATE PkgConfig::GTK4)
|
|
153
|
+
target_compile_options(basalt_notification_stub PRIVATE -Wall -Wextra)
|
|
154
|
+
|
|
155
|
+
# ---------------------------------------------------------------------------
|
|
156
|
+
# demo_layout_gtk — exercises the widget layer with hand-written frames.
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
add_executable(demo_layout_gtk gtk/demo_layout_gtk.cpp)
|
|
160
|
+
target_link_libraries(demo_layout_gtk PRIVATE basalt_gtk_view)
|
|
161
|
+
|
|
162
|
+
# ---------------------------------------------------------------------------
|
|
163
|
+
# basalt_gtk_mounting — the GTK half of the Fabric mounting manager.
|
|
164
|
+
#
|
|
165
|
+
# The mutation walk is not here: it is in core/MountingWalk.h, shared with every
|
|
166
|
+
# other desktop platform. What is here is what is genuinely GTK about mounting.
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
if(TARGET basalt_core)
|
|
170
|
+
add_library(basalt_gtk_mounting STATIC
|
|
171
|
+
gtk/GtkMountingManager.cpp
|
|
172
|
+
# Which components this platform claims. See core/ComponentRegistry.h.
|
|
173
|
+
gtk/ComponentRegistryGtk.cpp
|
|
174
|
+
# The mounting manager loads <Image> pixels itself, so the loader lives
|
|
175
|
+
# here rather than with the host: mount_harness_gtk links this too.
|
|
176
|
+
gtk/GtkImageLoader.cpp
|
|
177
|
+
gtk/GtkScrollView.cpp
|
|
178
|
+
gtk/GtkTextInput.cpp
|
|
179
|
+
gtk/GtkTitleBar.cpp
|
|
180
|
+
# Whether a point drags the window: the geometry half, kept apart from the
|
|
181
|
+
# title bar so it needs no toplevel. See the header.
|
|
182
|
+
gtk/GtkTitleBarLayout.cpp
|
|
183
|
+
# Accepting a file or text dragged onto the window; see
|
|
184
|
+
# core/DragAndDrop.h for the model the three hosts share.
|
|
185
|
+
gtk/GtkDropTarget.cpp
|
|
186
|
+
# A window's size and full-screen state; see core/WindowControl.h.
|
|
187
|
+
gtk/GtkWindowControl.cpp
|
|
188
|
+
# The application menu; see core/MenuModel.h for why the three differ.
|
|
189
|
+
gtk/GtkMenuBar.cpp
|
|
190
|
+
gtk/GtkWindowModule.cpp
|
|
191
|
+
# Linux's implementation of core/FontRegistry.h.
|
|
192
|
+
gtk/FontRegistryFontconfig.cpp
|
|
193
|
+
# ...and of core/ColorScheme.h.
|
|
194
|
+
gtk/ColorSchemeGtk.cpp
|
|
195
|
+
# ...and of core/PlatformServices.h.
|
|
196
|
+
gtk/PlatformServicesGtk.cpp
|
|
197
|
+
gtk/PangoTextLayout.cpp
|
|
198
|
+
# Replaces React Native's stub; see cmake/ReactNativeCore.cmake.
|
|
199
|
+
gtk/PangoTextLayoutManager.cpp)
|
|
200
|
+
|
|
201
|
+
target_include_directories(basalt_gtk_mounting PUBLIC gtk)
|
|
202
|
+
target_link_libraries(basalt_gtk_mounting PUBLIC basalt_core)
|
|
203
|
+
|
|
204
|
+
# SYSTEM, so -Wall -Wextra on this project's own sources does not drown in
|
|
205
|
+
# diagnostics from React Native's headers, which are not -Wextra clean (its
|
|
206
|
+
# own targets build with a narrower warning set).
|
|
207
|
+
target_include_directories(basalt_gtk_mounting SYSTEM PUBLIC
|
|
208
|
+
${RN_DIR}/ReactCommon
|
|
209
|
+
${RN_DIR}/ReactCommon/jsi
|
|
210
|
+
# Not ${RN_DIR}/ReactCxxPlatform: when React Native is an installed package
|
|
211
|
+
# that directory does not exist and this one is the fetched copy. Latent
|
|
212
|
+
# until a version whose headers are not -Wextra clean, which 0.81 is.
|
|
213
|
+
${REACT_CXX_PLATFORM_DIR}
|
|
214
|
+
${FOLLY_DIR}
|
|
215
|
+
# Out-of-tree platforms pick a variant for each seam that has one. The cxx
|
|
216
|
+
# variants are the generic implementations; textlayoutmanager/cxx is a stub
|
|
217
|
+
# that measures nothing and is the first thing a Linux platform replaces.
|
|
218
|
+
${RN_DIR}/ReactCommon/react/renderer/graphics/platform/cxx
|
|
219
|
+
${RN_DIR}/ReactCommon/react/renderer/components/view/platform/cxx
|
|
220
|
+
${RN_DIR}/ReactCommon/react/renderer/textlayoutmanager/platform/cxx
|
|
221
|
+
${RN_DIR}/ReactCommon/react/renderer/imagemanager/platform/cxx
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
target_compile_definitions(basalt_gtk_mounting PUBLIC
|
|
225
|
+
FOLLY_NO_CONFIG=1
|
|
226
|
+
FOLLY_CFG_NO_COROUTINES=1
|
|
227
|
+
FOLLY_MOBILE=0
|
|
228
|
+
FOLLY_HAVE_PTHREAD=1
|
|
229
|
+
FOLLY_HAVE_CLOCK_GETTIME=1
|
|
230
|
+
GLOG_USE_GLOG_EXPORT
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# RN headers carry Xcode's #pragma mark, which GCC does not recognise.
|
|
234
|
+
target_compile_options(basalt_gtk_mounting PRIVATE -Wall -Wextra -Wno-unknown-pragmas)
|
|
235
|
+
|
|
236
|
+
target_link_libraries(basalt_gtk_mounting PUBLIC basalt_gtk_view rn_core)
|
|
237
|
+
target_link_libraries(basalt_gtk_mounting PUBLIC hermes-engine::hermesvm)
|
|
238
|
+
|
|
239
|
+
# @shopify/react-native-skia, when the build was pointed at an app that has
|
|
240
|
+
# it. See ../../basalt-core/native/cmake/Skia.cmake.
|
|
241
|
+
#
|
|
242
|
+
# Here rather than on basalt_core, for the reason the other two packages
|
|
243
|
+
# give: a platform context is a host's dependency. This one reaches
|
|
244
|
+
# fontconfig and GDK, and core/portability_probe.cpp links the core with no
|
|
245
|
+
# toolkit on purpose.
|
|
246
|
+
if(TARGET skia_core)
|
|
247
|
+
target_link_libraries(basalt_gtk_mounting PUBLIC skia_core)
|
|
248
|
+
target_sources(basalt_gtk_mounting PUBLIC $<TARGET_OBJECTS:skia_core>)
|
|
249
|
+
target_compile_definitions(basalt_gtk_mounting PUBLIC BASALT_HAS_SKIA=1)
|
|
250
|
+
# This host's half: the TurboModule the package asks for by name, and the
|
|
251
|
+
# platform context it hands to Skia. See gtk/GtkSkiaModule.h.
|
|
252
|
+
#
|
|
253
|
+
# No unicode adapter beside them, where the win32 package has one: that
|
|
254
|
+
# host links the libgrapheme backend and has to answer for
|
|
255
|
+
# `SkUnicodes::ICU::Make` itself. This one links skunicode_icu, which
|
|
256
|
+
# defines it.
|
|
257
|
+
target_sources(basalt_gtk_mounting PRIVATE
|
|
258
|
+
gtk/GtkSkiaModule.cpp
|
|
259
|
+
gtk/GtkSkiaContext.cpp
|
|
260
|
+
# The `<Canvas>` peer. The shortest of the three, because an RnView
|
|
261
|
+
# already draws a GdkTexture -- see gtk/GtkSkiaPeer.h.
|
|
262
|
+
gtk/GtkSkiaPeer.cpp)
|
|
263
|
+
endif()
|
|
264
|
+
|
|
265
|
+
# The seams point both ways, and GNU ld has to be told.
|
|
266
|
+
#
|
|
267
|
+
# `basalt_core` declares `core/PlatformServices.h`, `core/ColorScheme.h` and
|
|
268
|
+
# `core/FontRegistry.h`; this library defines them. So `CoreModules.o`, inside
|
|
269
|
+
# libbasalt_core.a, has undefined references that only libbasalt_gtk_mounting.a
|
|
270
|
+
# can satisfy -- while this library's own objects call into core. That is a
|
|
271
|
+
# genuine cycle between two static archives.
|
|
272
|
+
#
|
|
273
|
+
# It links anywhere the linker resolves across the whole command line, which
|
|
274
|
+
# is why Windows and macOS never noticed. GNU ld scans left to right exactly
|
|
275
|
+
# once, and CMake orders a dependency *after* its dependent, so libbasalt_core.a
|
|
276
|
+
# arrives with libbasalt_gtk_mounting.a already behind it and the seams come
|
|
277
|
+
# out undefined.
|
|
278
|
+
#
|
|
279
|
+
# Declaring the cycle is CMake's own answer: for mutually dependent STATIC
|
|
280
|
+
# libraries it repeats the whole connected component on the link line. A
|
|
281
|
+
# `--start-group` would work too and would say less about why.
|
|
282
|
+
target_link_libraries(basalt_core PUBLIC basalt_gtk_mounting)
|
|
283
|
+
|
|
284
|
+
# ---------------------------------------------------------------------------
|
|
285
|
+
# mount_harness_gtk — drives real ShadowViewMutations through the real mounting
|
|
286
|
+
# manager into real GTK widgets, with no JS runtime involved.
|
|
287
|
+
# ---------------------------------------------------------------------------
|
|
288
|
+
add_executable(mount_harness_gtk gtk/mount_harness_gtk.cpp)
|
|
289
|
+
target_link_libraries(mount_harness_gtk PRIVATE basalt_gtk_mounting)
|
|
290
|
+
target_compile_options(mount_harness_gtk PRIVATE -Wno-unknown-pragmas)
|
|
291
|
+
|
|
292
|
+
# ---------------------------------------------------------------------------
|
|
293
|
+
# basalt_gtk -- the real thing: ReactHost, Hermes and a live surface, with
|
|
294
|
+
# the mutation stream coming from Fabric rather than from a harness.
|
|
295
|
+
# ---------------------------------------------------------------------------
|
|
296
|
+
add_executable(basalt_gtk
|
|
297
|
+
gtk/main_gtk.cpp
|
|
298
|
+
gtk/GtkAnimationChoreographer.cpp
|
|
299
|
+
gtk/GtkRunLoopObserver.cpp
|
|
300
|
+
gtk/GtkFocus.cpp
|
|
301
|
+
gtk/GtkKeyEvents.cpp
|
|
302
|
+
# org.freedesktop.Notifications, over the session bus.
|
|
303
|
+
${BASALT_PACKAGE_GTK_SOURCES}
|
|
304
|
+
gtk/GtkTouchDispatcher.cpp)
|
|
305
|
+
target_link_libraries(basalt_gtk PRIVATE basalt_gtk_mounting)
|
|
306
|
+
if(BASALT_PACKAGE_GTK_LINK_LIBRARIES)
|
|
307
|
+
target_link_libraries(basalt_gtk PRIVATE ${BASALT_PACKAGE_GTK_LINK_LIBRARIES})
|
|
308
|
+
endif()
|
|
309
|
+
target_compile_options(basalt_gtk PRIVATE -Wall -Wextra -Wno-unknown-pragmas)
|
|
310
|
+
|
|
311
|
+
# ---------------------------------------------------------------------------
|
|
312
|
+
# basalt_gtk_tests -- the test suite.
|
|
313
|
+
#
|
|
314
|
+
# Needs a display: every test touches widgets, and GTK cannot create one
|
|
315
|
+
# before gtk_init succeeds. It presents no window. On a headless machine run
|
|
316
|
+
# it under Xvfb; see docs/TESTING.md.
|
|
317
|
+
# ---------------------------------------------------------------------------
|
|
318
|
+
add_executable(basalt_gtk_tests
|
|
319
|
+
${BASALT_TEST_HARNESS}
|
|
320
|
+
${BASALT_CORE_TESTS}
|
|
321
|
+
${BASALT_PACKAGE_TESTS}
|
|
322
|
+
tests/TestMainGtk.cpp
|
|
323
|
+
tests/test_mounting.cpp
|
|
324
|
+
tests/test_view.cpp
|
|
325
|
+
tests/test_text.cpp
|
|
326
|
+
tests/test_focus.cpp
|
|
327
|
+
tests/test_key_events_gtk.cpp
|
|
328
|
+
tests/test_hittest.cpp
|
|
329
|
+
tests/test_scrollview.cpp
|
|
330
|
+
tests/test_image.cpp
|
|
331
|
+
tests/test_accessibility.cpp
|
|
332
|
+
tests/test_viewprops.cpp
|
|
333
|
+
tests/test_textinput.cpp
|
|
334
|
+
tests/test_titlebar.cpp
|
|
335
|
+
# The drag regions, asking what tests/test_win32_titlebar.cpp asks of
|
|
336
|
+
# Windows. Needs a shown window: it walks up from gtk_widget_pick.
|
|
337
|
+
tests/test_titlebar_drag.cpp
|
|
338
|
+
tests/test_version.cpp
|
|
339
|
+
# Hit testing lives with the touch dispatcher, which the host builds; the
|
|
340
|
+
# tests need it too, and it pulls in nothing else.
|
|
341
|
+
gtk/GtkFocus.cpp
|
|
342
|
+
gtk/GtkKeyEvents.cpp
|
|
343
|
+
# org.freedesktop.Notifications, over the session bus.
|
|
344
|
+
${BASALT_PACKAGE_GTK_SOURCES}
|
|
345
|
+
gtk/GtkTouchDispatcher.cpp)
|
|
346
|
+
# The Skia/GDK pixel-format agreement, which only exists to test when Skia
|
|
347
|
+
# is in the build. See tests/test_skia_texture.cpp for why a comment was
|
|
348
|
+
# not enough.
|
|
349
|
+
if(TARGET skia_core)
|
|
350
|
+
target_sources(basalt_gtk_tests PRIVATE tests/test_skia_texture.cpp)
|
|
351
|
+
endif()
|
|
352
|
+
target_link_libraries(basalt_gtk_tests PRIVATE basalt_gtk_mounting)
|
|
353
|
+
if(BASALT_PACKAGE_GTK_LINK_LIBRARIES)
|
|
354
|
+
target_link_libraries(basalt_gtk_tests PRIVATE ${BASALT_PACKAGE_GTK_LINK_LIBRARIES})
|
|
355
|
+
endif()
|
|
356
|
+
target_include_directories(basalt_gtk_tests PRIVATE tests ${BASALT_TEST_INCLUDE})
|
|
357
|
+
target_compile_options(basalt_gtk_tests PRIVATE -Wall -Wextra -Wno-unknown-pragmas)
|
|
358
|
+
|
|
359
|
+
message(STATUS "basalt_gtk_mounting enabled (RN_DIR=${RN_DIR})")
|
|
360
|
+
else()
|
|
361
|
+
message(STATUS "basalt_gtk_mounting skipped (pass -DRN_DIR=... to enable)")
|
|
362
|
+
endif()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Linux's half of the colour-scheme seam.
|
|
2
|
+
//
|
|
3
|
+
// `GtkSettings:gtk-application-prefer-dark-theme` is what a GTK application
|
|
4
|
+
// reads, and what a desktop environment sets when the user asks for dark mode.
|
|
5
|
+
//
|
|
6
|
+
// The more modern answer is the `org.freedesktop.appearance color-scheme`
|
|
7
|
+
// setting from the XDG desktop portal, which works across toolkits and inside a
|
|
8
|
+
// Flatpak sandbox. It needs a D-Bus round trip and a subscription, and GTK
|
|
9
|
+
// already reflects the portal's value into this setting on a desktop that has
|
|
10
|
+
// one -- so this is the same answer with none of the plumbing. Worth revisiting
|
|
11
|
+
// if a sandboxed build ever disagrees with the desktop around it.
|
|
12
|
+
|
|
13
|
+
#include "ColorScheme.h"
|
|
14
|
+
|
|
15
|
+
#include <gtk/gtk.h>
|
|
16
|
+
|
|
17
|
+
namespace basalt {
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
|
|
21
|
+
void onPreferDarkChanged(GObject * /*settings*/, GParamSpec * /*spec*/, gpointer /*userData*/) {
|
|
22
|
+
notifyColorSchemeChanged();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
bool gObserving = false;
|
|
26
|
+
|
|
27
|
+
} // namespace
|
|
28
|
+
|
|
29
|
+
ColorScheme systemColorScheme() {
|
|
30
|
+
// gtk_settings_get_default returns null before gtk_init, which is where a
|
|
31
|
+
// unit test reads from. Light is React Native's default when a platform has
|
|
32
|
+
// no answer.
|
|
33
|
+
GtkSettings *settings = gtk_settings_get_default();
|
|
34
|
+
if (settings == nullptr) {
|
|
35
|
+
return ColorScheme::Light;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
gboolean prefersDark = FALSE;
|
|
39
|
+
g_object_get(settings, "gtk-application-prefer-dark-theme", &prefersDark, nullptr);
|
|
40
|
+
return prefersDark == TRUE ? ColorScheme::Dark : ColorScheme::Light;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void startObservingColorScheme() {
|
|
44
|
+
if (gObserving) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
GtkSettings *settings = gtk_settings_get_default();
|
|
48
|
+
if (settings == nullptr) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
g_signal_connect(settings,
|
|
52
|
+
"notify::gtk-application-prefer-dark-theme",
|
|
53
|
+
G_CALLBACK(onPreferDarkChanged),
|
|
54
|
+
nullptr);
|
|
55
|
+
gObserving = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
} // namespace basalt
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// The component registry for the GTK platform. See core/ComponentRegistry.h for
|
|
2
|
+
// why this is per-platform rather than shared.
|
|
3
|
+
|
|
4
|
+
#include "ComponentRegistry.h"
|
|
5
|
+
#include "ExpoImageComponent.h"
|
|
6
|
+
|
|
7
|
+
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
|
8
|
+
#include <react/renderer/components/FBReactNativeSpec/ComponentDescriptors.h>
|
|
9
|
+
#include <react/renderer/components/image/ImageComponentDescriptor.h>
|
|
10
|
+
#include <react/renderer/components/iostextinput/TextInputComponentDescriptor.h>
|
|
11
|
+
#include <react/renderer/components/modal/ModalHostViewComponentDescriptor.h>
|
|
12
|
+
#include <react/renderer/components/scrollview/ScrollViewComponentDescriptor.h>
|
|
13
|
+
#include <react/renderer/components/switch/AppleSwitchComponentDescriptor.h>
|
|
14
|
+
#include <react/renderer/components/text/ParagraphComponentDescriptor.h>
|
|
15
|
+
#include <react/renderer/components/text/RawTextComponentDescriptor.h>
|
|
16
|
+
#include <react/renderer/components/text/TextComponentDescriptor.h>
|
|
17
|
+
#include <react/renderer/components/view/ViewComponentDescriptor.h>
|
|
18
|
+
|
|
19
|
+
namespace facebook::react {
|
|
20
|
+
|
|
21
|
+
ComponentRegistryFactory getDefaultComponentRegistryFactory() {
|
|
22
|
+
return [](const EventDispatcher::Weak &eventDispatcher,
|
|
23
|
+
const std::shared_ptr<const ContextContainer> &contextContainer) {
|
|
24
|
+
static auto providerRegistry = []() {
|
|
25
|
+
auto registry = std::make_shared<ComponentDescriptorProviderRegistry>();
|
|
26
|
+
registry->add(concreteComponentDescriptorProvider<ViewComponentDescriptor>());
|
|
27
|
+
// Text is three descriptors, and only one of them mounts. <Text> becomes
|
|
28
|
+
// a Text node, its string a RawText node, and the outermost <Text>
|
|
29
|
+
// becomes a Paragraph that folds the whole subtree into a single
|
|
30
|
+
// AttributedString. Only Paragraph has a widget.
|
|
31
|
+
registry->add(concreteComponentDescriptorProvider<ParagraphComponentDescriptor>());
|
|
32
|
+
registry->add(concreteComponentDescriptorProvider<TextComponentDescriptor>());
|
|
33
|
+
registry->add(concreteComponentDescriptorProvider<RawTextComponentDescriptor>());
|
|
34
|
+
// Image's descriptor pulls an ImageManager out of the ContextContainer,
|
|
35
|
+
// creating one if absent. React Native's cxx ImageManager is a stub, so
|
|
36
|
+
// it produces no pixels; GtkImageLoader does that from the props instead.
|
|
37
|
+
registry->add(concreteComponentDescriptorProvider<ImageComponentDescriptor>());
|
|
38
|
+
// Unlike Image's, ScrollView's descriptor is a bare alias for
|
|
39
|
+
// ConcreteComponentDescriptor -- no manager, no ContextContainer entry.
|
|
40
|
+
// Its content child is a plain View, so nothing else is needed. Leaving
|
|
41
|
+
// it out does not fail loudly: the registry silently substitutes
|
|
42
|
+
// UnimplementedNativeView, which has no ScrollViewState, and the symptom
|
|
43
|
+
// is a ScrollView that renders but never scrolls.
|
|
44
|
+
registry->add(concreteComponentDescriptorProvider<ScrollViewComponentDescriptor>());
|
|
45
|
+
// React Native's *iOS* TextInput, whose C++ is portable: it measures
|
|
46
|
+
// through a TextLayoutManager, which here is the Pango one. Android's
|
|
47
|
+
// needs fbjni. Its component name is "TextInput".
|
|
48
|
+
registry->add(concreteComponentDescriptorProvider<TextInputComponentDescriptor>());
|
|
49
|
+
// expo-image's view. Registered whether or not the build has Expo in it:
|
|
50
|
+
// the descriptor is ordinary Fabric C++, and an app that never renders
|
|
51
|
+
// one pays a registry entry. See core/ExpoImageComponent.h.
|
|
52
|
+
registry->add(concreteComponentDescriptorProvider<ExpoImageComponentDescriptor>());
|
|
53
|
+
|
|
54
|
+
// --- The controls -----------------------------------------------------
|
|
55
|
+
//
|
|
56
|
+
// Everything above is a box with something drawn in it. These are not:
|
|
57
|
+
// each one is a toolkit control, or a window, and each one needed the
|
|
58
|
+
// view layer to grow a peer before registering it here would have meant
|
|
59
|
+
// anything. Registering a descriptor with nothing to mount it does not
|
|
60
|
+
// error -- Fabric builds the shadow nodes, lays them out, and the app
|
|
61
|
+
// renders blank rectangles -- so this list and the mounting manager's
|
|
62
|
+
// `hasComponent` are two statements of the same fact and have to agree.
|
|
63
|
+
|
|
64
|
+
// <ActivityIndicator>. React Native's JavaScript writes the 20pt or 36pt
|
|
65
|
+
// box into the view's style, so the shadow node needs no measurement of
|
|
66
|
+
// its own; what the host draws inside it is a spinner.
|
|
67
|
+
registry->add(concreteComponentDescriptorProvider<ActivityIndicatorViewComponentDescriptor>());
|
|
68
|
+
// <Switch>. The descriptor is React Native's iOS one -- portable C++
|
|
69
|
+
// apart from a `measureContent` that instantiates a UISwitch, which
|
|
70
|
+
// core/DesktopControls.cpp replaces with a constant so a switch is the
|
|
71
|
+
// same size on all three desktops.
|
|
72
|
+
registry->add(concreteComponentDescriptorProvider<SwitchComponentDescriptor>());
|
|
73
|
+
// <Modal>. Not a second window: the shadow node is a root-kind node sized
|
|
74
|
+
// from its state and positioned absolutely, so a modal is an overlay
|
|
75
|
+
// filling the surface -- which is also what it is on the web. The host
|
|
76
|
+
// commits the window's size into that state; see
|
|
77
|
+
// core/DesktopControls.h's modalScreenSizeNeedsUpdate for why it must.
|
|
78
|
+
registry->add(concreteComponentDescriptorProvider<ModalHostViewComponentDescriptor>());
|
|
79
|
+
// <RefreshControl>. The spinner a scroll view shows while it refreshes.
|
|
80
|
+
// The gesture that starts it is in core/PullToRefresh.h, because a
|
|
81
|
+
// desktop has no rubber band to release.
|
|
82
|
+
registry->add(concreteComponentDescriptorProvider<PullToRefreshViewComponentDescriptor>());
|
|
83
|
+
// What React Native substitutes for a component no platform registered.
|
|
84
|
+
// Registering it is what turns "nothing happens" into a mounted view the
|
|
85
|
+
// tree dump can show, and it is what the comments above mean when they
|
|
86
|
+
// say the substitution is silent.
|
|
87
|
+
registry->add(concreteComponentDescriptorProvider<UnimplementedNativeViewComponentDescriptor>());
|
|
88
|
+
// React DevTools' element highlighter. It draws nothing here yet -- the
|
|
89
|
+
// highlight arrives as a command rather than as props -- but a DevTools
|
|
90
|
+
// session mounts one, and an unregistered component in the tree is a
|
|
91
|
+
// blank rectangle in the middle of the app.
|
|
92
|
+
registry->add(concreteComponentDescriptorProvider<DebuggingOverlayComponentDescriptor>());
|
|
93
|
+
|
|
94
|
+
return registry;
|
|
95
|
+
}();
|
|
96
|
+
return providerRegistry->createComponentDescriptorRegistry(
|
|
97
|
+
{eventDispatcher, contextContainer, nullptr});
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
} // namespace facebook::react
|