Skip to content
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
56 changes: 36 additions & 20 deletions engine/src/flutter/shell/platform/windows/display_monitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,19 @@ DisplayMonitor::DisplayMonitor(FlutterWindowsEngine* engine)

DisplayMonitor::~DisplayMonitor() {}

BOOL CALLBACK DisplayMonitor::EnumMonitorCallback(HMONITOR monitor,
HDC hdc,
LPRECT rect,
LPARAM data) {
MonitorEnumState* state = reinterpret_cast<MonitorEnumState*>(data);
const DisplayMonitor* self = state->display_monitor;
std::vector<FlutterEngineDisplay>* displays = state->displays;

std::optional<FlutterEngineDisplay> DisplayMonitor::FromMonitor(
HMONITOR monitor) const {
MONITORINFOEXW monitor_info = {};
monitor_info.cbSize = sizeof(monitor_info);
if (self->win32_->GetMonitorInfoW(monitor, &monitor_info) == 0) {
// Return TRUE to continue enumeration and skip this monitor.
// Returning FALSE would stop the entire enumeration process,
// potentially missing other valid monitors.
return TRUE;
if (win32_->GetMonitorInfoW(monitor, &monitor_info) == 0) {
return std::nullopt;
}

DEVMODEW dev_mode = {};
dev_mode.dmSize = sizeof(dev_mode);
if (!self->win32_->EnumDisplaySettingsW(monitor_info.szDevice,
ENUM_CURRENT_SETTINGS, &dev_mode)) {
// Return TRUE to continue enumeration and skip this monitor.
// Returning FALSE would stop the entire enumeration process,
// potentially missing other valid monitors.
return TRUE;
if (!win32_->EnumDisplaySettingsW(monitor_info.szDevice,
ENUM_CURRENT_SETTINGS, &dev_mode)) {
return std::nullopt;
}

UINT dpi = GetDpiForMonitor(monitor);
Expand All @@ -64,8 +52,25 @@ BOOL CALLBACK DisplayMonitor::EnumMonitorCallback(HMONITOR monitor,
display.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top;
display.device_pixel_ratio =
static_cast<double>(dpi) / static_cast<double>(kDefaultDpi);
return display;
}

displays->push_back(display);
BOOL CALLBACK DisplayMonitor::EnumMonitorCallback(HMONITOR monitor,
HDC hdc,
LPRECT rect,
LPARAM data) {
MonitorEnumState* state = reinterpret_cast<MonitorEnumState*>(data);
const DisplayMonitor* self = state->display_monitor;
std::vector<FlutterEngineDisplay>* displays = state->displays;
const std::optional<FlutterEngineDisplay> display =
self->FromMonitor(monitor);
if (!display) {
// Return TRUE to continue enumeration and skip this monitor.
// Returning FALSE would stop the entire enumeration process,
// potentially missing other valid monitors.
return TRUE;
}
displays->push_back(*display);
return TRUE;
}

Expand All @@ -88,6 +93,17 @@ bool DisplayMonitor::HandleWindowMessage(HWND hwnd,
return false;
}

std::optional<FlutterEngineDisplay> DisplayMonitor::FindById(
FlutterEngineDisplayId id) {
for (auto const& display : GetDisplays()) {
if (display.display_id == id) {
return display;
}
}

return std::nullopt;
}

std::vector<FlutterEngineDisplay> DisplayMonitor::GetDisplays() const {
std::vector<FlutterEngineDisplay> displays;
MonitorEnumState state = {this, &displays};
Expand Down
7 changes: 7 additions & 0 deletions engine/src/flutter/shell/platform/windows/display_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class DisplayMonitor {
LPARAM lparam,
LRESULT* result);

// Finds the display information associated with the id.
std::optional<FlutterEngineDisplay> FindById(FlutterEngineDisplayId id);

// Get the display information for all displays
std::vector<FlutterEngineDisplay> GetDisplays() const;

Expand All @@ -41,6 +44,10 @@ class DisplayMonitor {
LPRECT rect,
LPARAM data);

// Helper method that creates a |FlutterEngineDisplay| from the
// provided |monitor|.
std::optional<FlutterEngineDisplay> FromMonitor(HMONITOR monitor) const;

FlutterWindowsEngine* engine_;

std::shared_ptr<WindowsProcTable> win32_;
Expand Down
13 changes: 13 additions & 0 deletions engine/src/flutter/shell/platform/windows/flutter_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "flutter/fml/logging.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/windows/display_monitor.h"
#include "flutter/shell/platform/windows/dpi_utils.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
Expand Down Expand Up @@ -76,9 +77,11 @@ static uint64_t ConvertWinButtonToFlutterButton(UINT button) {
FlutterWindow::FlutterWindow(
int width,
int height,
std::shared_ptr<DisplayMonitor> const& display_monitor,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm maybe we should rename this to DisplayManager. "Monitor" is a bit on an overloaded term here, and we're using it for more than just listening to changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do that in another PR? Just want to limit the scope, I can add that to my list as a follow up

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup that sounds good to me 👍

std::shared_ptr<WindowsProcTable> windows_proc_table,
std::unique_ptr<TextInputManager> text_input_manager)
: touch_id_generator_(kMinTouchDeviceId, kMaxTouchDeviceId),
display_monitor_(display_monitor),
windows_proc_table_(std::move(windows_proc_table)),
text_input_manager_(std::move(text_input_manager)),
ax_fragment_root_(nullptr) {
Expand Down Expand Up @@ -305,6 +308,16 @@ PointerLocation FlutterWindow::GetPrimaryPointerLocation() {
return {(size_t)point.x, (size_t)point.y};
}

FlutterEngineDisplayId FlutterWindow::GetDisplayId() {
FlutterEngineDisplayId const display_id =
reinterpret_cast<FlutterEngineDisplayId>(
MonitorFromWindow(GetWindowHandle(), MONITOR_DEFAULTTONEAREST));
if (!display_monitor_->FindById(display_id)) {
FML_LOG(ERROR) << "Current monitor not found in display list.";
}
return display_id;
}

void FlutterWindow::OnThemeChange() {
binding_handler_delegate_->OnHighContrastChanged();
}
Expand Down
9 changes: 9 additions & 0 deletions engine/src/flutter/shell/platform/windows/flutter_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

namespace flutter {

class DisplayMonitor;

// A win32 flutter child window used as implementations for flutter view. In
// the future, there will likely be a CoreWindow-based FlutterWindow as well.
// At the point may make sense to dependency inject the native window rather
Expand All @@ -38,6 +40,7 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
// Create flutter Window for use as child window
FlutterWindow(int width,
int height,
std::shared_ptr<DisplayMonitor> const& display_monitor,
std::shared_ptr<WindowsProcTable> windows_proc_table = nullptr,
std::unique_ptr<TextInputManager> text_input_manager = nullptr);

Expand Down Expand Up @@ -169,6 +172,9 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
// |FlutterWindowBindingHandler|
virtual PointerLocation GetPrimaryPointerLocation() override;

// [FlutterWindowBindingHandler]
virtual FlutterEngineDisplayId GetDisplayId() override;

// Called when a theme change message is issued.
virtual void OnThemeChange();

Expand Down Expand Up @@ -356,6 +362,9 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
// Generates touch point IDs for touch events.
SequentialIdGenerator touch_id_generator_;

// Provides access to the list of available displays.
std::shared_ptr<DisplayMonitor> display_monitor_;

// Abstracts Windows APIs that may not be available on all supported versions
// of Windows.
std::shared_ptr<WindowsProcTable> windows_proc_table_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,16 @@ class FlutterWindowTest : public WindowsTest {};
} // namespace

TEST_F(FlutterWindowTest, CreateDestroy) {
FlutterWindow window(800, 600);
std::unique_ptr<FlutterWindowsEngine> engine =
FlutterWindowsEngineBuilder{GetContext()}.Build();
FlutterWindow window(800, 600, engine->display_monitor());
ASSERT_TRUE(TRUE);
}

TEST_F(FlutterWindowTest, OnBitmapSurfaceUpdated) {
FlutterWindow win32window(100, 100);
std::unique_ptr<FlutterWindowsEngine> engine =
FlutterWindowsEngineBuilder{GetContext()}.Build();
FlutterWindow win32window(100, 100, engine->display_monitor());
int old_handle_count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);

constexpr size_t row_bytes = 100 * 4;
Expand Down Expand Up @@ -162,7 +166,9 @@ TEST_F(FlutterWindowTest, OnCursorRectUpdatedHighDPI) {
}

TEST_F(FlutterWindowTest, OnPointerStarSendsDeviceType) {
FlutterWindow win32window(100, 100);
std::unique_ptr<FlutterWindowsEngine> engine =
FlutterWindowsEngineBuilder{GetContext()}.Build();
FlutterWindow win32window(100, 100, engine->display_monitor());
MockWindowBindingHandlerDelegate delegate;
EXPECT_CALL(delegate, OnWindowStateEvent).Times(AnyNumber());
win32window.SetView(&delegate);
Expand Down
3 changes: 2 additions & 1 deletion engine/src/flutter/shell/platform/windows/flutter_windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ static FlutterDesktopViewControllerRef CreateViewController(
flutter::FlutterWindowsEngine* engine_ptr = EngineFromHandle(engine_ref);
std::unique_ptr<flutter::WindowBindingHandler> window_wrapper =
std::make_unique<flutter::FlutterWindow>(
width, height, engine_ptr->windows_proc_table());
width, height, engine_ptr->display_monitor(),
engine_ptr->windows_proc_table());

std::unique_ptr<flutter::FlutterWindowsEngine> engine;
if (owns_engine) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ FlutterWindowsEngine::FlutterWindowsEngine(
static_cast<egl::GpuPreference>(project_->gpu_preference()));
window_proc_delegate_manager_ = std::make_unique<WindowProcDelegateManager>();

display_monitor_ = std::make_unique<DisplayMonitor>(this);
display_monitor_ = std::make_shared<DisplayMonitor>(this);

window_proc_delegate_manager_->RegisterTopLevelWindowProcDelegate(
[](HWND hwnd, UINT msg, WPARAM wpar, LPARAM lpar, void* user_data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class FlutterWindowsEngine {
return message_dispatcher_.get();
}

DisplayMonitor* display_monitor() { return display_monitor_.get(); }
std::shared_ptr<DisplayMonitor> display_monitor() { return display_monitor_; }

// Notifies the engine about a display update.
void UpdateDisplay(const std::vector<FlutterEngineDisplay>& displays);
Expand Down Expand Up @@ -425,7 +425,7 @@ class FlutterWindowsEngine {
mutable std::shared_mutex views_mutex_;

// The display monitor.
std::unique_ptr<DisplayMonitor> display_monitor_;
std::shared_ptr<DisplayMonitor> display_monitor_;

// Task runner for tasks posted from the engine.
std::unique_ptr<TaskRunner> task_runner_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,14 @@ void FlutterWindowsView::SendWindowMetrics(size_t width,
FlutterWindowMetricsEvent FlutterWindowsView::CreateWindowMetricsEvent() const {
PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
double pixel_ratio = binding_handler_->GetDpiScale();
FlutterEngineDisplayId display_id = binding_handler_->GetDisplayId();

FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = bounds.width;
event.height = bounds.height;
event.pixel_ratio = pixel_ratio;
event.display_id = display_id;
event.view_id = view_id_;

return event;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,8 @@ TEST(FlutterWindowsViewTest, WindowRepaintTests) {
EngineModifier modifier(engine.get());

FlutterWindowsView view{kImplicitViewId, engine.get(),
std::make_unique<flutter::FlutterWindow>(100, 100)};
std::make_unique<flutter::FlutterWindow>(
100, 100, engine->display_monitor())};

bool schedule_frame_called = false;
modifier.embedder_api().ScheduleFrame =
Expand Down Expand Up @@ -1733,5 +1734,20 @@ TEST(FlutterWindowsViewTest, OnFocusTriggersSendFocusViewEvent) {
FlutterViewFocusDirection::kUndefined);
EXPECT_TRUE(received_focus_event);
}

TEST(FlutterWindowsViewTest, WindowMetricsEventContainsDisplayId) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

auto window_binding_handler =
std::make_unique<NiceMock<MockWindowBindingHandler>>();
EXPECT_CALL(*window_binding_handler, GetDisplayId)
.WillOnce(testing::Return(12));
FlutterWindowsView view{kImplicitViewId, engine.get(),
std::move(window_binding_handler)};

FlutterWindowMetricsEvent event = view.CreateWindowMetricsEvent();
EXPECT_EQ(event.display_id, 12);
}
} // namespace testing
} // namespace flutter
10 changes: 4 additions & 6 deletions engine/src/flutter/shell/platform/windows/host_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ std::unique_ptr<HostWindow> HostWindow::CreateRegularWindow(
// Set up the view.
auto view_window = std::make_unique<FlutterWindow>(
initial_window_rect.width(), initial_window_rect.height(),
engine->windows_proc_table());
engine->display_monitor(), engine->windows_proc_table());

std::unique_ptr<FlutterWindowsView> view =
engine->CreateView(std::move(view_window));
Expand Down Expand Up @@ -627,11 +627,9 @@ void HostWindow::SetFullscreen(
HMONITOR monitor =
MonitorFromWindow(window_handle_, MONITOR_DEFAULTTONEAREST);
if (display_id) {
for (auto const& display : engine_->display_monitor()->GetDisplays()) {
if (display.display_id == display_id) {
monitor = reinterpret_cast<HMONITOR>(display.display_id);
break;
}
if (auto const display =
engine_->display_monitor()->FindById(display_id.value())) {
monitor = reinterpret_cast<HMONITOR>(display->display_id);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@

namespace flutter {
namespace testing {
MockWindow::MockWindow() : FlutterWindow(1, 1) {};
MockWindow::MockWindow() : FlutterWindow(1, 1, nullptr) {};
MockWindow::MockWindow(std::unique_ptr<WindowsProcTable> window_proc_table,
std::unique_ptr<TextInputManager> text_input_manager)
: FlutterWindow(1,
1,
nullptr,
std::move(window_proc_table),
std::move(text_input_manager)) {};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class MockWindow : public FlutterWindow {
OnImeComposition,
(UINT const, WPARAM const, LPARAM const),
(override));
MOCK_METHOD(FlutterEngineDisplayId, GetDisplayId, (), (override));

MOCK_METHOD(void, OnThemeChange, (), (override));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class MockWindowBindingHandler : public WindowBindingHandler {
MOCK_METHOD(AlertPlatformNodeDelegate*, GetAlertDelegate, (), (override));
MOCK_METHOD(ui::AXPlatformNodeWin*, GetAlert, (), (override));
MOCK_METHOD(bool, Focus, (), (override));
MOCK_METHOD(FlutterEngineDisplayId, GetDisplayId, (), (override));

private:
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowBindingHandler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "flutter/shell/platform/common/alert_platform_node_delegate.h"
#include "flutter/shell/platform/common/geometry.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/windows/public/flutter_windows.h"
#include "flutter/shell/platform/windows/window_binding_handler_delegate.h"

Expand Down Expand Up @@ -87,6 +88,10 @@ class WindowBindingHandler {
// Focuses the current window.
// Returns true if the window was successfully focused.
virtual bool Focus() = 0;

// Retrieve the display ID of the display that this window has the largest
// area of intersection with.
virtual FlutterEngineDisplayId GetDisplayId() = 0;
};

} // namespace flutter
Expand Down