@@ -41,8 +41,6 @@ const bool printPlaySpeed = false;
4141
4242#define WM_VIEWER_PLAY_TIMER (WM_APP + 1 )
4343
44- static const UINT_PTR VIEWER_FULLSCREEN_DWM_TIMER = 0x5100 ;
45- static const UINT VIEWER_FULLSCREEN_DWM_DELAY_MS = 250 ;
4644
4745enum QMouseMenuID
4846{
@@ -61,6 +59,80 @@ static const QMouseMenuInfo QMouseMenu[] = {
6159 { " Sync Input" , QMouseMenuSyncInput },
6260};
6361
62+ class CTransitionSnapshotCover {
63+ public:
64+ CTransitionSnapshotCover () : mHwnd (NULL ), mBitmap (NULL ) {}
65+
66+ ~CTransitionSnapshotCover ()
67+ {
68+ Destroy ();
69+ }
70+
71+ bool Create (const RECT &rc)
72+ {
73+ Destroy ();
74+
75+ const int w = rc.right - rc.left ;
76+ const int h = rc.bottom - rc.top ;
77+ if (w <= 0 || h <= 0 )
78+ return false ;
79+
80+ HDC screenDC = ::GetDC (NULL );
81+ if (screenDC == NULL )
82+ return false ;
83+
84+ HDC memDC = ::CreateCompatibleDC (screenDC);
85+ if (memDC == NULL ) {
86+ ::ReleaseDC (NULL , screenDC);
87+ return false ;
88+ }
89+
90+ mBitmap = ::CreateCompatibleBitmap (screenDC, w, h);
91+ if (mBitmap != NULL ) {
92+ HGDIOBJ oldBitmap = ::SelectObject (memDC, mBitmap );
93+ ::BitBlt (memDC, 0 , 0 , w, h, screenDC, rc.left, rc.top, SRCCOPY );
94+ ::SelectObject (memDC, oldBitmap);
95+ }
96+
97+ ::DeleteDC (memDC);
98+ ::ReleaseDC (NULL , screenDC);
99+
100+ if (mBitmap == NULL )
101+ return false ;
102+
103+ mHwnd = ::CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE ,
104+ _T (" STATIC" ), NULL , WS_POPUP | SS_BITMAP ,
105+ rc.left , rc.top , w, h, NULL , NULL , AfxGetInstanceHandle (), NULL );
106+ if (mHwnd == NULL ) {
107+ ::DeleteObject (mBitmap );
108+ mBitmap = NULL ;
109+ return false ;
110+ }
111+
112+ ::SendMessage (mHwnd , STM_SETIMAGE , IMAGE_BITMAP , (LPARAM )mBitmap);
113+ ::ShowWindow (mHwnd , SW_SHOWNOACTIVATE );
114+ ::UpdateWindow (mHwnd );
115+ ::DwmFlush ();
116+ return true ;
117+ }
118+
119+ void Destroy ()
120+ {
121+ if (mHwnd != NULL ) {
122+ ::DestroyWindow (mHwnd );
123+ mHwnd = NULL ;
124+ }
125+ if (mBitmap != NULL ) {
126+ ::DeleteObject (mBitmap );
127+ mBitmap = NULL ;
128+ }
129+ }
130+
131+ private:
132+ HWND mHwnd ;
133+ HBITMAP mBitmap ;
134+ };
135+
64136using namespace std ;
65137
66138// CViewerView
@@ -1713,38 +1785,47 @@ void CViewerView::ToggleFullScreen()
17131785 CMainFrame *pMainFrm = static_cast <CMainFrame *>(AfxGetMainWnd ());
17141786 if (pMainFrm == NULL )
17151787 return ;
1788+ HWND hFrame = pMainFrm->GetSafeHwnd ();
17161789
17171790 const bool entering = !mFullMode ;
1791+ MONITORINFO monitorInfo = {};
1792+ monitorInfo.cbSize = sizeof (monitorInfo);
1793+ HMONITOR hMonitor = ::MonitorFromWindow (hFrame, MONITOR_DEFAULTTONEAREST );
1794+ const bool haveMonitorInfo = ::GetMonitorInfo (hMonitor, &monitorInfo) != FALSE ;
1795+
1796+ CTransitionSnapshotCover transitionCover;
1797+ if (haveMonitorInfo)
1798+ transitionCover.Create (monitorInfo.rcMonitor );
1799+
1800+ // Batch the structural full-screen change without LockWindowUpdate. That API
1801+ // can make themed non-client areas flash as classic controls during the frame
1802+ // swap. The snapshot cover keeps DWM's one-frame stale surface out of view
1803+ // without flashing through to the desktop or a black placeholder.
17181804 pMainFrm->SetRedraw (FALSE );
17191805 SetRedraw (FALSE );
1720- ::LockWindowUpdate (pMainFrm->GetSafeHwnd ());
1721- KillTimer (VIEWER_FULLSCREEN_DWM_TIMER );
1722- BOOL disableDwmTransitions = TRUE ;
1723- ::DwmSetWindowAttribute (pMainFrm->GetSafeHwnd (),
1724- DWMWA_TRANSITIONS_FORCEDISABLED,
1725- &disableDwmTransitions,
1726- sizeof(disableDwmTransitions));
17271806
17281807 if (entering) {
17291808 mPreFullPlacement .length = sizeof (mPreFullPlacement );
17301809 mHavePreFullPlacement = pMainFrm->GetWindowPlacement (&mPreFullPlacement ) != FALSE ;
1731- if (mPreFullPlacement .showCmd == SW_SHOWMINIMIZED )
1810+ if (mPreFullPlacement .showCmd == SW_SHOWMINIMIZED || !pMainFrm-> IsZoomed () )
17321811 mPreFullPlacement .showCmd = SW_SHOWNORMAL ;
17331812
17341813 mFullMode = true ;
17351814
17361815 MONITORINFO mi = {};
17371816 mi.cbSize = sizeof (mi);
17381817 HMONITOR hmon = ::MonitorFromWindow (pMainFrm->GetSafeHwnd (), MONITOR_DEFAULTTONEAREST );
1739- if (::GetMonitorInfo (hmon, &mi)) {
1818+ if (haveMonitorInfo || ::GetMonitorInfo (hmon, &mi)) {
1819+ if (haveMonitorInfo)
1820+ mi = monitorInfo;
17401821 CRect rc (mi.rcMonitor );
17411822 pMainFrm->SetMenu (NULL );
17421823 pMainFrm->ModifyStyle (
17431824 WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX ,
17441825 WS_POPUP , 0 );
17451826 pMainFrm->SetWindowPos (&CWnd::wndTop, rc.left , rc.top ,
17461827 rc.Width (), rc.Height (),
1747- SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOREDRAW );
1828+ SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOREDRAW | SWP_NOCOPYBITS );
17481829 }
17491830 } else {
17501831 mFullMode = false ;
@@ -1756,24 +1837,32 @@ void CViewerView::ToggleFullScreen()
17561837 0 );
17571838 pMainFrm->AddMainMenu ();
17581839 GetDocument ()->UpdateMenu();
1759- if (mHavePreFullPlacement )
1840+ if (mHavePreFullPlacement && mPreFullPlacement .showCmd != SW_SHOWMAXIMIZED ) {
1841+ const CRect rc (mPreFullPlacement .rcNormalPosition );
1842+ pMainFrm->SetWindowPos (NULL , rc.left , rc.top ,
1843+ rc.Width (), rc.Height (),
1844+ SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED |
1845+ SWP_NOREDRAW | SWP_NOCOPYBITS );
1846+ } else if (mHavePreFullPlacement ) {
17601847 pMainFrm->SetWindowPlacement (&mPreFullPlacement );
1761- else
1848+ } else {
17621849 pMainFrm->ShowWindow (SW_RESTORE );
1850+ }
17631851 pMainFrm->SetWindowPos (NULL , 0 , 0 , 0 , 0 ,
17641852 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1765- SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOREDRAW );
1853+ SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOREDRAW | SWP_NOCOPYBITS );
17661854 }
17671855
17681856 pMainFrm->RecalcLayout (TRUE );
17691857 FitToWindow ();
17701858 pMainFrm->SetRedraw (TRUE );
17711859 SetRedraw (TRUE );
1772- ::LockWindowUpdate (NULL );
17731860 pMainFrm->SetForegroundWindow ();
17741861 pMainFrm->RedrawWindow (NULL , NULL ,
17751862 RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME | RDW_ERASE );
1776- SetTimer (VIEWER_FULLSCREEN_DWM_TIMER , VIEWER_FULLSCREEN_DWM_DELAY_MS , NULL );
1863+ ::DwmFlush ();
1864+ transitionCover.Destroy ();
1865+ ::DwmFlush ();
17771866}
17781867
17791868void CViewerView::ToggleHelp ()
@@ -2101,16 +2190,6 @@ void CViewerView::OnDestroy()
21012190{
21022191 CView::OnDestroy ();
21032192
2104- KillTimer (VIEWER_FULLSCREEN_DWM_TIMER );
2105- CMainFrame *pMainFrm = static_cast <CMainFrame *>(AfxGetMainWnd ());
2106- if (pMainFrm != NULL ) {
2107- BOOL disableDwmTransitions = FALSE ;
2108- ::DwmSetWindowAttribute (pMainFrm->GetSafeHwnd (),
2109- DWMWA_TRANSITIONS_FORCEDISABLED,
2110- &disableDwmTransitions,
2111- sizeof(disableDwmTransitions));
2112- }
2113-
21142193 mBufferPool ->disable ();
21152194 mBufferQueue ->destroy ();
21162195 KillPlayTimer ();
@@ -2154,19 +2233,6 @@ void CViewerView::OnSize(UINT nType, int cx, int cy)
21542233
21552234void CViewerView::OnTimer (UINT_PTR nIDEvent)
21562235{
2157- if (nIDEvent == VIEWER_FULLSCREEN_DWM_TIMER ) {
2158- KillTimer (VIEWER_FULLSCREEN_DWM_TIMER );
2159- CMainFrame *pMainFrm = static_cast <CMainFrame *>(AfxGetMainWnd ());
2160- if (pMainFrm != NULL ) {
2161- BOOL disableDwmTransitions = FALSE ;
2162- ::DwmSetWindowAttribute (pMainFrm->GetSafeHwnd (),
2163- DWMWA_TRANSITIONS_FORCEDISABLED,
2164- &disableDwmTransitions,
2165- sizeof(disableDwmTransitions));
2166- }
2167- return ;
2168- }
2169-
21702236 CView::OnTimer (nIDEvent);
21712237}
21722238
0 commit comments