mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
205 lines
6.4 KiB
C++
205 lines
6.4 KiB
C++
// Copyright 2016 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "flutter/sky/shell/platform/glfw/window_impl.h"
|
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include "flutter/sky/shell/platform/glfw/platform_view_glfw.h"
|
|
#include "flutter/sky/shell/shell.h"
|
|
|
|
namespace sky {
|
|
namespace shell {
|
|
namespace {
|
|
|
|
WindowImpl* ToImpl(GLFWwindow* window) {
|
|
return static_cast<WindowImpl*>(glfwGetWindowUserPointer(window));
|
|
}
|
|
|
|
void OnWindowSizeChanged(GLFWwindow* window, int width, int height) {
|
|
ToImpl(window)->UpdateViewportMetrics(width, height);
|
|
}
|
|
|
|
void OnMouseButtonChanged(GLFWwindow* window, int button, int action, int mods) {
|
|
ToImpl(window)->DispatchMouseButtonEvent(button, action, mods);
|
|
}
|
|
|
|
void OnCursorPosChanged(GLFWwindow* window, double x, double y) {
|
|
ToImpl(window)->DispatchMouseMoveEvent(x, y);
|
|
}
|
|
|
|
void OnKeyEvent(GLFWwindow* window, int key, int scancode, int action,
|
|
int mods) {
|
|
sky::InputEventPtr result = sky::InputEvent::New();
|
|
result->time_stamp = base::TimeTicks::Now().ToInternalValue();
|
|
switch (action) {
|
|
case GLFW_PRESS:
|
|
case GLFW_REPEAT:
|
|
result->type = sky::EventType::KEY_PRESSED;
|
|
break;
|
|
case GLFW_RELEASE:
|
|
result->type = sky::EventType::KEY_RELEASED;
|
|
break;
|
|
default:
|
|
LOG(WARNING) << "Unknown key action: " << action;
|
|
return;
|
|
}
|
|
result->key_data = sky::KeyData::New();
|
|
result->key_data->key_code = key;
|
|
result->key_data->scan_code = scancode;
|
|
|
|
if (mods & GLFW_MOD_SHIFT)
|
|
result->key_data->meta_state |= 0x00000001;
|
|
if (mods & GLFW_MOD_CONTROL)
|
|
result->key_data->meta_state |= 0x00001000;
|
|
if (mods & GLFW_MOD_ALT)
|
|
result->key_data->meta_state |= 0x00000002;
|
|
|
|
ToImpl(window)->DispatchKeyEvent(result.Pass());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
WindowImpl::WindowImpl(GLFWwindow* window)
|
|
: window_(window),
|
|
shell_view_(new ShellView(Shell::Shared())),
|
|
buttons_(0),
|
|
view_services_binding_(this) {
|
|
glfwSetWindowUserPointer(window_, this);
|
|
auto platform_view =
|
|
static_cast<sky::shell::PlatformViewGLFW*>(shell_view_->view());
|
|
platform_view->SurfaceCreated(window);
|
|
platform_view->ConnectToEngine(mojo::GetProxy(&engine_));
|
|
|
|
int width = 0;
|
|
int height = 0;
|
|
glfwGetWindowSize(window_, &width, &height);
|
|
UpdateViewportMetrics(width, height);
|
|
|
|
glfwSetWindowSizeCallback(window_, OnWindowSizeChanged);
|
|
glfwSetMouseButtonCallback(window_, OnMouseButtonChanged);
|
|
glfwSetKeyCallback(window_, OnKeyEvent);
|
|
}
|
|
|
|
WindowImpl::~WindowImpl() {
|
|
shell_view_.reset();
|
|
glfwDestroyWindow(window_);
|
|
window_ = nullptr;
|
|
}
|
|
|
|
void WindowImpl::RunFromBundle(const std::string& script_uri,
|
|
const std::string& bundle_path) {
|
|
mojo::ServiceProviderPtr view_services;
|
|
view_services_binding_.Bind(mojo::GetProxy(&view_services));
|
|
|
|
ServicesDataPtr services = ServicesData::New();
|
|
services->view_services = view_services.Pass();
|
|
engine_->SetServices(services.Pass());
|
|
engine_->RunFromBundle(script_uri, bundle_path);
|
|
}
|
|
|
|
void WindowImpl::RunFromFile(const std::string& file) {
|
|
// TODO(johnmccutchan): Wire up support for asset bundles when running
|
|
// from source.
|
|
engine_->RunFromFile(file, "", "");
|
|
}
|
|
|
|
void WindowImpl::UpdateViewportMetrics(int width, int height) {
|
|
auto metrics = sky::ViewportMetrics::New();
|
|
metrics->physical_width = width;
|
|
metrics->physical_height = height;
|
|
// TODO(abarth): There doesn't appear to be a way to get the device pixel
|
|
// ratio from GLFW.
|
|
metrics->device_pixel_ratio = 1.0;
|
|
engine_->OnViewportMetricsChanged(metrics.Pass());
|
|
}
|
|
|
|
void WindowImpl::DispatchMouseButtonEvent(int button, int action, int mods) {
|
|
pointer::PointerType type;
|
|
if (action == GLFW_PRESS) {
|
|
if (!buttons_) {
|
|
type = pointer::PointerType::DOWN;
|
|
glfwSetCursorPosCallback(window_, OnCursorPosChanged);
|
|
} else {
|
|
type = pointer::PointerType::MOVE;
|
|
}
|
|
// GLFW's button order matches what we want:
|
|
// https://github.com/flutter/engine/blob/master/sky/specs/pointer.md
|
|
// http://www.glfw.org/docs/3.2/group__buttons.html
|
|
buttons_ |= 1 << button;
|
|
} else if (action == GLFW_RELEASE) {
|
|
buttons_ &= ~(1 << button);
|
|
if (!buttons_) {
|
|
type = pointer::PointerType::UP;
|
|
glfwSetCursorPosCallback(window_, nullptr);
|
|
} else {
|
|
type = pointer::PointerType::MOVE;
|
|
}
|
|
} else {
|
|
DLOG(INFO) << "Unknown mouse action: " << action;
|
|
return;
|
|
}
|
|
|
|
double x = 0.f, y = 0.f;
|
|
glfwGetCursorPos(window_, &x, &y);
|
|
|
|
base::TimeDelta time_stamp = base::TimeTicks::Now() - base::TimeTicks();
|
|
|
|
auto pointer_data = pointer::Pointer::New();
|
|
pointer_data->time_stamp = time_stamp.InMicroseconds();
|
|
pointer_data->type = type;
|
|
pointer_data->kind = pointer::PointerKind::MOUSE;
|
|
pointer_data->x = x;
|
|
pointer_data->y = y;
|
|
pointer_data->buttons = buttons_;
|
|
pointer_data->pressure = 1.0;
|
|
pointer_data->pressure_max = 1.0;
|
|
|
|
auto pointer_packet = pointer::PointerPacket::New();
|
|
pointer_packet->pointers.push_back(pointer_data.Pass());
|
|
engine_->OnPointerPacket(pointer_packet.Pass());
|
|
}
|
|
|
|
void WindowImpl::DispatchMouseMoveEvent(double x, double y) {
|
|
base::TimeDelta time_stamp = base::TimeTicks::Now() - base::TimeTicks();
|
|
|
|
auto pointer_data = pointer::Pointer::New();
|
|
pointer_data->time_stamp = time_stamp.InMicroseconds();
|
|
pointer_data->type = pointer::PointerType::MOVE;
|
|
pointer_data->kind = pointer::PointerKind::MOUSE;
|
|
pointer_data->x = x;
|
|
pointer_data->y = y;
|
|
pointer_data->buttons = buttons_;
|
|
pointer_data->pressure = 1.0;
|
|
pointer_data->pressure_max = 1.0;
|
|
|
|
auto pointer_packet = pointer::PointerPacket::New();
|
|
pointer_packet->pointers.push_back(pointer_data.Pass());
|
|
engine_->OnPointerPacket(pointer_packet.Pass());
|
|
}
|
|
|
|
void WindowImpl::DispatchKeyEvent(sky::InputEventPtr sky_event) {
|
|
for (auto& listener : raw_keyboard_listeners_) {
|
|
listener->OnKey(sky_event.Clone());
|
|
}
|
|
}
|
|
|
|
void WindowImpl::ConnectToService(const mojo::String& service_name,
|
|
mojo::ScopedMessagePipeHandle handle) {
|
|
if (service_name == raw_keyboard::RawKeyboardService::Name_) {
|
|
raw_keyboard_bindings_.AddBinding(
|
|
this,
|
|
mojo::InterfaceRequest<raw_keyboard::RawKeyboardService>(handle.Pass()));
|
|
}
|
|
}
|
|
|
|
void WindowImpl::AddListener(
|
|
mojo::InterfaceHandle<raw_keyboard::RawKeyboardListener> listener) {
|
|
raw_keyboard_listeners_.push_back(
|
|
raw_keyboard::RawKeyboardListenerPtr::Create(listener.Pass()));
|
|
}
|
|
|
|
} // namespace shell
|
|
} // namespace sky
|