mirror of
https://github.com/yattee/yattee.git
synced 2026-07-21 06:42:01 +00:00
Fix macOS black video after re-parenting the shared player view
The player video surface is a single shared MPVOGLView that is re-parented between the mini-bar container (main window) and the expanded-player sheet (a separate sheet window). When presenting the sheet, the new container attaches the shared view before the old mini-bar container tears down, so the old container's viewWillMove(toSuperview: nil) was ripping the shared view out of its new home via removeFromSuperview() — leaving it with no window and a black surface. Symmetric, so it also blanked the mini-bar preview after collapsing. Only detach the shared view if it still belongs to the container (superview === self). Also force a repaint on window reattach so a paused frame redraws, and extend the onAppear resumeRendering to macOS.
This commit is contained in:
@@ -170,6 +170,12 @@ final class MPVOGLView: NSView {
|
|||||||
|
|
||||||
// Update contents scale for new window
|
// Update contents scale for new window
|
||||||
videoLayer?.contentsScale = window.backingScaleFactor
|
videoLayer?.contentsScale = window.backingScaleFactor
|
||||||
|
|
||||||
|
// Reattaching (e.g. macOS player sheet dismissed via ESC then re-expanded)
|
||||||
|
// detaches this shared view without stopping playback. macOS drawing is
|
||||||
|
// pull-based, so force a redraw to repaint the current frame — otherwise
|
||||||
|
// the layer stays black until MPV emits a new frame (never, if paused).
|
||||||
|
resumeRendering()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,10 +184,21 @@ private class MPVContainerNSView: NSView {
|
|||||||
|
|
||||||
override func viewWillMove(toSuperview newSuperview: NSView?) {
|
override func viewWillMove(toSuperview newSuperview: NSView?) {
|
||||||
super.viewWillMove(toSuperview: newSuperview)
|
super.viewWillMove(toSuperview: newSuperview)
|
||||||
// When being removed from superview, detach player view first
|
// When being removed from superview, detach the player view first for a clean
|
||||||
// This ensures proper cleanup order during window destruction
|
// teardown order during window destruction.
|
||||||
|
//
|
||||||
|
// The player view is a single SHARED instance (backend.playerView) that is
|
||||||
|
// re-parented between containers (mini bar ⇄ expanded sheet). When presenting
|
||||||
|
// the sheet, the new container attaches the shared view (AppKit auto-removes it
|
||||||
|
// from the old container) BEFORE this old container is torn down. So by the time
|
||||||
|
// we get here, `currentPlayerView` may already live in another container. Only
|
||||||
|
// remove it if it still actually belongs to us — otherwise we would rip the
|
||||||
|
// shared view out of its new home and blank the video (black screen on re-open,
|
||||||
|
// and a black mini-bar preview after collapse).
|
||||||
if newSuperview == nil {
|
if newSuperview == nil {
|
||||||
currentPlayerView?.removeFromSuperview()
|
if let playerView = currentPlayerView, playerView.superview === self {
|
||||||
|
playerView.removeFromSuperview()
|
||||||
|
}
|
||||||
currentPlayerView = nil
|
currentPlayerView = nil
|
||||||
onDidMoveToWindow = nil
|
onDidMoveToWindow = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,11 +143,12 @@ struct MPVVideoView: View {
|
|||||||
applies: appliesAspectRatio
|
applies: appliesAspectRatio
|
||||||
))
|
))
|
||||||
.onAppear {
|
.onAppear {
|
||||||
#if os(iOS)
|
#if os(iOS) || os(macOS)
|
||||||
// Resume the MPV display link when the expanded video view appears.
|
// Resume the MPV display link when the expanded video view appears.
|
||||||
// MiniPlayerView pauses rendering when its video preview hides during expand;
|
// MiniPlayerView pauses rendering when its video preview hides during expand;
|
||||||
// PlayerService.playerSheetDidAppear is gated behind background playback, so it
|
// PlayerService.playerSheetDidAppear is gated behind background playback, so it
|
||||||
// can't be relied on to resume.
|
// can't be relied on to resume. On macOS this also recovers the sheet re-open
|
||||||
|
// black screen when the shared render view reappears without a window re-parent.
|
||||||
backend.resumeRendering()
|
backend.resumeRendering()
|
||||||
#endif
|
#endif
|
||||||
// Start debug updates if overlay is already visible when view appears
|
// Start debug updates if overlay is already visible when view appears
|
||||||
|
|||||||
Reference in New Issue
Block a user