66using System . IO ;
77using System . Runtime . CompilerServices ;
88using System . Runtime . InteropServices ;
9+ using System . Threading ;
910using Microsoft . UI . Input ;
1011using Microsoft . UI . Windowing ;
1112using Microsoft . UI . Xaml ;
2930using Windows . Win32 . Graphics . Gdi ;
3031using Windows . Win32 . UI . HiDpi ;
3132using Windows . Win32 . UI . WindowsAndMessaging ;
33+ using Uno . UI . Dispatching ;
3234using Point = System . Drawing . Point ;
3335
3436namespace Uno . UI . Runtime . Skia . Win32 ;
@@ -208,6 +210,15 @@ private unsafe LRESULT WndProcInner(HWND hwnd, uint msg, WPARAM wParam, LPARAM l
208210
209211 switch ( msg )
210212 {
213+ case PInvoke . WM_NCPAINT :
214+ // see the comment in the WM_ERASEBKGND handler
215+ if ( WasShown && _beforeFirstEraseBkgnd && ( _pendingState is OverlappedPresenterState . Maximized || Window ? . AppWindow . Presenter is FullScreenPresenter ) )
216+ {
217+ OnWindowSizeOrLocationChanged ( ) ; // In case the window size has changed but WM_SIZE is not fired yet. This happens specifically if the window is starting maximized using _pendingState
218+ XamlRoot ! . VisualTree . RootElement . UpdateLayout ( ) ; // relayout in response to the new window size
219+ ( XamlRoot ? . Content ? . Visual . CompositionTarget as CompositionTarget ) ? . OnRenderFrameOpportunity ( ) ; // force an early render
220+ }
221+ break ;
211222 case PInvoke . WM_ACTIVATE :
212223 OnWmActivate ( wParam ) ;
213224 return new LRESULT ( 0 ) ;
@@ -253,11 +264,15 @@ private unsafe LRESULT WndProcInner(HWND hwnd, uint msg, WPARAM wParam, LPARAM l
253264 if ( _beforeFirstEraseBkgnd )
254265 {
255266 // Without drawing on the first WM_ERASEBKGND, we get an initial white frame
256- // Note that we don't call OnRenderFrameOpportunity here, but before showing
257- // the window in ShowCore. The problem is that any minor delay will cause
258- // a split-second white flash, so we're keeping the "time to blit" to a
259- // minimum by "rendering" before the window is shown and only drawing when
260- // receiving the first WM_ERASEBKGND
267+ // Note that we don't call OnRenderFrameOpportunity here, but in ShowCore right before
268+ // showing the window or in WM_NCPAINT which is the first message received after showing
269+ // the window in ShowCore and after a possible window size change because the window was
270+ // shown in a maximized/fullscreen state.
271+ // The problem is that any minor delay will cause a split-second white flash, so we're keeping
272+ // the "time to blit" to a minimum by "rendering" asap and only "drawing" when
273+ // receiving the first WM_ERASEBKGND. Even then, there is still a race between our drawing a frame
274+ // and the next screen refresh and while in most cases we are able to win the race and not get this
275+ // split second of "whiteness", it's not a guarantee, especially on a slower device.
261276 _beforeFirstEraseBkgnd = false ;
262277 // The render timer might already be running. This is fine. The CompositionTarget
263278 // contract allows calling OnNativePlatformFrameRequested multiple times.
@@ -466,20 +481,14 @@ protected internal override void Activate()
466481
467482 protected override void ShowCore ( )
468483 {
469- // see the comment in WndProc's WM_ERASEBKGND handling
470- if ( _beforeFirstEraseBkgnd )
471- {
472- ( XamlRoot ? . Content ? . Visual . CompositionTarget as CompositionTarget ) ? . OnRenderFrameOpportunity ( ) ;
473- }
474-
475484 if ( Window ? . AppWindow . Presenter is FullScreenPresenter )
476485 {
477486 // The window takes a split second to be rerendered with the fullscreen window size but
478487 // no fix has been found for this yet.
479488 SetWindowStyle ( WINDOW_STYLE . WS_DLGFRAME , false ) ;
480489 _ = PInvoke . ShowWindow ( _hwnd , SHOW_WINDOW_CMD . SW_MAXIMIZE ) ;
481490 }
482- else if ( Window ? . AppWindow . Presenter is OverlappedPresenter overlappedPresenter )
491+ else if ( Window ? . AppWindow . Presenter is OverlappedPresenter )
483492 {
484493 switch ( _pendingState )
485494 {
@@ -489,17 +498,18 @@ protected override void ShowCore()
489498 case OverlappedPresenterState . Minimized :
490499 _ = PInvoke . ShowWindow ( _hwnd , SHOW_WINDOW_CMD . SW_MINIMIZE ) ;
491500 break ;
492- case OverlappedPresenterState . Restored :
493- _ = PInvoke . ShowWindow ( _hwnd , SHOW_WINDOW_CMD . SW_RESTORE ) ;
494- break ;
495501 default :
496- _ = PInvoke . ShowWindow ( _hwnd , SHOW_WINDOW_CMD . SW_SHOWDEFAULT ) ;
502+ // see the comment in the WM_ERASEBKGND handler
503+ OnWindowSizeOrLocationChanged ( ) ; // In case the window size has changed but WM_SIZE is not fired yet. This happens specifically if the window is starting maximized using _pendingState
504+ XamlRoot ! . VisualTree . RootElement . UpdateLayout ( ) ; // relayout in response to the new window size
505+ ( XamlRoot ? . Content ? . Visual . CompositionTarget as CompositionTarget ) ? . OnRenderFrameOpportunity ( ) ; // force an early render
506+ PInvoke . ShowWindow ( _hwnd , SHOW_WINDOW_CMD . SW_SHOWDEFAULT ) ;
497507 break ;
498508 }
499509 }
500510 else
501511 {
502- PInvoke . ShowWindow ( _hwnd , SHOW_WINDOW_CMD . SW_SHOWDEFAULT ) ;
512+ throw new InvalidOperationException ( "Unsupported Window Presenter." ) ;
503513 }
504514 }
505515
0 commit comments