Skip to content
Open
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
2 changes: 1 addition & 1 deletion clay/lynx_adaptor/perf_controller_clay.cc
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ void PerfControllerClay::EndFluencyMonitor(int id) {
return;
}

shell::ReportEvent event;
shell::PerfReportEvent event;
event.event_name = std::string(kLynxFluencyEvent);

// string props
Expand Down
2 changes: 2 additions & 0 deletions clay/shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ source_set("flutter_windows_source") {
"keyboard_manager.h",
"keyboard_utils.cc",
"keyboard_utils.h",
"overlay_platform_plugin_win.cc",
"overlay_platform_plugin_win.h",
"overlay_view_controller.cc",
"overlay_view_controller.h",
"overlay_view_manager_service.cc",
Expand Down
22 changes: 19 additions & 3 deletions clay/shell/platform/windows/flutter_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static HCURSOR GetCursorByType(clay::CursorTypes cursor_type) {

FlutterWindow::FlutterWindow(HWND parent_hwnd, int x, int y, int width,
int height)
: binding_handler_delegate_(nullptr) {
: parent_hwnd_(parent_hwnd), binding_handler_delegate_(nullptr) {
Window::InitializeChild("FLUTTERVIEW", parent_hwnd, x, y, width, height);
auto cursor = ::LoadCursor(nullptr, IDC_ARROW);
SetClassLongPtr(GetWindowHandle(), GCLP_HCURSOR,
Expand Down Expand Up @@ -273,13 +273,15 @@ void FlutterWindow::OnPaint() {
void FlutterWindow::OnPointerMove(double x, double y,
ClayPointerDeviceKind device_kind,
int32_t device_id, int modifiers_state) {
ConvertPointToParentWindow(&x, &y);
binding_handler_delegate_->OnPointerMove(x, y, device_kind, device_id,
modifiers_state);
}

void FlutterWindow::OnPointerDown(double x, double y,
ClayPointerDeviceKind device_kind,
int32_t device_id, UINT button) {
ConvertPointToParentWindow(&x, &y);
uint64_t flutter_button = ConvertWinButtonToFlutterButton(button);
if (flutter_button != 0) {
binding_handler_delegate_->OnPointerDown(
Expand All @@ -291,6 +293,7 @@ void FlutterWindow::OnPointerDown(double x, double y,
void FlutterWindow::OnPointerUp(double x, double y,
ClayPointerDeviceKind device_kind,
int32_t device_id, UINT button) {
ConvertPointToParentWindow(&x, &y);
uint64_t flutter_button = ConvertWinButtonToFlutterButton(button);
if (flutter_button != 0) {
binding_handler_delegate_->OnPointerUp(
Expand All @@ -302,6 +305,7 @@ void FlutterWindow::OnPointerUp(double x, double y,
void FlutterWindow::OnPointerLeave(double x, double y,
ClayPointerDeviceKind device_kind,
int32_t device_id) {
ConvertPointToParentWindow(&x, &y);
binding_handler_delegate_->OnPointerLeave(x, y, device_kind, device_id);
}

Expand Down Expand Up @@ -344,7 +348,8 @@ void FlutterWindow::OnScroll(double delta_x, double delta_y,
POINT point;
GetCursorPos(&point);

ScreenToClient(GetWindowHandle(), &point);
ScreenToClient(parent_hwnd_ ? parent_hwnd_ : Window::GetWindowHandle(),
&point);
binding_handler_delegate_->OnScroll(point.x, point.y, delta_x, delta_y,
GetScrollOffsetMultiplier(), device_kind,
device_id);
Expand Down Expand Up @@ -384,10 +389,21 @@ bool FlutterWindow::OnBitmapSurfaceUpdated(const void* allocation,
PointerLocation FlutterWindow::GetPrimaryPointerLocation() {
POINT point;
GetCursorPos(&point);
ScreenToClient(GetWindowHandle(), &point);
ScreenToClient(parent_hwnd_ ? parent_hwnd_ : Window::GetWindowHandle(),
&point);
return {(size_t)point.x, (size_t)point.y};
}

void FlutterWindow::ConvertPointToParentWindow(double* x, double* y) {
if (!parent_hwnd_) {
return;
}
POINT point = {static_cast<LONG>(*x), static_cast<LONG>(*y)};
MapWindowPoints(Window::GetWindowHandle(), parent_hwnd_, &point, 1);
*x = point.x;
*y = point.y;
}

void FlutterWindow::OnThemeChange() {
binding_handler_delegate_->UpdateHighContrastEnabled(
GetHighContrastEnabled());
Expand Down
6 changes: 6 additions & 0 deletions clay/shell/platform/windows/flutter_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ class FlutterWindow : public Window, public WindowBindingHandler {
bool NeedsVSync() override;

private:
// Clay pointer events use the implicit view's physical coordinates, while
// Win32 child-window messages use coordinates local to the child.
void ConvertPointToParentWindow(double* x, double* y);

HWND parent_hwnd_ = nullptr;

// A pointer to a FlutterWindowsView that can be used to update engine
// windowing and input state.
WindowBindingHandlerDelegate* binding_handler_delegate_;
Expand Down
27 changes: 16 additions & 11 deletions clay/shell/platform/windows/flutter_windows_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "clay/shell/common/switches.h"
#include "clay/shell/platform/common/path_utils.h"
#include "clay/shell/platform/windows/flutter_windows_view.h"
#include "clay/shell/platform/windows/overlay_platform_plugin_win.h"
#include "clay/shell/platform/windows/overlay_view_manager_service.h"
#include "clay/shell/platform/windows/overlay_windows_view.h"
#include "clay/shell/platform/windows/task_runner.h"
Expand Down Expand Up @@ -254,6 +255,21 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
FML_LOG(ERROR) << "Failed to start Flutter engine";
return false;
}

service_manager_ = engine_->GetServiceManager();
if (!service_manager_) {
FML_LOG(ERROR) << "Failed to get clay service manager";
return false;
}
// CoverView resolves OverlayService while the UI tree is being created, so
// register the Windows implementation before launching the shell.
overlay_view_manager_service_ =
std::make_shared<OverlayViewManagerService>(this);
service_manager_->RegisterService<OverlayViewManagerService>(
overlay_view_manager_service_);
overlay_platform_service_ = std::make_shared<OverlayPlatformServiceWin>();
service_manager_->RegisterService<OverlayService>(overlay_platform_service_);

// Step 1: Launch the shell.
if (!engine_->LaunchShell()) {
FML_LOG(ERROR) << "Could not launch the engine using supplied "
Expand All @@ -266,17 +282,6 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
FML_LOG(ERROR) << "Could not create platform view components.";
return false;
}
service_manager_ = engine_->GetServiceManager();
if (!service_manager_) {
FML_LOG(ERROR) << "Failed to get clay service manager";
return false;
}

overlay_view_manager_service_ =
std::make_shared<OverlayViewManagerService>(this);
// |view_| can be nullptr in headless mode; avoid dereferencing it here.
service_manager_->RegisterService<OverlayViewManagerService>(
overlay_view_manager_service_);

// Configure device frame rate displayed via devtools.
std::vector<std::unique_ptr<clay::Display>> displays;
Expand Down
2 changes: 2 additions & 0 deletions clay/shell/platform/windows/flutter_windows_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace clay {

class FlutterWindowsView;
class OverlayViewManagerService;
class OverlayService;

// A unique identifier for a view.
using FlutterViewId = int64_t;
Expand Down Expand Up @@ -361,6 +362,7 @@ class FlutterWindowsEngine : public PlatformViewEmbedderDelegate,
std::shared_ptr<clay::ServiceManager> service_manager_;

std::shared_ptr<OverlayViewManagerService> overlay_view_manager_service_;
std::shared_ptr<OverlayService> overlay_platform_service_;
};

} // namespace clay
Expand Down
14 changes: 14 additions & 0 deletions clay/shell/platform/windows/flutter_windows_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,20 @@ uint32_t FlutterWindowsView::GetFrameBufferId(size_t width, size_t height) {
return kWindowFrameBufferID;
}

void FlutterWindowsView::PrepareSurfaceSize(size_t width, size_t height) {
std::unique_lock<std::mutex> lock(resize_mutex_);
if (!surface_ || !surface_->IsValid()) {
return;
}
if (SurfaceWillUpdate(surface_->width(), surface_->height(), width, height) ||
SurfaceWillUpdate(resize_target_width_, resize_target_height_, width,
height)) {
resize_status_ = ResizeState::kResizeStarted;
resize_target_width_ = width;
resize_target_height_ = height;
}
}

void FlutterWindowsView::SetDamageRegion(const clay::Rect& region) {
if (!surface_) {
return;
Expand Down
4 changes: 4 additions & 0 deletions clay/shell/platform/windows/flutter_windows_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
// Returns the frame buffer id for the engine to render to.
uint32_t GetFrameBufferId(size_t width, size_t height);

// Prepares a surface resize for the next frame without blocking the caller.
// The actual resize is performed by GetFrameBufferId on the raster thread.
void PrepareSurfaceSize(size_t width, size_t height);

void SetDamageRegion(const clay::Rect& region);

void SetPresentDamageRegion(const clay::Rect& region);
Expand Down
104 changes: 104 additions & 0 deletions clay/shell/platform/windows/overlay_platform_plugin_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2026 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.

#include "clay/shell/platform/windows/overlay_platform_plugin_win.h"

#include <Windows.h>

#include <utility>

#include "clay/shell/platform/windows/flutter_windows_engine.h"

namespace clay {

OverlayPlatformPluginWin::OverlayPlatformPluginWin(FlutterWindowsEngine* engine,
OverlayViewManager* manager)
: engine_(engine), manager_(manager) {}

void OverlayPlatformPluginWin::ChangeVisibility(bool visible) {
if (!view_) {
return;
}
HWND window = view_->GetWindowHandle();
if (visible) {
ShowWindow(window, SW_SHOW);
} else {
ShowWindow(window, SW_HIDE);
}
}

void OverlayPlatformPluginWin::SetEventThrough(bool event_through) {
event_through_ = event_through;
if (view_) {
view_->SetEventThrough(event_through);
}
}

void OverlayPlatformPluginWin::SetSize(int width, int height) {
if (width <= 0 || height <= 0) {
return;
}
preferred_width_ = width;
preferred_height_ = height;
EnsureView();
}

void OverlayPlatformPluginWin::OnDetachFromTree() { ChangeVisibility(false); }

void OverlayPlatformPluginWin::OnViewDestroy() {
if (manager_ && node_id_ != -1) {
manager_->RemoveView(node_id_);
}
view_.reset();
node_id_ = -1;
}

void OverlayPlatformPluginWin::InitPlatformOverlay(
std::shared_ptr<Actor<fml::WeakPtr<OverlayListener>>> overlay_listener,
int id, std::string tag, ExternalViewPlugin* recording_plugin) {
OverlayPlatformPlugin::InitPlatformOverlay(std::move(overlay_listener), id,
std::move(tag), recording_plugin);
if (!engine_ || !engine_->view() || !manager_) {
return;
}
node_id_ = id;
EnsureView();
}

void OverlayPlatformPluginWin::EnsureView() {
if (view_ || node_id_ == -1 || preferred_width_ <= 0 ||
preferred_height_ <= 0 || !engine_ || !engine_->view() || !manager_) {
return;
}
OverlayWindowCreationRequest request = {
.preferred_size = {preferred_width_, preferred_height_},
.title = L"cover-view"};
view_ = manager_->CreateView(node_id_, OverlayWindowType::kChild, request,
engine_->view()->GetWindowHandle());
if (view_) {
view_->SetEventThrough(event_through_);
}
}

std::unique_ptr<OverlayPlatformPlugin>
OverlayPlatformServiceWin::CreateOverlayPlatformPlugin() {
if (!overlay_view_manager_service_) {
return nullptr;
}
return std::make_unique<OverlayPlatformPluginWin>(
overlay_view_manager_service_->GetEngine(),
overlay_view_manager_service_->GetOverlayWindowManager());
}

void OverlayPlatformServiceWin::OnInit(ServiceManager& service_manager,
const PlatformServiceContext& ctx) {
overlay_view_manager_service_ =
service_manager.GetService<OverlayViewManagerService>();
}

void OverlayPlatformServiceWin::OnDestroy() {
overlay_view_manager_service_ = nullptr;
}

} // namespace clay
71 changes: 71 additions & 0 deletions clay/shell/platform/windows/overlay_platform_plugin_win.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2026 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.

#ifndef CLAY_SHELL_PLATFORM_WINDOWS_OVERLAY_PLATFORM_PLUGIN_WIN_H_
#define CLAY_SHELL_PLATFORM_WINDOWS_OVERLAY_PLATFORM_PLUGIN_WIN_H_

#include <memory>
#include <string>

#include "clay/common/service/service_manager.h"
#include "clay/shell/platform/windows/overlay_view_manager_service.h"
#include "clay/ui/platform/overlay_service.h"

namespace clay {

class OverlayPlatformPluginWin final : public OverlayPlatformPlugin {
public:
OverlayPlatformPluginWin(FlutterWindowsEngine* engine,
OverlayViewManager* manager);
~OverlayPlatformPluginWin() override = default;

void ChangeVisibility(bool visible) override;
void SetLevel(int level) override {}
void SetCutOutMode(bool is_cut_out) override {}
void SetAndroidSoftInputMode(std::string mode) override {}
void SetAndroidNativeEventPass(bool is_pass) override {}
void SetStatusBarTranslucent(bool is_translucent) override {}
void SetStatusBarTranslucentStyle(std::string style) override {}
void SetAndroidFullScreen(bool is_full_screen) override {}
void SetEventThrough(bool event_through) override;
void SetSize(int width, int height) override;

bool ShouldHandleTreeLifecycle() const override { return true; }
bool RequiresExternalViewPlugin() const override { return false; }
void OnAttachToTree() override {}
void OnDetachFromTree() override;
void OnViewDestroy() override;

void InitPlatformOverlay(
std::shared_ptr<Actor<fml::WeakPtr<OverlayListener>>> overlay_listener,
int id, std::string tag, ExternalViewPlugin* recording_plugin) override;

private:
void EnsureView();

int64_t node_id_ = -1;
int preferred_width_ = 0;
int preferred_height_ = 0;
bool event_through_ = false;
FlutterWindowsEngine* engine_ = nullptr;
OverlayViewManager* manager_ = nullptr;
std::shared_ptr<OverlayViewController> view_;
};

class OverlayPlatformServiceWin final : public OverlayService {
public:
std::unique_ptr<OverlayPlatformPlugin> CreateOverlayPlatformPlugin() override;

void OnInit(ServiceManager& service_manager,
const PlatformServiceContext& ctx) override;
void OnDestroy() override;

private:
Puppet<Owner::kPlatform, OverlayViewManagerService>
overlay_view_manager_service_;
};

} // namespace clay

#endif // CLAY_SHELL_PLATFORM_WINDOWS_OVERLAY_PLATFORM_PLUGIN_WIN_H_
Loading
Loading