这是indexloc提供的服务,不要输入任何密码
Skip to content
Closed
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
3 changes: 3 additions & 0 deletions engine/src/flutter/shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ source_set("flutter_windows_source") {
"cursor_handler.h",
"direct_manipulation.cc",
"direct_manipulation.h",
"display_manager.cc",
"display_manager.h",
"dpi_utils.cc",
"dpi_utils.h",
"egl/context.cc",
Expand Down Expand Up @@ -206,6 +208,7 @@ executable("flutter_windows_unittests") {
"compositor_software_unittests.cc",
"cursor_handler_unittests.cc",
"direct_manipulation_unittests.cc",
"display_manager_unittests.cc",
"dpi_utils_unittests.cc",
"flutter_project_bundle_unittests.cc",
"flutter_window_unittests.cc",
Expand Down
142 changes: 142 additions & 0 deletions engine/src/flutter/shell/platform/windows/display_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2013 The Flutter 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/shell/platform/windows/display_manager.h"
#include "flutter/shell/platform/windows/dpi_utils.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"

#include <memory>
#include "flutter/fml/logging.h"

namespace flutter {
namespace {
struct CallbackData {
std::shared_ptr<WindowsProcTable> windows_proc_table;
std::vector<FlutterEngineDisplay> displays;
};
} // namespace

DisplayManager::DisplayManager(FlutterWindowsEngine* engine) : engine_(engine) {
WNDCLASS window_class = RegisterWindowClass();
window_handle_ =
CreateWindowEx(0, window_class.lpszClassName, L"", 0, 0, 0, 0, 0,
HWND_MESSAGE, nullptr, window_class.hInstance, nullptr);

if (window_handle_) {
SetWindowLongPtr(window_handle_, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(this));
} else {
auto error = GetLastError();
LPWSTR message = nullptr;
size_t size = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, NULL);
OutputDebugString(message);
LocalFree(message);
Comment on lines +30 to +38
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For consistency with the rest of the Flutter engine code, it's better to use FML_LOG(ERROR) instead of OutputDebugString. This ensures that error messages are routed through the standard logging channels.

The current implementation also doesn't check if FormatMessageW succeeds, which could lead to issues if message is nullptr. The suggested change below addresses these points.

Please also add #include "flutter/fml/platform/win/wstring_conversion.h" at the top of the file to use fml::WideToUtf8.

    const auto error = GetLastError();
    LPWSTR message_buffer = nullptr;
    size_t size = FormatMessageW(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        reinterpret_cast<LPWSTR>(&message_buffer), 0, nullptr);
    if (size > 0 && message_buffer) {
      FML_LOG(ERROR) << "Failed to create display manager window: "
                     << fml::WideToUtf8(message_buffer);
      LocalFree(message_buffer);
    } else {
      FML_LOG(ERROR) << "Failed to create display manager window. Error code: "
                     << error;
    }

}
}

DisplayManager::~DisplayManager() {
if (window_handle_) {
DestroyWindow(window_handle_);
window_handle_ = nullptr;
}
UnregisterClass(window_class_name_.c_str(), nullptr);
}

std::vector<FlutterEngineDisplay> DisplayManager::displays() const {
auto windows_proc_table = engine_->windows_proc_table();
CallbackData data = {windows_proc_table, std::vector<FlutterEngineDisplay>()};
windows_proc_table->EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc,
reinterpret_cast<LPARAM>(&data));

if (data.displays.size() == 1) {
data.displays[0].single_display = true;
}

return data.displays;
}

WNDCLASS DisplayManager::RegisterWindowClass() {
window_class_name_ = L"FlutterDisplayManager";

WNDCLASS window_class{};
window_class.hCursor = nullptr;
window_class.lpszClassName = window_class_name_.c_str();
window_class.style = 0;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = GetModuleHandle(nullptr);
window_class.hIcon = nullptr;
window_class.hbrBackground = 0;
window_class.lpszMenuName = nullptr;
window_class.lpfnWndProc = WndProc;
RegisterClass(&window_class);
return window_class;
}

LRESULT
DisplayManager::HandleMessage(UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
switch (message) {
case WM_DISPLAYCHANGE:
case WM_DEVICECHANGE: {
if (engine_->running()) {
engine_->OnDisplaysChanged(displays());
}
break;
}
}
return DefWindowProcW(window_handle_, message, wparam, lparam);
}

LRESULT DisplayManager::WndProc(HWND const window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
if (auto* that = reinterpret_cast<DisplayManager*>(
GetWindowLongPtr(window, GWLP_USERDATA))) {
return that->HandleMessage(message, wparam, lparam);
} else {
return DefWindowProc(window, message, wparam, lparam);
}
}

BOOL CALLBACK DisplayManager::MonitorEnumProc(HMONITOR hMonitor,
HDC,
LPRECT,
LPARAM lParam) {
auto data = reinterpret_cast<CallbackData*>(lParam);

MONITORINFOEX monitor_info = {};
monitor_info.cbSize = sizeof(MONITORINFOEX);
if (!data->windows_proc_table->GetMonitorInfo(hMonitor, &monitor_info)) {
return TRUE;
}

// Get display settings
DEVMODE dev_mode = {};
dev_mode.dmSize = sizeof(DEVMODE);
bool has_display_settings = data->windows_proc_table->EnumDisplaySettingsW(
monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode);

FlutterEngineDisplay display;
display.struct_size = sizeof(FlutterEngineDisplay);
display.display_id = reinterpret_cast<FlutterEngineDisplayId>(hMonitor);
display.single_display = false;
display.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left;
display.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top;
display.refresh_rate = has_display_settings
? static_cast<double>(dev_mode.dmDisplayFrequency)
: 0.0;
display.device_pixel_ratio = GetDpiForMonitor(hMonitor);

data->displays.push_back(display);
return TRUE;
}

} // namespace flutter
51 changes: 51 additions & 0 deletions engine/src/flutter/shell/platform/windows/display_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_DISPLAY_MANAGER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_DISPLAY_MANAGER_H_

#include <windows.h>
#include <string>
#include <vector>

#include "flutter/shell/platform/embedder/embedder.h"

namespace flutter {
class FlutterWindowsEngine;

class DisplayManager {
public:
DisplayManager(FlutterWindowsEngine* engine);
virtual ~DisplayManager();
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The destructor is marked virtual, but DisplayManager doesn't seem to be designed as a base class. According to the Google C++ Style Guide, destructors should only be virtual in classes intended for inheritance.1

Please consider making the destructor non-virtual.

  ~DisplayManager();

Style Guide References

Footnotes

  1. C++ code should follow the Google C++ Style Guide, which recommends non-virtual destructors for classes not intended to be base classes. (link)


std::vector<FlutterEngineDisplay> displays() const;

HWND get_window_handle() const { return window_handle_; }

private:
WNDCLASS
RegisterWindowClass();

LRESULT
HandleMessage(UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;

static LRESULT CALLBACK WndProc(HWND const window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;

static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor,
HDC,
LPRECT,
LPARAM lParam);

FlutterWindowsEngine* engine_;
HWND window_handle_;
std::wstring window_class_name_;
};
} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_DISPLAY_MANAGER_H_
Loading