From 0fa4df161ba467e73a98318368d2c51a184f9342 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Mon, 8 Jun 2026 22:33:01 +0200 Subject: [PATCH] Fix fullscreen not working when player window is pinned on macOS A pinned window carries .fullScreenAuxiliary, which AppKit refuses to make a primary fullscreen window, so toggleFullScreen was a silent no-op. Drop the floating config before entering fullscreen and restore it in windowDidExitFullScreen, keeping the pin setting intact. --- .../Player/ExpandedPlayerSheet+Layouts.swift | 5 ++-- .../Player/ExpandedPlayerWindowManager.swift | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Yattee/Views/Player/ExpandedPlayerSheet+Layouts.swift b/Yattee/Views/Player/ExpandedPlayerSheet+Layouts.swift index 860137da..1ea7144b 100644 --- a/Yattee/Views/Player/ExpandedPlayerSheet+Layouts.swift +++ b/Yattee/Views/Player/ExpandedPlayerSheet+Layouts.swift @@ -1571,8 +1571,9 @@ extension ExpandedPlayerSheet { playerService.seekBackward(by: seconds) }, onToggleFullscreen: { - // Toggle native macOS fullscreen - NSApp.keyWindow?.toggleFullScreen(nil) + // Toggle native macOS fullscreen (drops the floating + // config first so a pinned window can enter fullscreen) + ExpandedPlayerWindowManager.shared.toggleFullScreen() }, isFullscreen: NSApp.keyWindow?.styleMask.contains(.fullScreen) == true, onClose: { [self] in diff --git a/Yattee/Views/Player/ExpandedPlayerWindowManager.swift b/Yattee/Views/Player/ExpandedPlayerWindowManager.swift index 4e9208af..a560743d 100644 --- a/Yattee/Views/Player/ExpandedPlayerWindowManager.swift +++ b/Yattee/Views/Player/ExpandedPlayerWindowManager.swift @@ -246,9 +246,28 @@ final class ExpandedPlayerWindowManager: NSObject { /// Call this when the user changes the player mode setting. func updateWindowLevel(floating: Bool) { guard let window = playerWindow else { return } + // Don't touch level/collectionBehavior mid-fullscreen; the setting is + // re-read in windowDidExitFullScreen. + guard !window.styleMask.contains(.fullScreen) else { return } configureWindowLevel(window, floating: floating) } + /// Toggles native fullscreen on the player window. + func toggleFullScreen() { + guard let window = playerWindow else { + // Inline-sheet presentation: fullscreen the main app window + NSApp.keyWindow?.toggleFullScreen(nil) + return + } + // A floating (pinned) window carries .fullScreenAuxiliary, which AppKit + // refuses to make a primary fullscreen window. Switch to the primary + // config for the transition; windowDidExitFullScreen restores floating. + if !window.styleMask.contains(.fullScreen) { + configureWindowLevel(window, floating: false) + } + window.toggleFullScreen(nil) + } + /// Restores a window that was hidden for PiP mode. /// Call this when returning from PiP to show the player window again. func restoreFromPiP(animated: Bool = true) { @@ -497,6 +516,16 @@ extension ExpandedPlayerWindowManager: NSWindowDelegate { // Return false - we've already hidden the window with orderOut return false } + + nonisolated func windowDidExitFullScreen(_ notification: Notification) { + MainActor.assumeIsolated { + guard let window = playerWindow else { return } + // Restore the pinned (floating) config that toggleFullScreen + // dropped so the window could enter primary fullscreen. + let floating = appEnvironment?.settingsManager.macPlayerFloating ?? false + configureWindowLevel(window, floating: floating) + } + } } // MARK: - Two-Phase Window Root