Skip to content

Merge GLFW library implementations #194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions example/linux/flutter_embedder_example.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#ifdef USE_FLATTENED_INCLUDES
#include <flutter_desktop_embedding/embedder.h>
#else
#include <flutter_desktop_embedding/linux/embedder.h>
#include <flutter_desktop_embedding/glfw/embedder.h>
#endif

namespace {
Expand All @@ -53,7 +53,7 @@ std::string GetExecutableDirectory() {
} // namespace

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

Expand All @@ -78,7 +78,7 @@ int main(int argc, char **argv) {
auto window = flutter_desktop_embedding::CreateFlutterWindowInSnapshotMode(
640, 480, assets_path, icu_data_path, arguments);
if (window == nullptr) {
glfwTerminate();
flutter_desktop_embedding::FlutterTerminate();
return EXIT_FAILURE;
}

Expand Down
2 changes: 1 addition & 1 deletion example/windows/GLFW Example.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Dynamic Library|x64'">
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
<IntDir>$(SolutionDir)bin\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<IncludePath>$(ProjectDir)..\..\library\windows\dependencies\;$(ProjectDir)..\..\;$(IncludePath);$(ProjectDir)..\..\library\windows\</IncludePath>
<IncludePath>$(ProjectDir)..\..\library\windows\dependencies\;$(ProjectDir)..\..\;$(IncludePath);$(ProjectDir)..\..\library\windows\;$(ProjectDir)..\..\library\include\</IncludePath>
<LibraryPath>$(ProjectDir)..\..\library\windows\dependencies\GLFW\;$(SolutionDir)bin\$(Platform)\$(Configuration)\GLFW Library\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static Library|x64'">
Expand Down
2 changes: 1 addition & 1 deletion example/windows/flutter_embedder_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <iostream>
#include <vector>

#include "embedder.h"
#include "flutter_desktop_embedding/glfw/embedder.h"

int main(int argc, char **argv) {
if (!flutter_desktop_embedding::FlutterInit()) {
Expand Down
28 changes: 13 additions & 15 deletions library/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@ import("//build/packaging.gni")
import("//library/engine.gni")

published_shared_library("flutter_embedder") {
if (is_linux) {
sources = [
"linux/src/embedder.cc",
]
# GLFW embedding implementation.
if (is_linux || is_win) {
public = [
"include/flutter_desktop_embedding/linux/embedder.h",
"include/flutter_desktop_embedding/glfw/embedder.h",
]
sources = [
"common/glfw/embedder.cc",
"common/glfw/key_event_handler.cc",
"common/glfw/key_event_handler.h",
"common/glfw/keyboard_hook_handler.h",
"common/glfw/text_input_plugin.cc",
"common/glfw/text_input_plugin.h",
]
}

# Embedding-agnostic shared C++.
if (is_linux || is_win) {
sources += [
"common/internal/engine_method_result.cc",
Expand Down Expand Up @@ -56,16 +64,6 @@ published_shared_library("flutter_embedder") {
"include/flutter_desktop_embedding/plugin.h",
]
}
# GLFW-specific code.
if (is_linux || is_win) {
sources += [
"common/glfw/key_event_handler.cc",
"common/glfw/key_event_handler.h",
"common/glfw/keyboard_hook_handler.h",
"common/glfw/text_input_plugin.cc",
"common/glfw/text_input_plugin.h",
]
}

deps = [
":fetch_flutter_engine",
Expand Down
2 changes: 1 addition & 1 deletion library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ $ sudo apt-get install libglfw3-dev libepoxy-dev libjsoncpp-dev libgtk-3-dev \
#### Using the Library

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

You will also need to link `libflutter_engine.so` into your binary.
Expand Down
140 changes: 81 additions & 59 deletions library/linux/src/embedder.cc → library/common/glfw/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <flutter_desktop_embedding/linux/embedder.h>

#include <X11/Xlib.h>
#include <assert.h>
#include <gtk/gtk.h>
#include "library/include/flutter_desktop_embedding/glfw/embedder.h"

#include <assert.h>
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>

#include <flutter_embedder.h>

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

#ifdef __linux__
// For plugin-compatible event handling (e.g., modal windows).
#include <X11/Xlib.h>
#include <gtk/gtk.h>
#endif

// GLFW_TRUE & GLFW_FALSE are introduced since libglfw-3.3,
// add definitions here to compile under the old versions.
#ifndef GLFW_TRUE
Expand All @@ -51,67 +53,22 @@ struct FlutterEmbedderState {
// deleted from the heap.
std::vector<flutter_desktop_embedding::KeyboardHookHandler *>
keyboard_hook_handlers;

// Handles raw key interactions from GLFW.
// TODO: Move key_event_handler once
// https://github.com/google/flutter-desktop-embedding/issues/102 is resolved.
// TODO: Revisit ownership model once Issue #102 is resolved.
std::unique_ptr<flutter_desktop_embedding::KeyEventHandler> key_event_handler;
};

static constexpr char kDefaultWindowTitle[] = "Flutter";

// Callback forward declarations.
static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode,
int action, int mods);
static void GLFWCharCallback(GLFWwindow *window, unsigned int code_point);
static void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action,
int mods);

// Retrieves state bag for the window in question from the GLFWWindow.
static FlutterEmbedderState *GetSavedEmbedderState(GLFWwindow *window) {
return reinterpret_cast<FlutterEmbedderState *>(
glfwGetWindowUserPointer(window));
}

// Flushes event queue and then assigns default window callbacks.
static void GLFWAssignEventCallbacks(GLFWwindow *window) {
glfwPollEvents();
glfwSetKeyCallback(window, GLFWKeyCallback);
glfwSetCharCallback(window, GLFWCharCallback);
glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);
}

// Clears default window events.
static void GLFWClearEventCallbacks(GLFWwindow *window) {
glfwSetKeyCallback(window, nullptr);
glfwSetCharCallback(window, nullptr);
glfwSetMouseButtonCallback(window, nullptr);
}

static void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height) {
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = width;
event.height = height;
event.pixel_ratio = 1.0;
auto state = GetSavedEmbedderState(window);
FlutterEngineSendWindowMetricsEvent(state->engine, &event);
}

static void GLFWOnFlutterPlatformMessage(const FlutterPlatformMessage *message,
void *user_data) {
if (message->struct_size != sizeof(FlutterPlatformMessage)) {
std::cerr << "Invalid message size received. Expected: "
<< sizeof(FlutterPlatformMessage) << " but received "
<< message->struct_size << std::endl;
return;
}

GLFWwindow *window = reinterpret_cast<GLFWwindow *>(user_data);
auto state = GetSavedEmbedderState(window);
state->plugin_handler->HandleMethodCallMessage(
message, [window] { GLFWClearEventCallbacks(window); },
[window] { GLFWAssignEventCallbacks(window); });
}

// When GLFW calls back to the window with a cursor position move, forwards to
// FlutterEngine as a pointer event with appropriate phase.
static void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window,
FlutterPointerPhase phase,
double x, double y) {
Expand All @@ -124,14 +81,16 @@ static void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window,
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
auto state = GetSavedEmbedderState(window);
FlutterEngineSendPointerEvent(state->engine, &event, 1);
FlutterEngineSendPointerEvent(GetSavedEmbedderState(window)->engine, &event,
1);
}

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

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

// Passes character input events to registered handlers.
static void GLFWCharCallback(GLFWwindow *window, unsigned int code_point) {
for (flutter_desktop_embedding::KeyboardHookHandler *handler :
GetSavedEmbedderState(window)->keyboard_hook_handlers) {
handler->CharHook(window, code_point);
}
}

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

// Reports window size changes to the Flutter engine.
static void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height) {
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = width;
event.height = height;
// TODO: Handle pixel ratio for different DPI monitors.
event.pixel_ratio = 1.0;
FlutterEngineSendWindowMetricsEvent(GetSavedEmbedderState(window)->engine,
&event);
}

// Flushes event queue and then assigns default window callbacks.
static void GLFWAssignEventCallbacks(GLFWwindow *window) {
glfwPollEvents();
glfwSetKeyCallback(window, GLFWKeyCallback);
glfwSetCharCallback(window, GLFWCharCallback);
glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);
}

// Clears default window events.
static void GLFWClearEventCallbacks(GLFWwindow *window) {
glfwSetKeyCallback(window, nullptr);
glfwSetCharCallback(window, nullptr);
glfwSetMouseButtonCallback(window, nullptr);
}

// The Flutter Engine calls out to this function when new platform messages are
// available
static void GLFWOnFlutterPlatformMessage(const FlutterPlatformMessage *message,
void *user_data) {
if (message->struct_size != sizeof(FlutterPlatformMessage)) {
std::cerr << "Invalid message size received. Expected: "
<< sizeof(FlutterPlatformMessage) << " but received "
<< message->struct_size << std::endl;
return;
}

GLFWwindow *window = reinterpret_cast<GLFWwindow *>(user_data);
auto state = GetSavedEmbedderState(window);
state->plugin_handler->HandleMethodCallMessage(
message, [window] { GLFWClearEventCallbacks(window); },
[window] { GLFWAssignEventCallbacks(window); });
}

static bool GLFWMakeContextCurrent(void *user_data) {
GLFWwindow *window = reinterpret_cast<GLFWwindow *>(user_data);
glfwMakeContextCurrent(window);
Expand Down Expand Up @@ -192,7 +198,7 @@ static uint32_t GLFWGetActiveFbo(void *user_data) { return 0; }
static void GLFWClearCanvas(GLFWwindow *window) {
glfwMakeContextCurrent(window);
// This color is Material Blue Grey.
glClearColor(0.92549, 0.93725, 0.9451, 0);
glClearColor(236.0 / 255.0, 239.0 / 255.0, 241.0 / 255.0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFlush();
glfwSwapBuffers(window);
Expand Down Expand Up @@ -242,6 +248,13 @@ static FlutterEngine RunFlutterEngine(

namespace flutter_desktop_embedding {

// Initialize glfw
bool FlutterInit() { return glfwInit(); }

// Tear down glfw
void FlutterTerminate() { glfwTerminate(); }

// set up embedder state and add the plugin to the plugin_handler
bool AddPlugin(GLFWwindow *flutter_window, std::unique_ptr<Plugin> plugin) {
auto state = GetSavedEmbedderState(flutter_window);
return state->plugin_handler->AddPlugin(std::move(plugin));
Expand All @@ -261,7 +274,9 @@ GLFWwindow *CreateFlutterWindow(size_t initial_width, size_t initial_height,
const std::string &packages_path,
const std::string &icu_data_path,
const std::vector<std::string> &arguments) {
#ifdef __linux__
gtk_init(0, nullptr);
#endif
auto window = glfwCreateWindow(initial_width, initial_height,
kDefaultWindowTitle, NULL, NULL);
if (window == nullptr) {
Expand All @@ -274,6 +289,7 @@ GLFWwindow *CreateFlutterWindow(size_t initial_width, size_t initial_height,
glfwDestroyWindow(window);
return nullptr;
}

FlutterEmbedderState *state = new FlutterEmbedderState();
state->plugin_handler = std::make_unique<PluginHandler>(engine);
state->engine = engine;
Expand All @@ -297,13 +313,19 @@ GLFWwindow *CreateFlutterWindow(size_t initial_width, size_t initial_height,
}

void FlutterWindowLoop(GLFWwindow *flutter_window) {
#ifdef __linux__
// Necessary for GTK thread safety.
XInitThreads();
#endif
while (!glfwWindowShouldClose(flutter_window)) {
#ifdef __linux__
glfwPollEvents();
if (gtk_events_pending()) {
gtk_main_iteration();
}
#else
glfwWaitEvents();
#endif
// TODO(awdavies): This will be deprecated soon.
__FlutterEngineFlushPendingTasksNow();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef WINDOWS_LIBRARY_EMBEDDER_H_
#define WINDOWS_LIBRARY_EMBEDDER_H_
#ifndef LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_EMBEDDER_H_
#define LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_EMBEDDER_H_

#include <memory>
#include <string>
#include <vector>

#ifdef __linux__
// Epoxy must be included before any graphics-related code.
#include <epoxy/gl.h>
#endif

#include <GLFW/glfw3.h>

#include "library/include/flutter_desktop_embedding/plugin.h"
#ifdef USE_FLATTENED_INCLUDES
#include "plugin.h"
#else
#include "../plugin.h"
#endif

namespace flutter_desktop_embedding {

Expand Down Expand Up @@ -86,4 +96,4 @@ void FlutterWindowLoop(GLFWwindow *flutter_window);

} // namespace flutter_desktop_embedding

#endif // WINDOWS_LIBRARY_EMBEDDER_H_
#endif // LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_EMBEDDER_H_
Loading