diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index 2419628d..9b0572c6 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -5,6 +5,71 @@ #include "flutter/generated_plugin_registrant.h" #include "mpv/mpv_plugin.h" +// Registry key for window placement persistence +static constexpr wchar_t kWindowPlacementKey[] = L"Software\\Plezy"; +static constexpr wchar_t kWindowPlacementValue[] = L"WindowPlacement"; + +// Debounce timer for saving window placement +static UINT_PTR g_saveTimerId = 0; +static HWND g_mainHwnd = nullptr; + +// Forward declaration +static void SaveWindowPlacement(HWND hwnd); + +// Timer callback for debounced save +static void CALLBACK SaveTimerProc(HWND, UINT, UINT_PTR, DWORD) { + if (g_mainHwnd) SaveWindowPlacement(g_mainHwnd); + KillTimer(nullptr, g_saveTimerId); + g_saveTimerId = 0; +} + +// Save WINDOWPLACEMENT to registry +static void SaveWindowPlacement(HWND hwnd) { + WINDOWPLACEMENT wp{}; + wp.length = sizeof(wp); + if (!GetWindowPlacement(hwnd, &wp)) return; + + HKEY hKey; + if (RegCreateKeyExW(HKEY_CURRENT_USER, kWindowPlacementKey, 0, nullptr, + REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, + nullptr) == ERROR_SUCCESS) { + RegSetValueExW(hKey, kWindowPlacementValue, 0, REG_BINARY, + reinterpret_cast(&wp), sizeof(wp)); + RegCloseKey(hKey); + } +} + +// Load and apply WINDOWPLACEMENT from registry +static bool LoadWindowPlacement(HWND hwnd) { + HKEY hKey; + if (RegOpenKeyExW(HKEY_CURRENT_USER, kWindowPlacementKey, 0, KEY_READ, + &hKey) != ERROR_SUCCESS) + return false; + + WINDOWPLACEMENT wp{}; + wp.length = sizeof(wp); + DWORD size = sizeof(wp); + bool success = false; + + if (RegQueryValueExW(hKey, kWindowPlacementValue, nullptr, nullptr, + reinterpret_cast(&wp), &size) == ERROR_SUCCESS && + size == sizeof(wp)) { + // Prevent restoring as minimized + if (wp.showCmd == SW_SHOWMINIMIZED) wp.showCmd = SW_SHOWNORMAL; + success = SetWindowPlacement(hwnd, &wp) != 0; + } + + RegCloseKey(hKey); + return success; +} + +// Debounce save to avoid excessive registry writes during resize/move +static void DebounceSaveWindowPlacement(HWND hwnd) { + g_mainHwnd = hwnd; + if (g_saveTimerId) KillTimer(nullptr, g_saveTimerId); + g_saveTimerId = SetTimer(nullptr, 0, 500, SaveTimerProc); // 500ms debounce +} + FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} @@ -35,7 +100,11 @@ bool FlutterWindow::OnCreate() { SetChildContent(flutter_controller_->view()->GetNativeWindow()); - flutter_controller_->engine()->SetNextFrameCallback([&]() { + // Load saved window placement before showing + HWND hwnd = GetHandle(); + bool hasPlacement = LoadWindowPlacement(hwnd); + + flutter_controller_->engine()->SetNextFrameCallback([this, hasPlacement]() { this->Show(); }); @@ -48,6 +117,13 @@ bool FlutterWindow::OnCreate() { } void FlutterWindow::OnDestroy() { + // Cancel any pending save timer and save immediately + if (g_saveTimerId) { + KillTimer(nullptr, g_saveTimerId); + g_saveTimerId = 0; + } + SaveWindowPlacement(GetHandle()); + if (flutter_controller_) { flutter_controller_ = nullptr; } @@ -73,6 +149,9 @@ FlutterWindow::MessageHandler(HWND hwnd, UINT const message, case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; + case WM_WINDOWPOSCHANGED: + DebounceSaveWindowPlacement(hwnd); + break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam);