Skip to content

Commit 5bbdf39

Browse files
authored
Merge pull request #61 from adeeteya/windows_size_persistence
closes #55, allowing window size persistence on windows
2 parents 4d43ef8 + 0962146 commit 5bbdf39

4 files changed

Lines changed: 153 additions & 8 deletions

File tree

windows/runner/main.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <cmath>
12
#include <flutter/dart_project.h>
23
#include <flutter/flutter_view_controller.h>
34
#include <windows.h>
@@ -27,6 +28,27 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
2728
FlutterWindow window(project);
2829
Win32Window::Point origin(10, 10);
2930
Win32Window::Size size(400, 800);
31+
if (auto stored_size = LoadStoredWindowSize()) {
32+
int restored_width = stored_size->width;
33+
int restored_height = stored_size->height;
34+
if (stored_size->is_physical) {
35+
const POINT target_point = {static_cast<LONG>(origin.x),
36+
static_cast<LONG>(origin.y)};
37+
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
38+
UINT dpi = 96;
39+
if (monitor != nullptr) {
40+
dpi = FlutterDesktopGetDpiForMonitor(monitor);
41+
}
42+
double scale_factor = dpi / 96.0;
43+
if (scale_factor <= 0.0) {
44+
scale_factor = 1.0;
45+
}
46+
restored_width = static_cast<int>(std::round(restored_width / scale_factor));
47+
restored_height = static_cast<int>(std::round(restored_height / scale_factor));
48+
SaveWindowSize(StoredWindowSize{restored_width, restored_height, false});
49+
}
50+
size = Win32Window::Size(restored_width, restored_height);
51+
}
3052
if (!window.Create(L"ClassiPod", origin, size)) {
3153
return EXIT_FAILURE;
3254
}

windows/runner/utils.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77

88
#include <iostream>
99

10+
namespace {
11+
constexpr wchar_t kWindowSizeRegistryKey[] = L"Software\\ClassiPod";
12+
constexpr wchar_t kWindowWidthValueName[] = L"WindowWidth";
13+
constexpr wchar_t kWindowHeightValueName[] = L"WindowHeight";
14+
constexpr wchar_t kWindowSizeIsLogicalValueName[] = L"WindowSizeIsLogical";
15+
}
16+
1017
void CreateAndAttachConsole() {
1118
if (::AllocConsole()) {
1219
FILE *unused;
@@ -41,6 +48,80 @@ std::vector<std::string> GetCommandLineArguments() {
4148
return command_line_arguments;
4249
}
4350

51+
std::optional<StoredWindowSize> LoadStoredWindowSize() {
52+
HKEY key_handle;
53+
if (RegOpenKeyEx(HKEY_CURRENT_USER, kWindowSizeRegistryKey, 0, KEY_READ,
54+
&key_handle) != ERROR_SUCCESS) {
55+
return std::nullopt;
56+
}
57+
58+
DWORD width_value = 0;
59+
DWORD width_size = sizeof(width_value);
60+
if (RegQueryValueEx(key_handle, kWindowWidthValueName, nullptr, nullptr,
61+
reinterpret_cast<LPBYTE>(&width_value),
62+
&width_size) != ERROR_SUCCESS) {
63+
RegCloseKey(key_handle);
64+
return std::nullopt;
65+
}
66+
67+
DWORD height_value = 0;
68+
DWORD height_size = sizeof(height_value);
69+
if (RegQueryValueEx(key_handle, kWindowHeightValueName, nullptr, nullptr,
70+
reinterpret_cast<LPBYTE>(&height_value),
71+
&height_size) != ERROR_SUCCESS) {
72+
RegCloseKey(key_handle);
73+
return std::nullopt;
74+
}
75+
76+
DWORD logical_flag = 0;
77+
DWORD logical_flag_size = sizeof(logical_flag);
78+
bool is_physical = true;
79+
if (RegQueryValueEx(key_handle, kWindowSizeIsLogicalValueName, nullptr,
80+
nullptr, reinterpret_cast<LPBYTE>(&logical_flag),
81+
&logical_flag_size) == ERROR_SUCCESS) {
82+
is_physical = logical_flag != 1;
83+
}
84+
85+
RegCloseKey(key_handle);
86+
87+
if (width_value == 0 || height_value == 0) {
88+
return std::nullopt;
89+
}
90+
91+
return StoredWindowSize{static_cast<int>(width_value),
92+
static_cast<int>(height_value), is_physical};
93+
}
94+
95+
void SaveWindowSize(const StoredWindowSize& size) {
96+
if (size.width <= 0 || size.height <= 0) {
97+
return;
98+
}
99+
100+
HKEY key_handle;
101+
if (RegCreateKeyEx(HKEY_CURRENT_USER, kWindowSizeRegistryKey, 0, nullptr,
102+
REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &key_handle,
103+
nullptr) != ERROR_SUCCESS) {
104+
return;
105+
}
106+
107+
DWORD width_value = static_cast<DWORD>(size.width);
108+
RegSetValueEx(key_handle, kWindowWidthValueName, 0, REG_DWORD,
109+
reinterpret_cast<const BYTE*>(&width_value),
110+
sizeof(width_value));
111+
112+
DWORD height_value = static_cast<DWORD>(size.height);
113+
RegSetValueEx(key_handle, kWindowHeightValueName, 0, REG_DWORD,
114+
reinterpret_cast<const BYTE*>(&height_value),
115+
sizeof(height_value));
116+
117+
DWORD logical_flag = size.is_physical ? 0 : 1;
118+
RegSetValueEx(key_handle, kWindowSizeIsLogicalValueName, 0, REG_DWORD,
119+
reinterpret_cast<const BYTE*>(&logical_flag),
120+
sizeof(logical_flag));
121+
122+
RegCloseKey(key_handle);
123+
}
124+
44125
std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45126
if (utf16_string == nullptr) {
46127
return std::string();

windows/runner/utils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
#ifndef RUNNER_UTILS_H_
22
#define RUNNER_UTILS_H_
33

4+
#include <optional>
45
#include <string>
56
#include <vector>
67

8+
struct StoredWindowSize {
9+
int width;
10+
int height;
11+
// True when the stored values represent physical pixels, false for logical
12+
// coordinates.
13+
bool is_physical;
14+
};
15+
716
// Creates a console for the process, and redirects stdout and stderr to
817
// it for both the runner and the Flutter library.
918
void CreateAndAttachConsole();
@@ -16,4 +25,10 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string);
1625
// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
1726
std::vector<std::string> GetCommandLineArguments();
1827

28+
// Loads the last saved window size, if present.
29+
std::optional<StoredWindowSize> LoadStoredWindowSize();
30+
31+
// Persists the provided window size for future runs.
32+
void SaveWindowSize(const StoredWindowSize& size);
33+
1934
#endif // RUNNER_UTILS_H_

windows/runner/win32_window.cpp

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include "win32_window.h"
22

3+
#include <cmath>
34
#include <dwmapi.h>
45
#include <flutter_windows.h>
56

67
#include "resource.h"
8+
#include "utils.h"
79

810
namespace {
911

@@ -179,14 +181,39 @@ Win32Window::MessageHandler(HWND hwnd,
179181
WPARAM const wparam,
180182
LPARAM const lparam) noexcept {
181183
switch (message) {
182-
case WM_DESTROY:
183-
window_handle_ = nullptr;
184-
Destroy();
185-
if (quit_on_close_) {
186-
PostQuitMessage(0);
187-
}
188-
return 0;
189-
184+
case WM_DESTROY:{
185+
WINDOWPLACEMENT placement;
186+
placement.length = sizeof(WINDOWPLACEMENT);
187+
if (GetWindowPlacement(hwnd, &placement)) {
188+
RECT rect = placement.rcNormalPosition;
189+
int width = rect.right - rect.left;
190+
int height = rect.bottom - rect.top;
191+
192+
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
193+
UINT dpi = 96;
194+
if (monitor != nullptr) {
195+
dpi = FlutterDesktopGetDpiForMonitor(monitor);
196+
}
197+
double scale_factor = dpi / 96.0;
198+
if (scale_factor <= 0.0) {
199+
scale_factor = 1.0;
200+
}
201+
202+
int logical_width =
203+
static_cast<int>(std::round(width / scale_factor));
204+
int logical_height =
205+
static_cast<int>(std::round(height / scale_factor));
206+
207+
SaveWindowSize(
208+
StoredWindowSize{logical_width, logical_height, false});
209+
}
210+
window_handle_ = nullptr;
211+
Destroy();
212+
if (quit_on_close_) {
213+
PostQuitMessage(0);
214+
}
215+
return 0;
216+
}
190217
case WM_DPICHANGED: {
191218
auto newRectSize = reinterpret_cast<RECT*>(lparam);
192219
LONG newWidth = newRectSize->right - newRectSize->left;

0 commit comments

Comments
 (0)