@@ -15,6 +15,17 @@ namespace {
1515
1616constexpr wchar_t kWindowClassName [] = L" FLUTTER_HOST_WINDOW" ;
1717
18+ // RAII wrapper for global Win32 ATOMs.
19+ struct AtomRAII {
20+ explicit AtomRAII (wchar_t const * name) : atom(GlobalAddAtom(name)) {}
21+ ~AtomRAII () { GlobalDeleteAtom (atom); }
22+ ATOM const atom;
23+ };
24+
25+ // Atom used as the identifier for a window property that stores a pointer to a
26+ // |FlutterHostWindow| instance.
27+ AtomRAII const kWindowPropAtom (kWindowClassName );
28+
1829// Clamps |size| to the size of the virtual screen. Both the parameter and
1930// return size are in physical coordinates.
2031flutter::Size ClampToVirtualScreen (flutter::Size size) {
@@ -212,7 +223,7 @@ bool IsClassRegistered(LPCWSTR class_name) {
212223 0 ;
213224}
214225
215- // Convert std::string to std::wstring.
226+ // Converts std::string to std::wstring.
216227std::wstring StringToWstring (std::string_view str) {
217228 if (str.empty ()) {
218229 return {};
@@ -238,7 +249,7 @@ std::wstring StringToWstring(std::string_view str) {
238249#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
239250#endif
240251
241- // Update the window frame's theme to match the system theme.
252+ // Updates the window frame's theme to match the system theme.
242253void UpdateTheme (HWND window) {
243254 // Registry key for app theme preference.
244255 const wchar_t kGetPreferredBrightnessRegKey [] =
@@ -261,6 +272,31 @@ void UpdateTheme(HWND window) {
261272 }
262273}
263274
275+ // Associates |instance| with the window |hwnd| as a window property.
276+ // Can be retrieved later using GetInstanceProperty.
277+ // Logs an error if setting the property fails.
278+ void SetInstanceProperty (HWND hwnd, flutter::FlutterHostWindow* instance) {
279+ if (!SetProp (hwnd, MAKEINTATOM (kWindowPropAtom .atom ), instance)) {
280+ FML_LOG (ERROR) << " Failed to set up instance entry in the property list: "
281+ << GetLastErrorAsString ();
282+ }
283+ }
284+
285+ // Retrieves the instance pointer set with SetInstanceProperty, or returns
286+ // nullptr if the property was not set.
287+ flutter::FlutterHostWindow* GetInstanceProperty (HWND hwnd) {
288+ return reinterpret_cast <flutter::FlutterHostWindow*>(
289+ GetProp (hwnd, MAKEINTATOM (kWindowPropAtom .atom )));
290+ }
291+
292+ // Removes the instance property associated with |hwnd| previously set with
293+ // SetInstanceProperty. Logs an error if the property is not found.
294+ void RemoveInstanceProperty (HWND hwnd) {
295+ if (!RemoveProp (hwnd, MAKEINTATOM (kWindowPropAtom .atom ))) {
296+ FML_LOG (ERROR) << " Failed to locate instance entry in the property list" ;
297+ }
298+ }
299+
264300} // namespace
265301
266302namespace flutter {
@@ -303,6 +339,35 @@ FlutterHostWindow::FlutterHostWindow(FlutterHostWindowController* controller,
303339 window_size ? *window_size : Size{CW_USEDEFAULT, CW_USEDEFAULT}};
304340 }();
305341
342+ // Set up the view.
343+ FlutterWindowsEngine* const engine = window_controller_->engine ();
344+ auto view_window = std::make_unique<FlutterWindow>(
345+ initial_window_rect.width (), initial_window_rect.height (),
346+ engine->windows_proc_table ());
347+
348+ std::unique_ptr<FlutterWindowsView> view =
349+ engine->CreateView (std::move (view_window));
350+ if (!view) {
351+ FML_LOG (ERROR) << " Failed to create view" ;
352+ return ;
353+ }
354+
355+ view_controller_ =
356+ std::make_unique<FlutterWindowsViewController>(nullptr , std::move (view));
357+ FML_CHECK (engine->running ());
358+ // Must happen after engine is running.
359+ view_controller_->view ()->SendInitialBounds ();
360+ // The Windows embedder listens to accessibility updates using the
361+ // view's HWND. The embedder's accessibility features may be stale if
362+ // the app was in headless mode.
363+ view_controller_->engine ()->UpdateAccessibilityFeatures ();
364+
365+ // Ensure that basic setup of the view controller was successful.
366+ if (!view_controller_->view ()) {
367+ FML_LOG (ERROR) << " Failed to set up the view controller" ;
368+ return ;
369+ }
370+
306371 // Register the window class.
307372 if (!IsClassRegistered (kWindowClassName )) {
308373 auto const idi_app_icon = 101 ;
@@ -354,44 +419,6 @@ FlutterHostWindow::FlutterHostWindow(FlutterHostWindowController* controller,
354419 window_rect.top - top_dropshadow_height, 0 , 0 ,
355420 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
356421
357- // Set up the view.
358- RECT client_rect;
359- GetClientRect (hwnd, &client_rect);
360- int const width = client_rect.right - client_rect.left ;
361- int const height = client_rect.bottom - client_rect.top ;
362-
363- FlutterWindowsEngine* const engine = window_controller_->engine ();
364- auto view_window = std::make_unique<FlutterWindow>(
365- width, height, engine->windows_proc_table ());
366-
367- std::unique_ptr<FlutterWindowsView> view =
368- engine->CreateView (std::move (view_window));
369- if (!view) {
370- FML_LOG (ERROR) << " Failed to create view" ;
371- return ;
372- }
373-
374- view_controller_ =
375- std::make_unique<FlutterWindowsViewController>(nullptr , std::move (view));
376-
377- // Launch the engine if it is not running already.
378- if (!engine->running () && !engine->Run ()) {
379- FML_LOG (ERROR) << " Failed to launch engine" ;
380- return ;
381- }
382- // Must happen after engine is running.
383- view_controller_->view ()->SendInitialBounds ();
384- // The Windows embedder listens to accessibility updates using the
385- // view's HWND. The embedder's accessibility features may be stale if
386- // the app was in headless mode.
387- view_controller_->engine ()->UpdateAccessibilityFeatures ();
388-
389- // Ensure that basic setup of the view controller was successful.
390- if (!view_controller_->view ()) {
391- FML_LOG (ERROR) << " Failed to set up the view controller" ;
392- return ;
393- }
394-
395422 UpdateTheme (hwnd);
396423
397424 SetChildContent (view_controller_->view ()->GetWindowHandle ());
@@ -426,24 +453,32 @@ FlutterHostWindow::FlutterHostWindow(FlutterHostWindowController* controller,
426453 window_handle_ = hwnd;
427454}
428455
456+ FlutterHostWindow::FlutterHostWindow (FlutterHostWindowController* controller,
457+ HWND hwnd,
458+ FlutterWindowsView* view)
459+ : window_controller_(controller), window_handle_(hwnd) {
460+ SetInstanceProperty (hwnd, this );
461+ FML_CHECK (view != nullptr );
462+ child_content_ = view->GetWindowHandle ();
463+ }
464+
429465FlutterHostWindow::~FlutterHostWindow () {
430- if (HWND const hwnd = window_handle_) {
431- window_handle_ = nullptr ;
432- DestroyWindow (hwnd);
466+ RemoveInstanceProperty (window_handle_);
467+ HWND const hwnd = std::exchange (window_handle_, nullptr );
433468
434- // Unregisters the window class. It will fail silently if there are
435- // other windows using the class, as only the last window can
436- // successfully unregister the class.
469+ if (view_controller_) {
470+ DestroyWindow (hwnd);
471+ // Unregister the window class. Fail silently if other windows are still
472+ // using the class, as only the last window can successfully unregister it.
437473 if (!UnregisterClass (kWindowClassName , GetModuleHandle (nullptr ))) {
438- // Clears the error information after the failed unregistering .
474+ // Clear the error state after the failed unregistration .
439475 SetLastError (ERROR_SUCCESS);
440476 }
441477 }
442478}
443479
444480FlutterHostWindow* FlutterHostWindow::GetThisFromHandle (HWND hwnd) {
445- return reinterpret_cast <FlutterHostWindow*>(
446- GetWindowLongPtr (hwnd, GWLP_USERDATA));
481+ return GetInstanceProperty (hwnd);
447482}
448483
449484HWND FlutterHostWindow::GetWindowHandle () const {
@@ -466,10 +501,9 @@ LRESULT FlutterHostWindow::WndProc(HWND hwnd,
466501 LPARAM lparam) {
467502 if (message == WM_NCCREATE) {
468503 auto * const create_struct = reinterpret_cast <CREATESTRUCT*>(lparam);
469- SetWindowLongPtr (hwnd, GWLP_USERDATA,
470- reinterpret_cast <LONG_PTR>(create_struct->lpCreateParams ));
471504 auto * const window =
472505 static_cast <FlutterHostWindow*>(create_struct->lpCreateParams );
506+ SetInstanceProperty (hwnd, window);
473507 window->window_handle_ = hwnd;
474508
475509 EnableFullDpiSupportIfAvailable (hwnd);
@@ -486,13 +520,15 @@ LRESULT FlutterHostWindow::HandleMessage(HWND hwnd,
486520 UINT message,
487521 WPARAM wparam,
488522 LPARAM lparam) {
489- switch (message) {
490- case WM_DESTROY:
491- if (window_handle_ && quit_on_close_) {
492- PostQuitMessage (0 );
493- }
523+ if (window_handle_ && view_controller_) {
524+ LRESULT* result;
525+ if (view_controller_->engine ()->lifecycle_manager ()->WindowProc (
526+ hwnd, message, wparam, lparam, result)) {
494527 return 0 ;
528+ }
529+ }
495530
531+ switch (message) {
496532 case WM_DPICHANGED: {
497533 auto * const new_scaled_window_rect = reinterpret_cast <RECT*>(lparam);
498534 LONG const width =
@@ -567,6 +603,10 @@ LRESULT FlutterHostWindow::HandleMessage(HWND hwnd,
567603 break ;
568604 }
569605
606+ if (!view_controller_) {
607+ return 0 ;
608+ }
609+
570610 return DefWindowProc (hwnd, message, wparam, lparam);
571611}
572612
0 commit comments