Skip to content

Commit 885160b

Browse files
committed
Use Swift C++ interop to more closely integrate with Flutter engine
1 parent d12d24a commit 885160b

File tree

11 files changed

+116
-78
lines changed

11 files changed

+116
-78
lines changed

Package.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var targetPluginUsages = [Target.PluginUsage]()
1313
var platformCxxSettings: [CXXSetting] = []
1414
var platformSwiftSettings: [SwiftSetting] = [.swiftLanguageMode(.v5)]
1515

16-
func tryGuessSwiftLibRoot() -> String {
16+
func tryGuessSwiftRoot() -> String {
1717
let task = Process()
1818
task.executableURL = URL(fileURLWithPath: "/bin/sh")
1919
task.arguments = ["-c", "which swift"]
@@ -22,13 +22,14 @@ func tryGuessSwiftLibRoot() -> String {
2222
try task.run()
2323
let outputData = (task.standardOutput as! Pipe).fileHandleForReading.readDataToEndOfFile()
2424
let path = URL(fileURLWithPath: String(decoding: outputData, as: UTF8.self))
25-
return path.deletingLastPathComponent().path + "/../lib/swift"
25+
return path.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent()
26+
.path
2627
} catch {
27-
return "/usr/lib/swift"
28+
return ""
2829
}
2930
}
3031

31-
let SwiftLibRoot = tryGuessSwiftLibRoot()
32+
let SwiftRoot = tryGuessSwiftRoot()
3233
var FlutterPlatform: String
3334
var FlutterUnsafeLinkerFlags: [String] = []
3435

@@ -231,10 +232,19 @@ enum FlutterELinuxBackendType {
231232

232233
let FlutterELinuxBackend = FlutterELinuxBackendType.defaultBackend
233234

235+
let CxxIncludeDirs: [String] = [
236+
"\(SwiftRoot)/usr/include",
237+
"\(SwiftRoot)/usr/lib/swift",
238+
"/usr/include/drm",
239+
]
240+
241+
let CxxIncludeFlags = CxxIncludeDirs.flatMap { ["-I", $0] }
242+
234243
platformSwiftSettings += [
235244
.define("DISPLAY_BACKEND_TYPE_\(FlutterELinuxBackend.displayBackendType)"),
236245
.define("FLUTTER_TARGET_BACKEND_\(FlutterELinuxBackend.flutterTargetBackend)"),
237246
.interoperabilityMode(.Cxx),
247+
.unsafeFlags(CxxIncludeFlags),
238248
]
239249

240250
targets += [
@@ -401,7 +411,7 @@ targets += [
401411
.headerSearchPath("flutter-embedded-linux/src/third_party/rapidjson/include"),
402412
// FIXME: .cxxLanguageStandard breaks Foundation compile
403413
// FIXME: include path for swift/bridging.h
404-
.unsafeFlags(["-pthread", "-I", SwiftLibRoot, "-I", "/usr/include/drm", "-std=c++17"]),
414+
.unsafeFlags(["-pthread", "-std=c++17"] + CxxIncludeFlags),
405415
],
406416
linkerSettings: [
407417
// .unsafeFlags(["-pthread"]),
@@ -443,6 +453,8 @@ platformCxxSettings += [
443453
.headerSearchPath(
444454
"../CxxFlutterSwift/flutter-embedded-linux/src/flutter/shell/platform/common/client_wrapper/include"
445455
),
456+
.headerSearchPath("../CxxFlutterSwift/flutter-embedded-linux/src/third_party/rapidjson/include"),
457+
.unsafeFlags(CxxIncludeFlags),
446458
]
447459

448460
#else

Sources/CxxFlutterSwift/include/CxxFlutterSwift.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2023-2024 PADL Software Pty Ltd
2+
// Copyright (c) 2023-2025 PADL Software Pty Ltd
33
//
44
// Licensed under the Apache License, Version 2.0 (the License);
55
// you may not use this file except in compliance with the License.
@@ -21,8 +21,10 @@
2121

2222
#include <flutter_messenger.h>
2323
#include <flutter_elinux.h>
24+
#include <flutter_elinux_engine.h>
25+
#include <flutter_elinux_state.h>
26+
#include <flutter_elinux_view.h>
2427
#include <flutter_plugin_registrar.h>
25-
// #include <flutter_elinux_state.h>
2628
#include <flutter_platform_views.h>
2729

2830
#ifdef __cplusplus
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module CxxFlutterSwift {
2+
header "CxxFlutterSwift.h"
3+
}

Sources/FlutterSwift/Channel/FlutterEventChannel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public final class FlutterEventChannel: _FlutterBinaryMessengerConnectionReprese
3838
public let codec: FlutterMessageCodec
3939
public let priority: TaskPriority?
4040

41-
private typealias EventStreamTask = Task<Void, Never>
41+
private typealias EventStreamTask = Task<(), Never>
4242

4343
private let _connection: ManagedAtomic<FlutterBinaryMessengerConnection>
4444
private let tasks: ManagedCriticalState<[String: EventStreamTask]>

Sources/FlutterSwift/Client/FlutterEngine.swift

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2023-2024 PADL Software Pty Ltd
2+
// Copyright (c) 2023-2025 PADL Software Pty Ltd
33
//
44
// Licensed under the Apache License, Version 2.0 (the License);
55
// you may not use this file except in compliance with the License.
@@ -17,12 +17,13 @@
1717
#if os(Linux) && canImport(Glibc)
1818
@_implementationOnly
1919
import CxxFlutterSwift
20+
import CxxStdlib
2021

2122
public final class FlutterEngine: FlutterPluginRegistry, @unchecked Sendable {
22-
var engine: FlutterDesktopEngineRef! // strong or weak ref
2323
var pluginPublications = [String: Any]()
2424
let project: DartProject
2525
weak var viewController: FlutterViewController?
26+
private var engine: flutter.FlutterELinuxEngine! // strong or weak ref
2627
private var _binaryMessenger: FlutterDesktopMessenger!
2728
private var ownsEngine = true
2829
private var hasBeenRun = false
@@ -48,7 +49,8 @@ public final class FlutterEngine: FlutterPluginRegistry, @unchecked Sendable {
4849
)
4950
cStrings.withUnsafeMutableBufferPointer { pointer in
5051
properties.dart_entrypoint_argv = pointer.baseAddress
51-
self.engine = FlutterDesktopEngineCreate(&properties)
52+
let engine = FlutterDesktopEngineCreate(&properties)
53+
self.engine = unsafeBitCast(engine, to: flutter.FlutterELinuxEngine.self)
5254
self._binaryMessenger = FlutterDesktopMessenger(engine: self.engine)
5355
}
5456
}
@@ -61,6 +63,10 @@ public final class FlutterEngine: FlutterPluginRegistry, @unchecked Sendable {
6163
shutDown()
6264
}
6365

66+
private var _handle: FlutterDesktopEngineRef {
67+
unsafeBitCast(engine, to: FlutterDesktopEngineRef.self)
68+
}
69+
6470
// note we can't use public private(set) because we need the type to be FlutterDesktopMessenger!
6571
// in order for callbacks to work (otherwise self must be first initialized). But we want to
6672
// present a non-optional type to callers.
@@ -69,39 +75,31 @@ public final class FlutterEngine: FlutterPluginRegistry, @unchecked Sendable {
6975
}
7076

7177
public func run(entryPoint: String? = nil) -> Bool {
72-
if hasBeenRun {
73-
debugPrint("Cannot run an engine more than once.")
74-
return false
75-
}
76-
let runSucceeded = FlutterDesktopEngineRun(engine, entryPoint)
77-
if !runSucceeded {
78-
debugPrint("Failed to start engine.")
79-
}
80-
hasBeenRun = true
81-
return runSucceeded
78+
guard !hasBeenRun else { return false }
79+
hasBeenRun = engine.RunWithEntrypoint(entryPoint)
80+
return hasBeenRun
8281
}
8382

8483
public func shutDown() {
8584
pluginPublications.removeAll()
86-
if let engine, ownsEngine {
87-
FlutterDesktopEngineDestroy(engine)
85+
if engine != nil, ownsEngine {
86+
FlutterDesktopEngineDestroy(_handle)
8887
}
8988
engine = nil
9089
}
9190

9291
public func processMessages() -> UInt64 {
9392
precondition(engine != nil)
94-
return FlutterDesktopEngineProcessMessages(engine)
93+
return FlutterDesktopEngineProcessMessages(_handle)
9594
}
9695

9796
public func reloadSystemFonts() {
98-
precondition(engine != nil)
99-
FlutterDesktopEngineReloadSystemFonts(engine)
97+
engine.ReloadSystemFonts()
10098
}
10199

102100
func relinquishEngine() -> FlutterDesktopEngineRef {
103101
ownsEngine = false
104-
return engine
102+
return _handle
105103
}
106104

107105
public func registrar(for pluginKey: String) -> FlutterPluginRegistrar? {
@@ -116,5 +114,33 @@ public final class FlutterEngine: FlutterPluginRegistry, @unchecked Sendable {
116114
public func valuePublished(by pluginKey: String) -> Any? {
117115
pluginPublications[pluginKey]
118116
}
117+
118+
public var isRunning: Bool {
119+
engine.running()
120+
}
121+
122+
func onVsync(lastFrameTimeNS: UInt64, vsyncIntervalTimeNS: UInt64) {
123+
engine.OnVsync(lastFrameTimeNS, vsyncIntervalTimeNS)
124+
}
125+
126+
public var isImpellerEnabled: Bool {
127+
engine.IsImpellerEnabled()
128+
}
129+
130+
public func setSystemSettings(textScalingFactor: Float, enableHighContrast: Bool) {
131+
engine.SetSystemSettings(textScalingFactor, enableHighContrast)
132+
}
133+
134+
public func setView(_ view: FlutterView) {
135+
engine.SetView(view.view)
136+
}
137+
138+
func getRegistrar(pluginName: String) -> FlutterDesktopPluginRegistrarRef? {
139+
FlutterDesktopEngineGetPluginRegistrar(_handle, pluginName)
140+
}
141+
142+
var textureRegistrar: FlutterDesktopTextureRegistrarRef {
143+
FlutterDesktopEngineGetTextureRegistrar(_handle)
144+
}
119145
}
120146
#endif

Sources/FlutterSwift/Client/FlutterPlugin.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public final class FlutterDesktopPluginRegistrar: FlutterPluginRegistrar {
116116
) {
117117
self.engine = engine
118118
pluginKey = pluginName
119-
registrar = FlutterDesktopEngineGetPluginRegistrar(engine.engine, pluginName)
119+
registrar = engine.getRegistrar(pluginName: pluginName)
120120
FlutterDesktopPluginRegistrarSetDestructionHandlerBlock(registrar!) { _ in
121121
self.registrar = nil
122122
}
@@ -184,13 +184,17 @@ public struct FlutterDesktopTextureRegistrar {
184184
private let registrar: FlutterDesktopTextureRegistrarRef
185185

186186
public init(engine: FlutterEngine) {
187-
registrar = FlutterDesktopEngineGetTextureRegistrar(engine.engine)
187+
registrar = engine.textureRegistrar
188188
}
189189

190190
init?(plugin: FlutterDesktopPluginRegistrar) {
191191
guard let registrar = plugin.registrar else { return nil }
192192
self.registrar = FlutterDesktopRegistrarGetTextureRegistrar(registrar)
193193
}
194+
195+
public func markExternalTextureFrameAvailable(textureID: Int64) {
196+
FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable(registrar, textureID)
197+
}
194198
}
195199

196200
#endif

Sources/FlutterSwift/Client/FlutterView.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2023-2024 PADL Software Pty Ltd
2+
// Copyright (c) 2023-2025 PADL Software Pty Ltd
33
//
44
// Licensed under the Apache License, Version 2.0 (the License);
55
// you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@ import CxxFlutterSwift
2121
let kChannelName = "flutter/platform_views"
2222

2323
public struct FlutterView {
24-
let view: FlutterDesktopViewRef
24+
let view: flutter.FlutterELinuxView
2525
var platformViewsPluginRegistrar: FlutterPluginRegistrar?
2626
var platformViewsHandler: FlutterPlatformViewsPlugin?
2727
var viewController: FlutterViewController? {
@@ -38,16 +38,20 @@ public struct FlutterView {
3838
}
3939
}
4040

41-
init(_ view: FlutterDesktopViewRef) {
41+
init(_ view: flutter.FlutterELinuxView) {
4242
self.view = view
4343
}
4444

45+
init(_ view: FlutterDesktopViewRef) {
46+
self.init(unsafeBitCast(view, to: flutter.FlutterELinuxView.self))
47+
}
48+
4549
public func dispatchEvent() -> Bool {
46-
FlutterDesktopViewDispatchEvent(view)
50+
view.DispatchEvent()
4751
}
4852

4953
public var frameRate: Int32 {
50-
FlutterDesktopViewGetFrameRate(view)
54+
view.GetFrameRate()
5155
}
5256
}
5357
#endif

Sources/FlutterSwift/Client/FlutterViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public final class FlutterViewController {
145145

146146
public var view: FlutterView {
147147
didSet {
148-
FlutterDesktopEngineSetView(engine.engine, view.view)
148+
engine.setView(view)
149149
}
150150
}
151151

Sources/FlutterSwift/Client/FlutterWindow.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public struct FlutterWindow {
6363

6464
public func run() {
6565
let runLoop = RunLoop.main
66-
self.schedule(in: runLoop, forMode: .common)
66+
schedule(in: runLoop, forMode: .common)
6767
runLoop.run()
6868
}
6969
}

0 commit comments

Comments
 (0)