Skip to content

Commit 08b45c4

Browse files
pchampioDrakirus
authored and
Drakirus
committed
🍎 MacOS Support, HighDPI Support.
More Option for window/engine
1 parent b1e0679 commit 08b45c4

File tree

7 files changed

+128
-36
lines changed

7 files changed

+128
-36
lines changed

README.md

+47-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ for desktop
1212
This project doesn't compete with
1313
[this](https://github.com/google/flutter-desktop-embedding) awesome one.
1414
The purpose of this project is to support the
15-
[Flutter](https://github.com/flutter/flutter) framework on Windows, macOS, and
15+
[Flutter](https://github.com/flutter/flutter) framework on Windows, MacOS, and
1616
Linux using a **SINGLE** code base.
1717

1818
[**GLFW**](https://github.com/go-gl/glfw) fits the job because it
@@ -58,11 +58,11 @@ cd ../..
5858
# Download the share library (CORRESPONDING to the Flutter's version shown above)
5959
wget https://storage.googleapis.com/flutter_infra/flutter/af42b6dc95bd9f719e43c4e9f29a00640f0f0bba/linux-x64/linux-x64-embedder -O .build/temp.zip
6060

61-
# Move the share library
62-
unzip .build/temp.zip -x flutter_embedder.h && mv libflutter_engine.so flutter/library/linux/
61+
# Extract the share library
62+
unzip .build/temp.zip -x flutter_embedder.h
6363

6464
# REQUIRED: When using `go build` or `go run main.go`, the go library need to know where to look for the share library
65-
export CGO_LDFLAGS="-L${PWD}/flutter/library/linux"
65+
export CGO_LDFLAGS="-L${PWD}"
6666

6767
# If you `go build`, the share library must stay in the same path, relative to the go binary
6868

@@ -118,6 +118,48 @@ go run main.go
118118

119119
</details>
120120

121+
<details>
122+
<summary> :package: :checkered_flag: MacOS</summary>
123+
<h4>From binaries</h4>
124+
Check out the <a href="https://github.com/Drakirus/go-flutter-desktop-embedder/releases">Release</a> page for prebuilt versions.
125+
126+
<h4>From source</h4>
127+
128+
Go read first: [go-gl/glfw](https://github.com/go-gl/glfw/)
129+
130+
131+
```bash
132+
# Clone
133+
git clone https://github.com/Drakirus/go-flutter-desktop-embedder.git
134+
cd go-flutter-desktop-embedder
135+
136+
# Build the flutter simpleDemo project
137+
cd example/simpleDemo/
138+
cd flutter_project/demo/
139+
flutter build bundle
140+
cd ../..
141+
142+
# Download the share library (CORRESPONDING to the Flutter's version shown above)
143+
wget https://storage.googleapis.com/flutter_infra/flutter/af42b6dc95bd9f719e43c4e9f29a00640f0f0bba/darwin-x64/FlutterEmbedder.framework.zip -O .build/temp.zip
144+
145+
# Move the share library
146+
unzip .build/temp.zip -d .build && unzip .build/FlutterEmbedder.framework.zip -d .build/FlutterEmbedder.framework
147+
mv .build/FlutterEmbedder.framework .
148+
149+
# REQUIRED: When using `go build` or `go run main.go`, the go library need to know where to look for the share library
150+
export CGO_LDFLAGS="-F${PWD} -Wl,-rpath,@executable_path"
151+
152+
# If you `go build`, the share library must stay in the same path, relative to the go binary
153+
154+
# Get the libraries
155+
go get -u -v github.com/Drakirus/go-flutter-desktop-embedder
156+
157+
# Make sure the path in "main.go" to the `icudtl.dat` is correct.
158+
# Build the example project
159+
go build
160+
```
161+
162+
</details>
121163

122164

123165
## Flutter Demos Projects
@@ -128,7 +170,7 @@ The examples are available [here](./example/)
128170

129171
- [x] Linux :penguin:
130172
- [x] Windows :checkered_flag:
131-
- [ ] MacOS :apple:
173+
- [x] MacOS :apple:
132174
- [x] Text input
133175
- [ ] Plugins
134176
- [x] Importable go library

example/stocks/flutter/library/linux/.gitignore

-2
This file was deleted.

example/stocks/main.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ func main() {
1818

1919
options := []gutter.Option{
2020
gutter.OptionAssetPath("flutter_project/stocks/build/flutter_assets"),
21-
gutter.OptionICUDataPath("/opt/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat"),
21+
// gutter.OptionICUDataPath("/opt/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat"), // Linux (arch)
22+
gutter.OptionICUDataPath("./FlutterEmbedder.framework/Resources/icudtl.dat"), // OSX
23+
gutter.OptionWindowDimension(800, 600),
2224
gutter.OptionWindowInitializer(setIcon),
25+
gutter.OptionPixelRatio(1.9),
26+
gutter.OptionVmArguments([]string{"--dart-non-checked-mode", "--observatory-port=50300"}),
2327
}
2428

2529
if err = gutter.Run(options...); err != nil {

flutter/build.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ package flutter
44
// Linux Build Tags
55
// ----------------
66
#cgo linux CFLAGS: -I${SRCDIR}/library
7-
#cgo linux LDFLAGS: -lflutter_engine -Wl,-rpath,$ORIGIN/flutter/library/linux
7+
#cgo linux LDFLAGS: -lflutter_engine -Wl,-rpath,$ORIGIN
88
99
// Windows Build Tags
1010
// ----------------
1111
#cgo windows CFLAGS: -I${SRCDIR}/library
1212
#cgo windows LDFLAGS: -lflutter_engine
1313
14+
// Darwin Build Tags
15+
// ----------------
16+
#cgo darwin CFLAGS: -I${SRCDIR}/library
17+
#cgo darwin LDFLAGS: -framework FlutterEmbedder
18+
1419
*/
1520
import "C"
1621

flutter/flutter.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package flutter
22

33
// #include "flutter_embedder.h"
4-
// FlutterResult runFlutter(uintptr_t window, FlutterEngine *engine, FlutterProjectArgs * Args);
4+
// FlutterResult runFlutter(uintptr_t window, FlutterEngine *engine, FlutterProjectArgs * Args,
5+
// const char *const * vmArgs, int nVmAgrs);
6+
// char** makeCharArray(int size);
7+
// void setArrayString(char **a, char *s, int n);
58
import "C"
69
import (
710
"encoding/json"
@@ -41,12 +44,13 @@ type EngineOpenGL struct {
4144
FPlatfromMessage func(message PlatformMessage, window unsafe.Pointer) bool
4245

4346
// Engine arguments
47+
PixelRatio float64
4448
AssetsPath *CharExportedType
4549
IcuDataPath *CharExportedType
4650
}
4751

4852
// Run launches the Flutter Engine in a background thread.
49-
func (flu *EngineOpenGL) Run(window uintptr) Result {
53+
func (flu *EngineOpenGL) Run(window uintptr, vmArgs []string) Result {
5054

5155
globalFlutterOpenGL = *flu
5256

@@ -59,7 +63,12 @@ func (flu *EngineOpenGL) Run(window uintptr) Result {
5963

6064
args.struct_size = C.size_t(unsafe.Sizeof(args))
6165

62-
res := C.runFlutter(C.uintptr_t(window), &flu.Engine, &args)
66+
cVmArgs := C.makeCharArray(C.int(len(vmArgs)))
67+
for i, s := range vmArgs {
68+
C.setArrayString(cVmArgs, C.CString(s), C.int(i))
69+
}
70+
71+
res := C.runFlutter(C.uintptr_t(window), &flu.Engine, &args, cVmArgs, C.int(len(vmArgs)))
6372
if flu.Engine == nil {
6473
return KInvalidArguments
6574
}

flutter/flutter_helper.c

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

2-
#include "library/flutter_embedder.h"
2+
#include "library/flutter_embedder.h"
3+
#include <stdlib.h>
4+
35

46
// C proxies def
57
bool proxy_make_current(void *v);
@@ -12,7 +14,8 @@ bool proxy_on_platform_message(FlutterPlatformMessage *message,
1214
void *window);
1315

1416
// C helper
15-
FlutterResult runFlutter(uintptr_t window, FlutterEngine *engine, FlutterProjectArgs * Args){
17+
FlutterResult runFlutter(uintptr_t window, FlutterEngine *engine, FlutterProjectArgs * Args,
18+
const char *const * vmArgs, int nVmAgrs) {
1619

1720
FlutterRendererConfig config = {};
1821
config.type = kOpenGL;
@@ -25,16 +28,18 @@ FlutterResult runFlutter(uintptr_t window, FlutterEngine *engine, FlutterProject
2528
config.open_gl.fbo_callback = proxy_fbo_callback;
2629
config.open_gl.make_resource_current = proxy_make_resource_current;
2730

28-
const char *args_arr[] = {
29-
"",
30-
"--dart-non-checked-mode",
31-
NULL,
32-
};
33-
34-
Args->command_line_argc = 2;
35-
Args->command_line_argv = args_arr;
31+
Args->command_line_argc = nVmAgrs;
32+
Args->command_line_argv = vmArgs;
3633
Args->platform_message_callback = (FlutterPlatformMessageCallback)proxy_on_platform_message;
3734

3835
return FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, Args, (void*)window, engine);
3936
}
4037

38+
char** makeCharArray(int size) {
39+
return calloc(sizeof(char*), size);
40+
}
41+
42+
void setArrayString(char **a, char *s, int n) {
43+
a[n] = s;
44+
}
45+

gutter.go

+43-14
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,43 @@ func OptionICUDataPath(p string) Option {
2929
}
3030
}
3131

32+
// OptionVmArguments specify the arguments to the Dart VM.
33+
func OptionVmArguments(a []string) Option {
34+
return func(c *config) {
35+
// First should be argument is argv[0]
36+
c.VmArguments = append([]string{""}, a...)
37+
}
38+
}
39+
40+
// OptionWindowDimension specify the startup's dimention of the window.
41+
func OptionWindowDimension(x int, y int) Option {
42+
return func(c *config) {
43+
c.WindowDimension.x = x
44+
c.WindowDimension.y = y
45+
}
46+
}
47+
3248
// OptionWindowInitializer allow initializing the window.
3349
func OptionWindowInitializer(ini func(*glfw.Window) error) Option {
3450
return func(c *config) {
3551
c.WindowInitializer = ini
3652
}
3753
}
3854

55+
// OptionPixelRatio specify the scale factor for the physical screen.
56+
func OptionPixelRatio(ratio float64) Option {
57+
return func(c *config) {
58+
c.PixelRatio = ratio
59+
}
60+
}
61+
3962
type config struct {
63+
WindowDimension struct {x int; y int}
4064
AssetPath string
4165
ICUDataPath string
4266
WindowInitializer func(*glfw.Window) error
67+
PixelRatio float64
68+
VmArguments []string
4369
}
4470

4571
func (t config) merge(options ...Option) config {
@@ -64,7 +90,8 @@ func Run(options ...Option) (err error) {
6490
}
6591
defer glfw.Terminate()
6692

67-
if window, err = glfw.CreateWindow(800, 600, "Loading..", nil, nil); err != nil {
93+
window, err = glfw.CreateWindow(c.WindowDimension.x, c.WindowDimension.y, "Loading..", nil, nil)
94+
if err != nil {
6895
return err
6996
}
7097
defer window.Destroy()
@@ -73,7 +100,7 @@ func Run(options ...Option) (err error) {
73100
return err
74101
}
75102

76-
engine := runFlutter(window, c.AssetPath, c.ICUDataPath)
103+
engine := runFlutter(window, c)
77104

78105
defer engine.Shutdown()
79106

@@ -91,11 +118,13 @@ func glfwCursorPositionCallbackAtPhase(
91118
window *glfw.Window, phase flutter.PointerPhase,
92119
x float64, y float64,
93120
) {
94-
121+
winWidth, _ := window.GetSize()
122+
frameBuffWidth, _ := window.GetFramebufferSize()
123+
contentScale := float64(frameBuffWidth / winWidth)
95124
event := flutter.PointerEvent{
96125
Phase: phase,
97-
X: x,
98-
Y: y,
126+
X: x * contentScale,
127+
Y: y * contentScale,
99128
Timestamp: time.Now().UnixNano() / int64(time.Millisecond),
100129
}
101130

@@ -185,13 +214,12 @@ func glfwKeyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Act
185214
}
186215

187216
func glfwWindowSizeCallback(window *glfw.Window, width int, height int) {
217+
flutterOGL := *(*flutter.EngineOpenGL)(window.GetUserPointer())
188218
event := flutter.WindowMetricsEvent{
189219
Width: width,
190220
Height: height,
191-
PixelRatio: 1.2,
221+
PixelRatio: flutterOGL.PixelRatio,
192222
}
193-
194-
flutterOGL := *(*flutter.EngineOpenGL)(window.GetUserPointer())
195223
flutterOGL.EngineSendWindowMetricsEvent(event)
196224
}
197225

@@ -202,12 +230,12 @@ func glfwCharCallback(w *glfw.Window, char rune) {
202230
}
203231

204232
// Flutter Engine
205-
func runFlutter(window *glfw.Window, assetsPath string, icuDataPath string) *flutter.EngineOpenGL {
233+
func runFlutter(window *glfw.Window, c config) *flutter.EngineOpenGL {
206234

207235
flutterOGL := flutter.EngineOpenGL{
208236
// Engine arguments
209-
AssetsPath: (*flutter.CharExportedType)(C.CString(assetsPath)),
210-
IcuDataPath: (*flutter.CharExportedType)(C.CString(icuDataPath)),
237+
AssetsPath: (*flutter.CharExportedType)(C.CString(c.AssetPath)),
238+
IcuDataPath: (*flutter.CharExportedType)(C.CString(c.ICUDataPath)),
211239
// Render callbacks
212240
FMakeCurrent: func(v unsafe.Pointer) bool {
213241
w := glfw.GoWindow(v)
@@ -231,14 +259,15 @@ func runFlutter(window *glfw.Window, assetsPath string, icuDataPath string) *flu
231259
},
232260
// Messaging (TextInput)
233261
FPlatfromMessage: onPlatformMessage,
262+
PixelRatio: c.PixelRatio,
234263
}
235264

236265
state.notifyState = func() {
237266
// log.Printf("Text: Sending to the flutter engine %v", state)
238267
updateEditingState(window)
239268
}
240269

241-
result := flutterOGL.Run(window.GLFWWindow())
270+
result := flutterOGL.Run(window.GLFWWindow(), c.VmArguments)
242271

243272
if result != flutter.KSuccess {
244273
window.Destroy()
@@ -247,11 +276,11 @@ func runFlutter(window *glfw.Window, assetsPath string, icuDataPath string) *flu
247276

248277
window.SetUserPointer(unsafe.Pointer(&flutterOGL))
249278

250-
width, height := window.GetSize()
279+
width, height := window.GetFramebufferSize()
251280
glfwWindowSizeCallback(window, width, height)
252281

253282
window.SetKeyCallback(glfwKeyCallback)
254-
window.SetSizeCallback(glfwWindowSizeCallback)
283+
window.SetFramebufferSizeCallback(glfwWindowSizeCallback)
255284
window.SetMouseButtonCallback(glfwMouseButtonCallback)
256285
window.SetCharCallback(glfwCharCallback)
257286
return &flutterOGL

0 commit comments

Comments
 (0)