Skip to content

Commit bab6623

Browse files
committed
Initial implementation of a Flutter embedder that starts an application and sets up EGL successfully.
0 parents  commit bab6623

10 files changed

+762
-0
lines changed

.clang-format

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
BasedOnStyle: Chromium
3+
Standard: Cpp11
4+
SortIncludes: true
5+
...

.gitignore

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.idea/
2+
.vagrant/
3+
.sconsign.dblite
4+
.svn/
5+
6+
.DS_Store
7+
*.swp
8+
*.lock
9+
profile
10+
11+
DerivedData/
12+
build/
13+
14+
*.pbxuser
15+
*.mode1v3
16+
*.mode2v3
17+
*.perspectivev3
18+
19+
!default.pbxuser
20+
!default.mode1v3
21+
!default.mode2v3
22+
!default.perspectivev3
23+
24+
xcuserdata
25+
*.xcscmblueprint
26+
27+
*.moved-aside
28+
29+
*.pyc
30+
*sync/
31+
Icon?
32+
.tags*
33+
34+
*.sublime-workspace
35+
cmake-*/

CMakeLists.txt

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2018 The Flutter Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
cmake_minimum_required(VERSION 3.5.2)
6+
7+
project(flutter_wayland)
8+
9+
set(FLUTTER_ENGINE_SHA 949fb0fb4cbe4bf4753d68264b9d9cc966ba7058)
10+
11+
set(FLUTTER_EMBEDDER_ARTIFACTS_ZIP ${CMAKE_BINARY_DIR}/flutter_embedder_${FLUTTER_ENGINE_SHA}.zip)
12+
set(FLUTTER_ARTIFACTS_ZIP ${CMAKE_BINARY_DIR}/flutter_artifact_${FLUTTER_ENGINE_SHA}.zip)
13+
set(FLUTTER_BUCKET_BASE "https://storage.googleapis.com/flutter_infra/flutter")
14+
15+
# Download and setup the Flutter Engine.
16+
if(NOT EXISTS ${FLUTTER_EMBEDDER_ARTIFACTS_ZIP})
17+
file(DOWNLOAD
18+
${FLUTTER_BUCKET_BASE}/${FLUTTER_ENGINE_SHA}/linux-x64/linux-x64-embedder
19+
${FLUTTER_EMBEDDER_ARTIFACTS_ZIP}
20+
SHOW_PROGRESS
21+
)
22+
execute_process(
23+
COMMAND ${CMAKE_COMMAND} -E tar xzf ${FLUTTER_EMBEDDER_ARTIFACTS_ZIP}
24+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
25+
)
26+
endif()
27+
28+
if(NOT EXISTS ${FLUTTER_ARTIFACTS_ZIP})
29+
file(DOWNLOAD
30+
${FLUTTER_BUCKET_BASE}/${FLUTTER_ENGINE_SHA}/linux-x64/artifacts.zip
31+
${FLUTTER_ARTIFACTS_ZIP}
32+
SHOW_PROGRESS
33+
)
34+
execute_process(
35+
COMMAND ${CMAKE_COMMAND} -E tar xzf ${FLUTTER_ARTIFACTS_ZIP}
36+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
37+
)
38+
endif()
39+
40+
find_package(PkgConfig)
41+
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
42+
pkg_check_modules(WAYLAND_EGL REQUIRED wayland-egl)
43+
pkg_check_modules(EGL REQUIRED egl)
44+
45+
# Executable
46+
file(GLOB_RECURSE FLUTTER_WAYLAND_SRC
47+
"src/*.cc"
48+
"src/*.h"
49+
)
50+
51+
link_directories(${CMAKE_BINARY_DIR})
52+
53+
add_executable(flutter_wayland ${FLUTTER_WAYLAND_SRC})
54+
55+
target_link_libraries(flutter_wayland
56+
${WAYLAND_CLIENT_LIBRARIES}
57+
${WAYLAND_EGL_LIBRARIES}
58+
${EGL_LIBRARIES}
59+
flutter_engine
60+
)
61+
62+
target_include_directories(flutter_wayland
63+
PRIVATE
64+
${WAYLAND_CLIENT_INCLUDE_DIRS}
65+
${WAYLAND_EGL_INCLUDE_DIRS}
66+
${EGL_INCLUDE_DIRS}
67+
${CMAKE_BINARY_DIR}
68+
)

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Flutter Wayland
2+
============
3+
4+
A Flutter Embedder that talks to Wayland.

src/flutter_application.cc

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Copyright 2018 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter_application.h"
6+
7+
#include <sys/types.h>
8+
#include <unistd.h>
9+
10+
#include <chrono>
11+
#include <sstream>
12+
#include <vector>
13+
14+
namespace flutter {
15+
16+
static_assert(FLUTTER_ENGINE_VERSION == 1, "");
17+
18+
static const char* kICUDataFileName = "icudtl.dat";
19+
20+
static std::string GetExecutableDirectory() {
21+
char executable_path[1024] = {0};
22+
std::stringstream stream;
23+
stream << "/proc/" << getpid() << "/exe";
24+
auto path = stream.str();
25+
auto executable_path_size =
26+
::readlink(path.c_str(), executable_path, sizeof(executable_path));
27+
if (executable_path_size <= 0) {
28+
return "";
29+
}
30+
31+
auto path_string =
32+
std::string{executable_path, static_cast<size_t>(executable_path_size)};
33+
34+
auto found = path_string.find_last_of('/');
35+
36+
if (found == std::string::npos) {
37+
return "";
38+
}
39+
40+
return path_string.substr(0, found + 1);
41+
}
42+
43+
static std::string GetICUDataPath() {
44+
auto exe_dir = GetExecutableDirectory();
45+
if (exe_dir == "") {
46+
return "";
47+
}
48+
std::stringstream stream;
49+
stream << exe_dir << kICUDataFileName;
50+
51+
auto icu_path = stream.str();
52+
53+
if (::access(icu_path.c_str(), R_OK) != 0) {
54+
FLWAY_ERROR << "Could not find " << icu_path << std::endl;
55+
return "";
56+
}
57+
58+
return icu_path;
59+
}
60+
61+
FlutterApplication::FlutterApplication() {
62+
FlutterRendererConfig config = {};
63+
config.type = kSoftware;
64+
config.software.struct_size = sizeof(FlutterSoftwareRendererConfig);
65+
config.software.surface_present_callback =
66+
&FlutterApplication::PresentSurface;
67+
68+
// TODO: Pipe this in through command line args.
69+
#define MY_PROJECT \
70+
"/home/buzzy/VersionControlled/flutter/examples/flutter_gallery"
71+
72+
std::vector<const char*> engine_command_line_args = {
73+
"--disable-observatory", //
74+
"--dart-non-checked-mode", //
75+
};
76+
77+
auto icu_data_path = GetICUDataPath();
78+
79+
if (icu_data_path == "") {
80+
FLWAY_ERROR << "Could not find ICU data. It should be placed next to the "
81+
"executable but it wasn't there."
82+
<< std::endl;
83+
return;
84+
}
85+
86+
FlutterProjectArgs args = {
87+
.struct_size = sizeof(FlutterProjectArgs),
88+
.assets_path = MY_PROJECT "/build/flutter_assets",
89+
.main_path = "",
90+
.packages_path = "",
91+
.icu_data_path = icu_data_path.c_str(),
92+
.command_line_argc = static_cast<int>(engine_command_line_args.size()),
93+
.command_line_argv = engine_command_line_args.data(),
94+
};
95+
96+
FlutterEngine engine = nullptr;
97+
auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, // renderer
98+
&args, this, &engine_);
99+
100+
if (result != kSuccess) {
101+
FLWAY_ERROR << "Could not run the Flutter engine" << std::endl;
102+
return;
103+
}
104+
105+
valid_ = true;
106+
}
107+
108+
FlutterApplication::~FlutterApplication() {
109+
if (engine_ == nullptr) {
110+
return;
111+
}
112+
113+
auto result = FlutterEngineShutdown(engine_);
114+
115+
if (result != kSuccess) {
116+
FLWAY_ERROR << "Could not shutdown the Flutter engine." << std::endl;
117+
}
118+
}
119+
120+
bool FlutterApplication::IsValid() const {
121+
return valid_;
122+
}
123+
124+
bool FlutterApplication::SetWindowSize(size_t width, size_t height) {
125+
FlutterWindowMetricsEvent event = {};
126+
event.struct_size = sizeof(event);
127+
event.width = width;
128+
event.height = height;
129+
event.pixel_ratio = 1.0;
130+
return FlutterEngineSendWindowMetricsEvent(engine_, &event) == kSuccess;
131+
}
132+
133+
void FlutterApplication::ProcessEvents() {
134+
__FlutterEngineFlushPendingTasksNow();
135+
}
136+
137+
bool FlutterApplication::PresentSurface(void* user_data,
138+
const void* allocation,
139+
size_t row_bytes,
140+
size_t height) {
141+
return reinterpret_cast<FlutterApplication*>(user_data)->PresentSurface(
142+
allocation, row_bytes, height);
143+
}
144+
145+
void FlutterApplication::SetOnPresentCallback(PresentCallback callback) {
146+
std::lock_guard<std::mutex> lock(mutex_);
147+
present_callback_ = callback;
148+
}
149+
150+
bool FlutterApplication::PresentSurface(const void* allocation,
151+
size_t row_bytes,
152+
size_t height) {
153+
std::lock_guard<std::mutex> lock(mutex_);
154+
if (!present_callback_) {
155+
FLWAY_ERROR << "Present callback was not set." << std::endl;
156+
return false;
157+
}
158+
present_callback_(allocation, row_bytes, height);
159+
return true;
160+
}
161+
162+
bool FlutterApplication::SendPointerEvent(int button, int x, int y) {
163+
if (!valid_) {
164+
FLWAY_ERROR << "Pointer events on an invalid application." << std::endl;
165+
return false;
166+
}
167+
168+
// Simple hover event. Nothing to do.
169+
if (last_button_ == 0 && button == 0) {
170+
return true;
171+
}
172+
173+
FlutterPointerPhase phase = kCancel;
174+
175+
if (last_button_ == 0 && button != 0) {
176+
phase = kDown;
177+
} else if (last_button_ == button) {
178+
phase = kMove;
179+
} else {
180+
phase = kUp;
181+
}
182+
183+
last_button_ = button;
184+
return SendFlutterPointerEvent(phase, x, y);
185+
}
186+
187+
bool FlutterApplication::SendFlutterPointerEvent(FlutterPointerPhase phase,
188+
double x,
189+
double y) {
190+
FlutterPointerEvent event = {};
191+
event.struct_size = sizeof(event);
192+
event.phase = phase;
193+
event.x = x;
194+
event.y = y;
195+
event.timestamp =
196+
std::chrono::duration_cast<std::chrono::microseconds>(
197+
std::chrono::high_resolution_clock::now().time_since_epoch())
198+
.count();
199+
return FlutterEngineSendPointerEvent(engine_, &event, 1) == kSuccess;
200+
}
201+
202+
} // namespace flutter

src/flutter_application.h

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2018 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include <flutter_embedder.h>
8+
9+
#include <functional>
10+
#include <map>
11+
#include <mutex>
12+
13+
#include "macros.h"
14+
15+
namespace flutter {
16+
17+
class FlutterApplication {
18+
public:
19+
FlutterApplication();
20+
21+
~FlutterApplication();
22+
23+
bool IsValid() const;
24+
25+
void ProcessEvents();
26+
27+
bool SetWindowSize(size_t width, size_t height);
28+
29+
bool SendPointerEvent(int button, int x, int y);
30+
31+
using PresentCallback = std::function<
32+
void(const void* allocation, size_t row_bytes, size_t height)>;
33+
void SetOnPresentCallback(PresentCallback callback);
34+
35+
private:
36+
bool valid_;
37+
FlutterEngine engine_ = nullptr;
38+
std::mutex mutex_;
39+
PresentCallback present_callback_;
40+
int last_button_ = 0;
41+
42+
static bool PresentSurface(void* user_data,
43+
const void* allocation,
44+
size_t row_bytes,
45+
size_t height);
46+
47+
bool PresentSurface(const void* allocation, size_t row_bytes, size_t height);
48+
49+
bool SendFlutterPointerEvent(FlutterPointerPhase phase, double x, double y);
50+
51+
FLWAY_DISALLOW_COPY_AND_ASSIGN(FlutterApplication);
52+
};
53+
54+
} // namespace flutter

src/macros.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include <iostream>
8+
9+
#define FLWAY_DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete;
10+
11+
#define FLWAY_DISALLOW_ASSIGN(TypeName) \
12+
void operator=(const TypeName&) = delete;
13+
14+
#define FLWAY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
15+
FLWAY_DISALLOW_COPY(TypeName) \
16+
FLWAY_DISALLOW_ASSIGN(TypeName)
17+
18+
#define __FLWAY_LINE_PREFIX << __FILE__ << ":" << __LINE__ << ": "
19+
#define FLWAY_LOG std::cout << "LOG: " __FLWAY_LINE_PREFIX
20+
#define FLWAY_ERROR std::cerr << "ERROR: " __FLWAY_LINE_PREFIX

0 commit comments

Comments
 (0)