Skip to content

Commit a304a86

Browse files
authored
Merge GLFW library implementations (#194)
Merges the GLFW-based embedding implementations for Windows and Linux into a single shared implementation. At this point the implementations are largely identical, and having two copies is increasingly a maintenance burden. Originally they were separate since they were intended to be throw-away, and their development proceeded at different speeds. Now that they have reached parity, and there's a possibility that the GLFW implementation will be longer-lived than initially expected, having one copy that's testable on several platforms should simplify development.
1 parent 29c6a39 commit a304a86

File tree

12 files changed

+119
-483
lines changed

12 files changed

+119
-483
lines changed

example/linux/flutter_embedder_example.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#ifdef USE_FLATTENED_INCLUDES
2727
#include <flutter_desktop_embedding/embedder.h>
2828
#else
29-
#include <flutter_desktop_embedding/linux/embedder.h>
29+
#include <flutter_desktop_embedding/glfw/embedder.h>
3030
#endif
3131

3232
namespace {
@@ -53,7 +53,7 @@ std::string GetExecutableDirectory() {
5353
} // namespace
5454

5555
int main(int argc, char **argv) {
56-
if (!glfwInit()) {
56+
if (!flutter_desktop_embedding::FlutterInit()) {
5757
std::cerr << "Couldn't init GLFW" << std::endl;
5858
}
5959

@@ -78,7 +78,7 @@ int main(int argc, char **argv) {
7878
auto window = flutter_desktop_embedding::CreateFlutterWindowInSnapshotMode(
7979
640, 480, assets_path, icu_data_path, arguments);
8080
if (window == nullptr) {
81-
glfwTerminate();
81+
flutter_desktop_embedding::FlutterTerminate();
8282
return EXIT_FAILURE;
8383
}
8484

example/windows/GLFW Example.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Dynamic Library|x64'">
7373
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
7474
<IntDir>$(SolutionDir)bin\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
75-
<IncludePath>$(ProjectDir)..\..\library\windows\dependencies\;$(ProjectDir)..\..\;$(IncludePath);$(ProjectDir)..\..\library\windows\</IncludePath>
75+
<IncludePath>$(ProjectDir)..\..\library\windows\dependencies\;$(ProjectDir)..\..\;$(IncludePath);$(ProjectDir)..\..\library\windows\;$(ProjectDir)..\..\library\include\</IncludePath>
7676
<LibraryPath>$(ProjectDir)..\..\library\windows\dependencies\GLFW\;$(SolutionDir)bin\$(Platform)\$(Configuration)\GLFW Library\;$(LibraryPath)</LibraryPath>
7777
</PropertyGroup>
7878
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static Library|x64'">

example/windows/flutter_embedder_example.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include <iostream>
1616
#include <vector>
1717

18-
#include "embedder.h"
18+
#include "flutter_desktop_embedding/glfw/embedder.h"
1919

2020
int main(int argc, char **argv) {
2121
if (!flutter_desktop_embedding::FlutterInit()) {

library/BUILD.gn

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,22 @@ import("//build/packaging.gni")
1717
import("//library/engine.gni")
1818

1919
published_shared_library("flutter_embedder") {
20-
if (is_linux) {
21-
sources = [
22-
"linux/src/embedder.cc",
23-
]
20+
# GLFW embedding implementation.
21+
if (is_linux || is_win) {
2422
public = [
25-
"include/flutter_desktop_embedding/linux/embedder.h",
23+
"include/flutter_desktop_embedding/glfw/embedder.h",
24+
]
25+
sources = [
26+
"common/glfw/embedder.cc",
27+
"common/glfw/key_event_handler.cc",
28+
"common/glfw/key_event_handler.h",
29+
"common/glfw/keyboard_hook_handler.h",
30+
"common/glfw/text_input_plugin.cc",
31+
"common/glfw/text_input_plugin.h",
2632
]
2733
}
34+
35+
# Embedding-agnostic shared C++.
2836
if (is_linux || is_win) {
2937
sources += [
3038
"common/internal/engine_method_result.cc",
@@ -56,16 +64,6 @@ published_shared_library("flutter_embedder") {
5664
"include/flutter_desktop_embedding/plugin.h",
5765
]
5866
}
59-
# GLFW-specific code.
60-
if (is_linux || is_win) {
61-
sources += [
62-
"common/glfw/key_event_handler.cc",
63-
"common/glfw/key_event_handler.h",
64-
"common/glfw/keyboard_hook_handler.h",
65-
"common/glfw/text_input_plugin.cc",
66-
"common/glfw/text_input_plugin.h",
67-
]
68-
}
6967

7068
deps = [
7169
":fetch_flutter_engine",

library/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ $ sudo apt-get install libglfw3-dev libepoxy-dev libjsoncpp-dev libgtk-3-dev \
4949
#### Using the Library
5050

5151
Run `make` under `linux/`, then link `libflutter_embedder.so` into your
52-
binary. See [embedder.h](linux/include/flutter_desktop_embedding/embedder.h)
52+
binary. See [embedder.h](include/flutter_desktop_embedding/glfw/embedder.h)
5353
for details on calling into the library.
5454

5555
You will also need to link `libflutter_engine.so` into your binary.

library/linux/src/embedder.cc renamed to library/common/glfw/embedder.cc

Lines changed: 81 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,14 @@
1111
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
14-
#include <flutter_desktop_embedding/linux/embedder.h>
1514

16-
#include <X11/Xlib.h>
17-
#include <assert.h>
18-
#include <gtk/gtk.h>
15+
#include "library/include/flutter_desktop_embedding/glfw/embedder.h"
1916

17+
#include <assert.h>
2018
#include <algorithm>
2119
#include <chrono>
2220
#include <cstdlib>
2321
#include <iostream>
24-
#include <memory>
25-
#include <string>
2622

2723
#include <flutter_embedder.h>
2824

@@ -31,6 +27,12 @@
3127
#include "library/common/glfw/text_input_plugin.h"
3228
#include "library/common/internal/plugin_handler.h"
3329

30+
#ifdef __linux__
31+
// For plugin-compatible event handling (e.g., modal windows).
32+
#include <X11/Xlib.h>
33+
#include <gtk/gtk.h>
34+
#endif
35+
3436
// GLFW_TRUE & GLFW_FALSE are introduced since libglfw-3.3,
3537
// add definitions here to compile under the old versions.
3638
#ifndef GLFW_TRUE
@@ -51,67 +53,22 @@ struct FlutterEmbedderState {
5153
// deleted from the heap.
5254
std::vector<flutter_desktop_embedding::KeyboardHookHandler *>
5355
keyboard_hook_handlers;
56+
5457
// Handles raw key interactions from GLFW.
55-
// TODO: Move key_event_handler once
56-
// https://github.com/google/flutter-desktop-embedding/issues/102 is resolved.
58+
// TODO: Revisit ownership model once Issue #102 is resolved.
5759
std::unique_ptr<flutter_desktop_embedding::KeyEventHandler> key_event_handler;
5860
};
5961

6062
static constexpr char kDefaultWindowTitle[] = "Flutter";
6163

62-
// Callback forward declarations.
63-
static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode,
64-
int action, int mods);
65-
static void GLFWCharCallback(GLFWwindow *window, unsigned int code_point);
66-
static void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action,
67-
int mods);
68-
64+
// Retrieves state bag for the window in question from the GLFWWindow.
6965
static FlutterEmbedderState *GetSavedEmbedderState(GLFWwindow *window) {
7066
return reinterpret_cast<FlutterEmbedderState *>(
7167
glfwGetWindowUserPointer(window));
7268
}
7369

74-
// Flushes event queue and then assigns default window callbacks.
75-
static void GLFWAssignEventCallbacks(GLFWwindow *window) {
76-
glfwPollEvents();
77-
glfwSetKeyCallback(window, GLFWKeyCallback);
78-
glfwSetCharCallback(window, GLFWCharCallback);
79-
glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);
80-
}
81-
82-
// Clears default window events.
83-
static void GLFWClearEventCallbacks(GLFWwindow *window) {
84-
glfwSetKeyCallback(window, nullptr);
85-
glfwSetCharCallback(window, nullptr);
86-
glfwSetMouseButtonCallback(window, nullptr);
87-
}
88-
89-
static void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height) {
90-
FlutterWindowMetricsEvent event = {};
91-
event.struct_size = sizeof(event);
92-
event.width = width;
93-
event.height = height;
94-
event.pixel_ratio = 1.0;
95-
auto state = GetSavedEmbedderState(window);
96-
FlutterEngineSendWindowMetricsEvent(state->engine, &event);
97-
}
98-
99-
static void GLFWOnFlutterPlatformMessage(const FlutterPlatformMessage *message,
100-
void *user_data) {
101-
if (message->struct_size != sizeof(FlutterPlatformMessage)) {
102-
std::cerr << "Invalid message size received. Expected: "
103-
<< sizeof(FlutterPlatformMessage) << " but received "
104-
<< message->struct_size << std::endl;
105-
return;
106-
}
107-
108-
GLFWwindow *window = reinterpret_cast<GLFWwindow *>(user_data);
109-
auto state = GetSavedEmbedderState(window);
110-
state->plugin_handler->HandleMethodCallMessage(
111-
message, [window] { GLFWClearEventCallbacks(window); },
112-
[window] { GLFWAssignEventCallbacks(window); });
113-
}
114-
70+
// When GLFW calls back to the window with a cursor position move, forwards to
71+
// FlutterEngine as a pointer event with appropriate phase.
11572
static void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window,
11673
FlutterPointerPhase phase,
11774
double x, double y) {
@@ -124,14 +81,16 @@ static void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window,
12481
std::chrono::duration_cast<std::chrono::microseconds>(
12582
std::chrono::high_resolution_clock::now().time_since_epoch())
12683
.count();
127-
auto state = GetSavedEmbedderState(window);
128-
FlutterEngineSendPointerEvent(state->engine, &event, 1);
84+
FlutterEngineSendPointerEvent(GetSavedEmbedderState(window)->engine, &event,
85+
1);
12986
}
13087

88+
// Reports cursor move to the Flutter engine.
13189
static void GLFWcursorPositionCallback(GLFWwindow *window, double x, double y) {
13290
GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kMove, x, y);
13391
}
13492

93+
// Reports mouse button press to the Flutter engine.
13594
static void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action,
13695
int mods) {
13796
double x, y;
@@ -147,13 +106,15 @@ static void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action,
147106
}
148107
}
149108

109+
// Passes character input events to registered handlers.
150110
static void GLFWCharCallback(GLFWwindow *window, unsigned int code_point) {
151111
for (flutter_desktop_embedding::KeyboardHookHandler *handler :
152112
GetSavedEmbedderState(window)->keyboard_hook_handlers) {
153113
handler->CharHook(window, code_point);
154114
}
155115
}
156116

117+
// Passes raw key events to registered handlers.
157118
static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode,
158119
int action, int mods) {
159120
for (flutter_desktop_embedding::KeyboardHookHandler *handler :
@@ -162,6 +123,51 @@ static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode,
162123
}
163124
}
164125

126+
// Reports window size changes to the Flutter engine.
127+
static void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height) {
128+
FlutterWindowMetricsEvent event = {};
129+
event.struct_size = sizeof(event);
130+
event.width = width;
131+
event.height = height;
132+
// TODO: Handle pixel ratio for different DPI monitors.
133+
event.pixel_ratio = 1.0;
134+
FlutterEngineSendWindowMetricsEvent(GetSavedEmbedderState(window)->engine,
135+
&event);
136+
}
137+
138+
// Flushes event queue and then assigns default window callbacks.
139+
static void GLFWAssignEventCallbacks(GLFWwindow *window) {
140+
glfwPollEvents();
141+
glfwSetKeyCallback(window, GLFWKeyCallback);
142+
glfwSetCharCallback(window, GLFWCharCallback);
143+
glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);
144+
}
145+
146+
// Clears default window events.
147+
static void GLFWClearEventCallbacks(GLFWwindow *window) {
148+
glfwSetKeyCallback(window, nullptr);
149+
glfwSetCharCallback(window, nullptr);
150+
glfwSetMouseButtonCallback(window, nullptr);
151+
}
152+
153+
// The Flutter Engine calls out to this function when new platform messages are
154+
// available
155+
static void GLFWOnFlutterPlatformMessage(const FlutterPlatformMessage *message,
156+
void *user_data) {
157+
if (message->struct_size != sizeof(FlutterPlatformMessage)) {
158+
std::cerr << "Invalid message size received. Expected: "
159+
<< sizeof(FlutterPlatformMessage) << " but received "
160+
<< message->struct_size << std::endl;
161+
return;
162+
}
163+
164+
GLFWwindow *window = reinterpret_cast<GLFWwindow *>(user_data);
165+
auto state = GetSavedEmbedderState(window);
166+
state->plugin_handler->HandleMethodCallMessage(
167+
message, [window] { GLFWClearEventCallbacks(window); },
168+
[window] { GLFWAssignEventCallbacks(window); });
169+
}
170+
165171
static bool GLFWMakeContextCurrent(void *user_data) {
166172
GLFWwindow *window = reinterpret_cast<GLFWwindow *>(user_data);
167173
glfwMakeContextCurrent(window);
@@ -192,7 +198,7 @@ static uint32_t GLFWGetActiveFbo(void *user_data) { return 0; }
192198
static void GLFWClearCanvas(GLFWwindow *window) {
193199
glfwMakeContextCurrent(window);
194200
// This color is Material Blue Grey.
195-
glClearColor(0.92549, 0.93725, 0.9451, 0);
201+
glClearColor(236.0 / 255.0, 239.0 / 255.0, 241.0 / 255.0, 0);
196202
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
197203
glFlush();
198204
glfwSwapBuffers(window);
@@ -242,6 +248,13 @@ static FlutterEngine RunFlutterEngine(
242248

243249
namespace flutter_desktop_embedding {
244250

251+
// Initialize glfw
252+
bool FlutterInit() { return glfwInit(); }
253+
254+
// Tear down glfw
255+
void FlutterTerminate() { glfwTerminate(); }
256+
257+
// set up embedder state and add the plugin to the plugin_handler
245258
bool AddPlugin(GLFWwindow *flutter_window, std::unique_ptr<Plugin> plugin) {
246259
auto state = GetSavedEmbedderState(flutter_window);
247260
return state->plugin_handler->AddPlugin(std::move(plugin));
@@ -261,7 +274,9 @@ GLFWwindow *CreateFlutterWindow(size_t initial_width, size_t initial_height,
261274
const std::string &packages_path,
262275
const std::string &icu_data_path,
263276
const std::vector<std::string> &arguments) {
277+
#ifdef __linux__
264278
gtk_init(0, nullptr);
279+
#endif
265280
auto window = glfwCreateWindow(initial_width, initial_height,
266281
kDefaultWindowTitle, NULL, NULL);
267282
if (window == nullptr) {
@@ -274,6 +289,7 @@ GLFWwindow *CreateFlutterWindow(size_t initial_width, size_t initial_height,
274289
glfwDestroyWindow(window);
275290
return nullptr;
276291
}
292+
277293
FlutterEmbedderState *state = new FlutterEmbedderState();
278294
state->plugin_handler = std::make_unique<PluginHandler>(engine);
279295
state->engine = engine;
@@ -297,13 +313,19 @@ GLFWwindow *CreateFlutterWindow(size_t initial_width, size_t initial_height,
297313
}
298314

299315
void FlutterWindowLoop(GLFWwindow *flutter_window) {
316+
#ifdef __linux__
300317
// Necessary for GTK thread safety.
301318
XInitThreads();
319+
#endif
302320
while (!glfwWindowShouldClose(flutter_window)) {
321+
#ifdef __linux__
303322
glfwPollEvents();
304323
if (gtk_events_pending()) {
305324
gtk_main_iteration();
306325
}
326+
#else
327+
glfwWaitEvents();
328+
#endif
307329
// TODO(awdavies): This will be deprecated soon.
308330
__FlutterEngineFlushPendingTasksNow();
309331
}

library/windows/embedder.h renamed to library/include/flutter_desktop_embedding/glfw/embedder.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,25 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#ifndef WINDOWS_LIBRARY_EMBEDDER_H_
16-
#define WINDOWS_LIBRARY_EMBEDDER_H_
15+
#ifndef LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_EMBEDDER_H_
16+
#define LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_EMBEDDER_H_
1717

18+
#include <memory>
1819
#include <string>
1920
#include <vector>
2021

22+
#ifdef __linux__
23+
// Epoxy must be included before any graphics-related code.
24+
#include <epoxy/gl.h>
25+
#endif
26+
2127
#include <GLFW/glfw3.h>
2228

23-
#include "library/include/flutter_desktop_embedding/plugin.h"
29+
#ifdef USE_FLATTENED_INCLUDES
30+
#include "plugin.h"
31+
#else
32+
#include "../plugin.h"
33+
#endif
2434

2535
namespace flutter_desktop_embedding {
2636

@@ -86,4 +96,4 @@ void FlutterWindowLoop(GLFWwindow *flutter_window);
8696

8797
} // namespace flutter_desktop_embedding
8898

89-
#endif // WINDOWS_LIBRARY_EMBEDDER_H_
99+
#endif // LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_EMBEDDER_H_

0 commit comments

Comments
 (0)