@@ -15,6 +15,20 @@ namespace {
15
15
16
16
constexpr wchar_t kWindowClassName [] = L" FLUTTER_HOST_WINDOW" ;
17
17
18
+ // RAII wrapper for global Win32 ATOMs.
19
+ struct AtomRAII {
20
+ AtomRAII (wchar_t const * name) : atom(GlobalAddAtom(name)) {}
21
+ ~AtomRAII () { GlobalDeleteAtom (atom); }
22
+ ATOM const atom;
23
+ };
24
+
25
+ // Atom representing a window property that stores a pointer to this host
26
+ // window. This property serves as an alternative way to access the window in
27
+ // |FlutterHostWindow::GetThisFromHandle| for windows created from existing
28
+ // views, since the `GWLP_USERDATA` of such windows may point to something other
29
+ // than a |FlutterHostWindow|.
30
+ AtomRAII const kWindowPropAtom (kWindowClassName );
31
+
18
32
// Clamps |size| to the size of the virtual screen. Both the parameter and
19
33
// return size are in physical coordinates.
20
34
flutter::Size ClampToVirtualScreen (flutter::Size size) {
@@ -303,6 +317,40 @@ FlutterHostWindow::FlutterHostWindow(FlutterHostWindowController* controller,
303
317
window_size ? *window_size : Size {CW_USEDEFAULT, CW_USEDEFAULT}};
304
318
}();
305
319
320
+ // Set up the view.
321
+ FlutterWindowsEngine* const engine = window_controller_->engine ();
322
+ auto view_window = std::make_unique<FlutterWindow>(
323
+ initial_window_rect.width (), initial_window_rect.height (),
324
+ engine->windows_proc_table ());
325
+
326
+ std::unique_ptr<FlutterWindowsView> view =
327
+ engine->CreateView (std::move (view_window));
328
+ if (!view) {
329
+ FML_LOG (ERROR) << " Failed to create view" ;
330
+ return ;
331
+ }
332
+
333
+ view_controller_ =
334
+ std::make_unique<FlutterWindowsViewController>(nullptr , std::move (view));
335
+
336
+ // Launch the engine if it is not running already.
337
+ if (!engine->running () && !engine->Run ()) {
338
+ FML_LOG (ERROR) << " Failed to launch engine" ;
339
+ return ;
340
+ }
341
+ // Must happen after engine is running.
342
+ view_controller_->view ()->SendInitialBounds ();
343
+ // The Windows embedder listens to accessibility updates using the
344
+ // view's HWND. The embedder's accessibility features may be stale if
345
+ // the app was in headless mode.
346
+ view_controller_->engine ()->UpdateAccessibilityFeatures ();
347
+
348
+ // Ensure that basic setup of the view controller was successful.
349
+ if (!view_controller_->view ()) {
350
+ FML_LOG (ERROR) << " Failed to set up the view controller" ;
351
+ return ;
352
+ }
353
+
306
354
// Register the window class.
307
355
if (!IsClassRegistered (kWindowClassName )) {
308
356
auto const idi_app_icon = 101 ;
@@ -354,44 +402,6 @@ FlutterHostWindow::FlutterHostWindow(FlutterHostWindowController* controller,
354
402
window_rect.top - top_dropshadow_height, 0 , 0 ,
355
403
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
356
404
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
-
395
405
UpdateTheme (hwnd);
396
406
397
407
SetChildContent (view_controller_->view ()->GetWindowHandle ());
@@ -426,26 +436,46 @@ FlutterHostWindow::FlutterHostWindow(FlutterHostWindowController* controller,
426
436
window_handle_ = hwnd;
427
437
}
428
438
439
+ FlutterHostWindow::FlutterHostWindow (FlutterHostWindowController* controller,
440
+ HWND hwnd,
441
+ FlutterWindowsView* view)
442
+ : window_controller_(controller), window_handle_(hwnd) {
443
+ if (!SetProp (hwnd, MAKEINTATOM (kWindowPropAtom .atom ), this )) {
444
+ FML_LOG (ERROR) << " Failed to set up entry in the window property list" ;
445
+ return ;
446
+ }
447
+ child_content_ = view->GetWindowHandle ();
448
+ }
449
+
429
450
FlutterHostWindow::~FlutterHostWindow () {
430
- if (HWND const hwnd = window_handle_) {
431
- window_handle_ = nullptr ;
451
+ HWND const hwnd = window_handle_;
452
+ window_handle_ = nullptr ;
453
+ if (view_controller_) {
432
454
DestroyWindow (hwnd);
433
-
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.
455
+ // Unregister the window class. Fail silently if other windows are still
456
+ // using the class, as only the last window can successfully unregister it.
437
457
if (!UnregisterClass (kWindowClassName , GetModuleHandle (nullptr ))) {
438
- // Clears the error information after the failed unregistering .
458
+ // Clear the error state after the failed unregistration .
439
459
SetLastError (ERROR_SUCCESS);
440
460
}
441
461
}
442
462
}
443
463
444
464
FlutterHostWindow* FlutterHostWindow::GetThisFromHandle (HWND hwnd) {
465
+ // For native windows created by the runner, retrieve the instance pointer
466
+ // from a window property.
467
+ if (HANDLE const data = GetProp (hwnd, MAKEINTATOM (kWindowPropAtom .atom ))) {
468
+ return reinterpret_cast <FlutterHostWindow*>(data);
469
+ }
470
+ // Otherwise, retrieve the instance pointer from the window's user data.
445
471
return reinterpret_cast <FlutterHostWindow*>(
446
472
GetWindowLongPtr (hwnd, GWLP_USERDATA));
447
473
}
448
474
475
+ bool FlutterHostWindow::HasThisAsProperty (HWND hwnd) {
476
+ return GetProp (hwnd, MAKEINTATOM (kWindowPropAtom .atom )) != nullptr ;
477
+ }
478
+
449
479
HWND FlutterHostWindow::GetWindowHandle () const {
450
480
return window_handle_;
451
481
}
@@ -487,12 +517,6 @@ LRESULT FlutterHostWindow::HandleMessage(HWND hwnd,
487
517
WPARAM wparam,
488
518
LPARAM lparam) {
489
519
switch (message) {
490
- case WM_DESTROY:
491
- if (window_handle_ && quit_on_close_) {
492
- PostQuitMessage (0 );
493
- }
494
- return 0 ;
495
-
496
520
case WM_DPICHANGED: {
497
521
auto * const new_scaled_window_rect = reinterpret_cast <RECT*>(lparam);
498
522
LONG const width =
@@ -567,6 +591,18 @@ LRESULT FlutterHostWindow::HandleMessage(HWND hwnd,
567
591
break ;
568
592
}
569
593
594
+ if (!view_controller_) {
595
+ return 0 ;
596
+ }
597
+
598
+ if (window_handle_) {
599
+ LRESULT* result;
600
+ if (view_controller_->engine ()->lifecycle_manager ()->WindowProc (
601
+ hwnd, message, wparam, lparam, result)) {
602
+ return 0 ;
603
+ }
604
+ }
605
+
570
606
return DefWindowProc (hwnd, message, wparam, lparam);
571
607
}
572
608
0 commit comments