You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a follow-up to the previous fullscreen/window-composition fix.
On Windows 8+ with DWM composition, rapidly entering/exiting fullscreen could still expose transient compositor states during the top-level window style/geometry transition. Depending on playback state, this could appear as:
the desktop or windows behind MPC-BE becoming visible for a frame;
an old/stale framed player image;
the video renderer briefly appearing in the upper-left portion of the fullscreen surface;
an intermediate snapshot size before the final fullscreen video geometry was established;
similar transient artifacts with the empty player, audio-only playback, and audio cover-art/placeholder states.
The final implementation keeps the existing fullscreen logic intact and adds a short-lived, compositor-independent transition snapshot only on Windows 8 and later. The real MPC-BE window is temporarily cloaked while its final fullscreen/windowed style, geometry, child layout, and renderer rectangle are established. The snapshot remains in front until DWM has processed the final real-window state, then it is removed.
Root cause
The issue was not a normal repaint problem.
During a fullscreen transition, the main HWND changes non-client style, top-level rectangle, child layout, and video-renderer geometry in a very short interval. DWM can retain/present an older representation of the same HWND while those changes are being committed.
Simply hiding/showing the window, forcing synchronous repaint, or changing the order of SetWindowPos calls was not sufficient:
forcing RedrawWindow during the hidden geometry transaction could publish stale saved client/non-client bits;
cloaking without an independent visible surface could expose the desktop underneath;
a normal popup cover was not reliable enough as a compositor quarantine surface;
a full old-to-new screen capture could itself include background content;
changing snapshot geometry after it had already been submitted caused visible intermediate resize states.
The working solution is therefore a compositor handoff rather than a repaint workaround.
Implementation
The transition path now:
Determines the transition surface and captures only the currently relevant MPC-BE content.
Builds an opaque black layered snapshot covering the transition area.
For active video, places the frozen frame directly at the destination geometry that MPC-BE's final video layout will use, avoiding a second/intermediate snapshot resize.
For empty/audio/static states, preserves the existing rendered content without synthetically scaling the whole old view.
Commits the independent layered snapshot to DWM before the real window is cloaked.
Cloaks the real MPC-BE HWND while keeping it logically visible so the normal MFC/layout path can run.
Applies the normal fullscreen/windowed style, top-level geometry, layout, and MoveVideoWindow() work.
Reasserts the snapshot above the real player before reveal.
For static/audio states, performs the final repaint only after the target geometry is installed and while the layered snapshot still hides the real HWND from the user.
Uncloaks the real player and waits for the required compositor synchronization while the snapshot remains in front.
Removes the snapshot only after the final real-window presentation is ready.
No playback pause/restart is introduced.
Responsiveness
The correctness-critical compositor ordering is intentionally unchanged after the visual fix was validated.
To reduce the cost of repeated fullscreen toggles, the backing GDI surface is cached:
the compatible memory DC is reused;
the 32-bit DIB is reused when the transition dimensions are unchanged;
only the previously occupied content rectangle is cleared instead of zeroing the entire monitor-sized buffer on every toggle;
the layered transition HWND itself is still created/destroyed for each transition, preserving the DWM lifetime/order that proved reliable.
This primarily improves rapid/repeated F toggling without weakening the synchronization that prevents the artifacts.
Windows compatibility / regression containment
This change is deliberately runtime-gated to Windows 8 and later.
The new snapshot/cloak path is entered only behind:
No, I won't accept that. It's better to leave it as is or even roll it back to the way it was before.
There's no need for such complex code that also duplicates size calculations (and what if they change elsewhere in the future, etc.).
No, I won't accept that. It's better to leave it as is or even roll it back to the way it was before. There's no need for such complex code that also duplicates size calculations (and what if they change elsewhere in the future, etc.).
Understood. I can test a much smaller alternative, you'll judge if it too complex to maintain, the idea is to solve the last issue not addressed at first. Do you want me to keep trying or do you consider it done here, no further attempt needed?
Yes - keep trying.
The best thing is to find a solution without using DWM_CLOAK.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is a follow-up to the previous fullscreen/window-composition fix.
On Windows 8+ with DWM composition, rapidly entering/exiting fullscreen could still expose transient compositor states during the top-level window style/geometry transition. Depending on playback state, this could appear as:
The final implementation keeps the existing fullscreen logic intact and adds a short-lived, compositor-independent transition snapshot only on Windows 8 and later. The real MPC-BE window is temporarily cloaked while its final fullscreen/windowed style, geometry, child layout, and renderer rectangle are established. The snapshot remains in front until DWM has processed the final real-window state, then it is removed.
Root cause
The issue was not a normal repaint problem.
During a fullscreen transition, the main HWND changes non-client style, top-level rectangle, child layout, and video-renderer geometry in a very short interval. DWM can retain/present an older representation of the same HWND while those changes are being committed.
Simply hiding/showing the window, forcing synchronous repaint, or changing the order of SetWindowPos calls was not sufficient:
The working solution is therefore a compositor handoff rather than a repaint workaround.
Implementation
The transition path now:
No playback pause/restart is introduced.
Responsiveness
The correctness-critical compositor ordering is intentionally unchanged after the visual fix was validated.
To reduce the cost of repeated fullscreen toggles, the backing GDI surface is cached:
This primarily improves rapid/repeated F toggling without weakening the synchronization that prevents the artifacts.
Windows compatibility / regression containment
This change is deliberately runtime-gated to Windows 8 and later.
The new snapshot/cloak path is entered only behind:
SysVersion::IsWin8orLater()