Skip to content

Commit b44e867

Browse files
committed
Add support for modifyRegular in the embedder and update examples/tests
1 parent b4a3c73 commit b44e867

File tree

12 files changed

+483
-163
lines changed

12 files changed

+483
-163
lines changed

engine/src/flutter/shell/platform/common/windowing.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ struct WindowCreationSettings {
7575
std::optional<WindowState> state;
7676
};
7777

78+
// Settings for modifying a Flutter window.
79+
struct WindowModificationSettings {
80+
// The new requested size, in logical coordinates.
81+
std::optional<Size> size;
82+
// The new window title.
83+
std::optional<std::string> title;
84+
// The new window state.
85+
std::optional<WindowState> state;
86+
};
87+
7888
// Window metadata returned as the result of creating a Flutter window.
7989
struct WindowMetadata {
8090
// The ID of the view used for this window, which is unique to each window.

engine/src/flutter/shell/platform/windows/flutter_host_window.cc

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,15 @@ bool IsClassRegistered(LPCWSTR class_name) {
213213
}
214214

215215
// Convert std::string to std::wstring.
216-
std::wstring StringToWstring(std::string const& str) {
216+
std::wstring StringToWstring(std::string_view str) {
217217
if (str.empty()) {
218218
return {};
219219
}
220220
if (int buffer_size =
221-
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0)) {
221+
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0)) {
222222
std::wstring wide_str(buffer_size, L'\0');
223-
if (MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &wide_str[0],
223+
if (MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &wide_str[0],
224224
buffer_size)) {
225-
wide_str.pop_back();
226225
return wide_str;
227226
}
228227
}
@@ -447,14 +446,6 @@ FlutterHostWindow* FlutterHostWindow::GetThisFromHandle(HWND hwnd) {
447446
GetWindowLongPtr(hwnd, GWLP_USERDATA));
448447
}
449448

450-
WindowArchetype FlutterHostWindow::GetArchetype() const {
451-
return archetype_;
452-
}
453-
454-
FlutterViewId FlutterHostWindow::GetFlutterViewId() const {
455-
return view_controller_->view()->view_id();
456-
};
457-
458449
WindowState FlutterHostWindow::GetState() const {
459450
return state_;
460451
}
@@ -463,14 +454,6 @@ HWND FlutterHostWindow::GetWindowHandle() const {
463454
return window_handle_;
464455
}
465456

466-
void FlutterHostWindow::SetQuitOnClose(bool quit_on_close) {
467-
quit_on_close_ = quit_on_close;
468-
}
469-
470-
bool FlutterHostWindow::GetQuitOnClose() const {
471-
return quit_on_close_;
472-
}
473-
474457
void FlutterHostWindow::FocusViewOf(FlutterHostWindow* window) {
475458
if (window != nullptr && window->child_content_ != nullptr) {
476459
SetFocus(window->child_content_);
@@ -587,6 +570,19 @@ LRESULT FlutterHostWindow::HandleMessage(HWND hwnd,
587570
return DefWindowProc(hwnd, message, wparam, lparam);
588571
}
589572

573+
void FlutterHostWindow::SetClientSize(Size const& client_size) const {
574+
WINDOWINFO window_info = {.cbSize = sizeof(WINDOWINFO)};
575+
GetWindowInfo(window_handle_, &window_info);
576+
577+
std::optional<Size> const window_size = GetWindowSizeForClientSize(
578+
client_size, min_size_, max_size_, window_info.dwStyle,
579+
window_info.dwExStyle, nullptr);
580+
581+
Size const size = window_size.value_or(client_size);
582+
SetWindowPos(window_handle_, NULL, 0, 0, size.width(), size.height(),
583+
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
584+
}
585+
590586
void FlutterHostWindow::SetChildContent(HWND content) {
591587
child_content_ = content;
592588
SetParent(content, window_handle_);
@@ -597,4 +593,9 @@ void FlutterHostWindow::SetChildContent(HWND content) {
597593
client_rect.bottom - client_rect.top, true);
598594
}
599595

596+
void FlutterHostWindow::SetTitle(std::string_view title) const {
597+
std::wstring title_wide = StringToWstring(title);
598+
SetWindowText(window_handle_, title_wide.c_str());
599+
}
600+
600601
} // namespace flutter

engine/src/flutter/shell/platform/windows/flutter_host_window.h

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,13 @@ class FlutterHostWindow {
3333
// Returns the instance pointer for |hwnd| or nulllptr if invalid.
3434
static FlutterHostWindow* GetThisFromHandle(HWND hwnd);
3535

36-
// Returns the window archetype.
37-
WindowArchetype GetArchetype() const;
38-
39-
// Returns the hosted Flutter view's ID.
40-
FlutterViewId GetFlutterViewId() const;
41-
4236
// Returns the current window state.
4337
WindowState GetState() const;
4438

4539
// Returns the backing window handle, or nullptr if the native window is not
4640
// created or has already been destroyed.
4741
HWND GetWindowHandle() const;
4842

49-
// Sets whether closing this window will quit the application.
50-
void SetQuitOnClose(bool quit_on_close);
51-
52-
// Returns whether closing this window will quit the application.
53-
bool GetQuitOnClose() const;
54-
5543
private:
5644
friend FlutterHostWindowController;
5745

@@ -69,9 +57,15 @@ class FlutterHostWindow {
6957
// inheriting classes can handle.
7058
LRESULT HandleMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
7159

60+
// Resizes the window to accommodate a client area of the given |client_size|.
61+
void SetClientSize(Size const& client_size) const;
62+
7263
// Inserts |content| into the window tree.
7364
void SetChildContent(HWND content);
7465

66+
// Sets the window title.
67+
void SetTitle(std::string_view title) const;
68+
7569
// Controller for this window.
7670
FlutterHostWindowController* const window_controller_;
7771

engine/src/flutter/shell/platform/windows/flutter_host_window_controller.cc

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "flutter/shell/platform/common/windowing.h"
1010
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
11+
#include "flutter/shell/platform/windows/flutter_windows_view_controller.h"
1112

1213
namespace flutter {
1314

@@ -44,27 +45,73 @@ std::optional<WindowMetadata> FlutterHostWindowController::CreateHostWindow(
4445

4546
// Assume first window is the main window.
4647
if (windows_.empty()) {
47-
window->SetQuitOnClose(true);
48+
window->quit_on_close_ = true;
4849
}
4950

50-
FlutterViewId const view_id = window->GetFlutterViewId();
51-
WindowState const state = window->GetState();
51+
FlutterViewId const view_id = window->view_controller_->view()->view_id();
52+
WindowState const state = window->state_;
5253
windows_[view_id] = std::move(window);
5354

5455
WindowMetadata const result = {.view_id = view_id,
5556
.archetype = settings.archetype,
56-
.size = GetWindowSize(view_id),
57+
.size = GetViewSize(view_id),
5758
.parent_id = std::nullopt,
5859
.state = state};
5960

6061
return result;
6162
}
6263

63-
bool FlutterHostWindowController::DestroyHostWindow(FlutterViewId view_id) {
64-
if (auto const it = windows_.find(view_id); it != windows_.end()) {
65-
FlutterHostWindow* const window = it->second.get();
66-
HWND const window_handle = window->GetWindowHandle();
64+
bool FlutterHostWindowController::ModifyHostWindow(
65+
FlutterViewId view_id,
66+
WindowModificationSettings const& settings) const {
67+
FlutterHostWindow* const window = GetHostWindow(view_id);
68+
if (!window) {
69+
return false;
70+
}
71+
72+
HWND const window_handle = window->GetWindowHandle();
73+
74+
std::optional<Size> changed_size;
75+
if (settings.size.has_value()) {
76+
Size const view_size_before = GetViewSize(view_id);
77+
window->SetClientSize(*settings.size);
78+
Size const view_size_after = GetViewSize(view_id);
79+
if (!(view_size_before == view_size_after)) {
80+
changed_size = view_size_after;
81+
}
82+
}
83+
if (settings.title.has_value()) {
84+
window->SetTitle(*settings.title);
85+
}
86+
if (settings.state.has_value()) {
87+
WINDOWPLACEMENT window_placement = {.length = sizeof(WINDOWPLACEMENT)};
88+
if (GetWindowPlacement(window_handle, &window_placement)) {
89+
window_placement.showCmd = [&]() {
90+
switch (*settings.state) {
91+
case WindowState::kRestored:
92+
return SW_RESTORE;
93+
case WindowState::kMaximized:
94+
return SW_MAXIMIZE;
95+
case WindowState::kMinimized:
96+
return SW_MINIMIZE;
97+
default:
98+
FML_UNREACHABLE();
99+
};
100+
}();
101+
SetWindowPlacement(window_handle, &window_placement);
102+
}
103+
}
104+
105+
if (changed_size) {
106+
SendOnWindowChanged(view_id, changed_size, std::nullopt);
107+
}
67108

109+
return true;
110+
}
111+
112+
bool FlutterHostWindowController::DestroyHostWindow(
113+
FlutterViewId view_id) const {
114+
if (FlutterHostWindow* const window = GetHostWindow(view_id)) {
68115
// |window| will be removed from |windows_| when WM_NCDESTROY is handled.
69116
PostMessage(window->GetWindowHandle(), WM_CLOSE, 0, 0);
70117

@@ -93,7 +140,7 @@ LRESULT FlutterHostWindowController::HandleMessage(HWND hwnd,
93140
});
94141
if (it != windows_.end()) {
95142
FlutterViewId const view_id = it->first;
96-
bool const quit_on_close = it->second->GetQuitOnClose();
143+
bool const quit_on_close = it->second->quit_on_close_;
97144

98145
windows_.erase(it);
99146

@@ -118,7 +165,7 @@ LRESULT FlutterHostWindowController::HandleMessage(HWND hwnd,
118165
? WindowState::kMinimized
119166
: WindowState::kRestored;
120167
}
121-
SendOnWindowChanged(view_id, GetWindowSize(view_id), std::nullopt);
168+
SendOnWindowChanged(view_id, GetViewSize(view_id), std::nullopt);
122169
}
123170
} break;
124171
default:
@@ -155,17 +202,14 @@ void FlutterHostWindowController::DestroyAllWindows() {
155202
}
156203
}
157204

158-
Size FlutterHostWindowController::GetWindowSize(FlutterViewId view_id) const {
159-
HWND const hwnd = windows_.at(view_id)->GetWindowHandle();
160-
RECT frame_rect;
161-
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame_rect,
162-
sizeof(frame_rect));
163-
164-
// Convert to logical coordinates.
165-
double const dpr = FlutterDesktopGetDpiForHWND(hwnd) /
205+
Size FlutterHostWindowController::GetViewSize(FlutterViewId view_id) const {
206+
HWND const window_handle = GetHostWindow(view_id)->GetWindowHandle();
207+
RECT rect;
208+
GetClientRect(window_handle, &rect);
209+
double const dpr = FlutterDesktopGetDpiForHWND(window_handle) /
166210
static_cast<double>(USER_DEFAULT_SCREEN_DPI);
167-
double const width = (frame_rect.right - frame_rect.left) / dpr;
168-
double const height = (frame_rect.bottom - frame_rect.top) / dpr;
211+
double const width = rect.right / dpr;
212+
double const height = rect.bottom / dpr;
169213
return {width, height};
170214
}
171215

engine/src/flutter/shell/platform/windows/flutter_host_window_controller.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,21 @@ class FlutterHostWindowController {
3434
virtual std::optional<WindowMetadata> CreateHostWindow(
3535
WindowCreationSettings const& settings);
3636

37+
// Modifies the attributes of the window hosting the view with ID |view_id|
38+
// according to the given |settings|. A "onWindowChanged" message is sent if
39+
// at least one attribute is modified.
40+
//
41+
// Returns false if the controller does not have a window hosting a view with
42+
// ID |view_id|.
43+
virtual bool ModifyHostWindow(
44+
FlutterViewId view_id,
45+
WindowModificationSettings const& settings) const;
46+
3747
// Destroys the window that hosts the view with ID |view_id|.
3848
//
3949
// Returns false if the controller does not have a window hosting a view with
4050
// ID |view_id|.
41-
virtual bool DestroyHostWindow(FlutterViewId view_id);
51+
virtual bool DestroyHostWindow(FlutterViewId view_id) const;
4252

4353
// Gets the window hosting the view with ID |view_id|.
4454
//
@@ -62,9 +72,8 @@ class FlutterHostWindowController {
6272
// Destroys all windows managed by this controller.
6373
void DestroyAllWindows();
6474

65-
// Gets the size of the host window for the view with ID |view_id|. The size
66-
// is in logical coordinates and excludes the drop-shadow area.
67-
Size GetWindowSize(FlutterViewId view_id) const;
75+
// Retrieves the size of the view with ID |view_id|, in logical coordinates.
76+
Size GetViewSize(FlutterViewId view_id) const;
6877

6978
// Sends the "onWindowChanged" message to the Flutter engine.
7079
void SendOnWindowChanged(FlutterViewId view_id,

0 commit comments

Comments
 (0)