[vlc-commits] [Git][videolan/vlc][master] 9 commits: macosx: Delete callback for WindowFloatOnTop when removing vout for display

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Jun 18 05:15:49 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
71fe2203 by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Delete callback for WindowFloatOnTop when removing vout for display

Prevents a crash when vout is stopped and then started later

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
e1dfad10 by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Handle video playback appearance for library window via video output provider

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
0425c22f by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Port handling of end-of-playback view to all video windows

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
c1af1d50 by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Fix returnToLibrary behaviour when the main video view is assigned onto a non-library window video window

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
74a2a16b by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Extract video window's dismissal procedure to block variable, reuse for playback end view dismissal handling

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
5ae75479 by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Ensure animation context and full screen closing isn't started until end of playback view is dismissed

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
f9f441a3 by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Do not set fullscreen on window parent when setting up fullscreen

In native fullscreen mode, windowWillEnterFullscreen already does this

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
a009d7fe by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Apply fullscreen bool to vout thread within window class when using non-native fullscreen

Match behaviour to native fullscreen

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
a091acfd by Claudio Cambra at 2025-06-18T05:01:08+00:00
macosx: Use dispatch async to toggle fullscreen state for windows in video output provider

Avoids deadlocks when handling WindowEnable callback and setting of fullscreen variable on the windows' vout thread

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -


5 changed files:

- modules/gui/macosx/library/VLCLibraryWindow.m
- modules/gui/macosx/windows/video/VLCMainVideoViewController.h
- modules/gui/macosx/windows/video/VLCMainVideoViewController.m
- modules/gui/macosx/windows/video/VLCVideoOutputProvider.m
- modules/gui/macosx/windows/video/VLCVideoWindowCommon.m


Changes:

=====================================
modules/gui/macosx/library/VLCLibraryWindow.m
=====================================
@@ -412,34 +412,6 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
 
 #pragma mark - video output controlling
 
-- (void)setHasActiveVideo:(BOOL)hasActiveVideo
-{
-    [super setHasActiveVideo:hasActiveVideo];
-    if (hasActiveVideo) {
-        [self enableVideoPlaybackAppearance];
-    } else if (!self.videoViewController.view.hidden) {
-        // If we are switching to audio media then keep the active main video view open
-        NSURL * const currentMediaUrl = _playQueueController.playerController.URLOfCurrentMediaItem;
-        VLCMediaLibraryMediaItem * const mediaItem = [VLCMediaLibraryMediaItem mediaItemForURL:currentMediaUrl];
-        const BOOL decorativeViewVisible = mediaItem != nil && mediaItem.mediaType == VLC_ML_MEDIA_TYPE_AUDIO;
-
-        // If the playback end view is enabled and the player is stopped, display playback end view.
-        // We want to still display the decorative view for audio items.
-        // In other cases, we need to check that the player itself is in a stopped state. Removal of
-        // the active video can be triggered by more than just end of playback (e.g. disabling the
-        // video track).
-        if (!decorativeViewVisible &&
-            [NSUserDefaults.standardUserDefaults boolForKey:VLCPlaybackEndViewEnabledKey] &&
-            self.playerController.playerState == VLC_PLAYER_STATE_STOPPED) {
-            [self.videoViewController displayPlaybackEndView];
-        } else if (!decorativeViewVisible) {
-            [self disableVideoPlaybackAppearance];
-        }
-    } else {
-        [self disableVideoPlaybackAppearance];
-    }
-}
-
 - (void)playerStateChanged:(NSNotification *)notification
 {
     if (_playQueueController.playerController.playerState == VLC_PLAYER_STATE_STOPPED) {


=====================================
modules/gui/macosx/windows/video/VLCMainVideoViewController.h
=====================================
@@ -66,6 +66,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly) BOOL pipIsActive;
 
 @property (readonly) VLCPlaybackEndViewController *playbackEndViewController;
+ at property (readwrite) void (^endViewDismissHandler)(void);
 
 - (void)showControls;
 - (void)hideControls;


=====================================
modules/gui/macosx/windows/video/VLCMainVideoViewController.m
=====================================
@@ -557,9 +557,10 @@
         [self.playbackEndViewController.countdownTimer invalidate];
         [self.playbackEndViewController.view removeFromSuperview];
     }
-    VLCLibraryWindow *libraryWindow = (VLCLibraryWindow*)self.view.window;
-    if (libraryWindow != nil) {
-        [libraryWindow disableVideoPlaybackAppearance];
+    if (self.view.window.class == VLCLibraryWindow.class) {
+        [(VLCLibraryWindow *)self.view.window disableVideoPlaybackAppearance];
+    } else {
+        [self.view.window close];
     }
 }
 
@@ -607,12 +608,17 @@
 
 - (void)playbackEndViewReturnToLibrary:(NSNotification *)notification
 {
-    [self returnToLibrary:self];
+    if (self.endViewDismissHandler)
+        self.endViewDismissHandler();
+    else
+        [self returnToLibrary:self];
 }
 
 - (void)playbackEndViewHide:(NSNotification *)notification
 {
     [self.playbackEndViewController.view removeFromSuperview];
+    if (self.endViewDismissHandler)
+        self.endViewDismissHandler();
 }
 
 #pragma mark - PIPViewControllerDelegate


=====================================
modules/gui/macosx/windows/video/VLCVideoOutputProvider.m
=====================================
@@ -25,6 +25,7 @@
 
 #import "extensions/NSScreen+VLCAdditions.h"
 
+#import "library/VLCLibraryDataTypes.h"
 #import "library/VLCLibraryWindow.h"
 
 #import "main/CompatibilityFixes.h"
@@ -40,6 +41,8 @@
 #import "playqueue/VLCPlayQueueController.h"
 #import "playqueue/VLCPlayerController.h"
 
+#import "views/VLCPlaybackEndViewController.h"
+
 #import "windows/video/VLCAspectRatioRetainingVideoWindow.h"
 #import "windows/video/VLCMainVideoViewController.h"
 #import "windows/video/VLCVoutView.h"
@@ -423,6 +426,8 @@ static int WindowFloatOnTop(vlc_object_t *obj,
     voutView.voutThread = p_vout;
     voutView.voutWindow = p_wnd;
     videoWindow.hasActiveVideo = YES;
+    if (videoWindow.class == VLCLibraryWindow.class)
+        [(VLCLibraryWindow *)videoWindow enableVideoPlaybackAppearance];
     _playerController.activeVideoPlayback = YES;
     VLCMain.sharedInstance.libraryWindow.nonembedded = !b_mainWindowHasVideo;
 }
@@ -443,7 +448,6 @@ static int WindowFloatOnTop(vlc_object_t *obj,
     if (!videoWallpaper && !b_have_splitter && (var_InheritBool(getIntf(), "fullscreen") || _playerController.fullscreen)) {
         // this is not set when we start in fullscreen because of
         // fullscreen settings in video prefs the second time
-        var_SetBool(vlc_object_parent(p_wnd), "fullscreen", 1);
         [self setFullscreen:1 forWindow:p_wnd withAnimation:NO];
     }
 }
@@ -474,41 +478,92 @@ static int WindowFloatOnTop(vlc_object_t *obj,
 
 - (void)removeVoutForDisplay:(NSValue *)key
 {
-    VLCMain *mainInstance = VLCMain.sharedInstance;
-    VLCVideoWindowCommon *videoWindow = [_voutWindows objectForKey:key];
+    VLCVideoWindowCommon * const videoWindow = [_voutWindows objectForKey:key];
     if (!videoWindow) {
         msg_Err(getIntf(), "Cannot close nonexisting window");
         return;
     }
 
+    vlc_window_t * const p_wnd = (vlc_window_t *)key.pointerValue;
+    if (p_wnd) {
+        vout_thread_t * const p_vout = (vout_thread_t *)vlc_object_parent(p_wnd);
+        if (p_vout) {
+            var_DelCallback(p_vout, "video-on-top", WindowFloatOnTop, (__bridge void *)videoWindow);
+        } else {
+            msg_Warn(getIntf(),
+                     "Could not get p_vout to unregister WindowFloatOnTop callback for window %p",
+                     p_wnd);
+        }
+    } else {
+        msg_Warn(getIntf(), "Could not get p_wnd from key to unregister WindowFloatOnTop callback");
+    }
+
     [videoWindow.videoViewController.voutView releaseVoutThread];
 
     // set active video to no BEFORE closing the window and exiting fullscreen
     // (avoid stopping playback due to NSWindowWillCloseNotification, preserving fullscreen state)
-    [videoWindow setHasActiveVideo: NO];
+    videoWindow.hasActiveVideo = NO;
+
+    // do not close the window if we have the decorative view for audio visible
+    // or if we have enabled end-of-playback screens.
+    NSURL * const currentMediaUrl = _playerController.URLOfCurrentMediaItem;
+    VLCMediaLibraryMediaItem * const mediaItem =
+        [VLCMediaLibraryMediaItem mediaItemForURL:currentMediaUrl];
+    const BOOL decorativeViewVisible =
+        mediaItem != nil && mediaItem.mediaType == VLC_ML_MEDIA_TYPE_AUDIO;
+    const BOOL endOfPlaybackScreenEnabled =
+        [NSUserDefaults.standardUserDefaults boolForKey:VLCPlaybackEndViewEnabledKey];
+
+    // we need to check that the player itself is in a stopped state. Removal of the active video
+    // can be triggered by more than just end of playback (e.g. disabling the video track).
+    if (!decorativeViewVisible
+        && endOfPlaybackScreenEnabled
+        && _playerController.playerState == VLC_PLAYER_STATE_STOPPED) {
+        [videoWindow.videoViewController displayPlaybackEndView];
+        videoWindow.videoViewController.endViewDismissHandler = ^{
+            [self handleVideoCloseForDisplay:key];
+        };
+    } else if (!decorativeViewVisible) {
+        [self handleVideoCloseForDisplay:key];
+    }
+}
+
+- (void)handleVideoCloseForDisplay:(NSValue *)key
+{
+    VLCVideoWindowCommon * const videoWindow = [_voutWindows objectForKey:key];
+    if (!videoWindow) {
+        msg_Err(getIntf(), "Cannot handle close for nonexistent window");
+        return;
+    }
 
     // prevent visible extra window if in fullscreen
     [NSAnimationContext beginGrouping];
-    BOOL b_native = var_InheritBool(getIntf(), "macosx-nativefullscreenmode");
+    const BOOL b_native = var_InheritBool(getIntf(), "macosx-nativefullscreenmode");
 
     // close fullscreen, without changing fullscreen vars
-    if (!b_native && ([videoWindow fullscreen] || [videoWindow inFullscreenTransition]))
+    if (!b_native && (videoWindow.fullscreen || videoWindow.inFullscreenTransition))
         [videoWindow leaveFullscreenWithAnimation:NO];
 
     // native fullscreen window will not be closed if
     // fullscreen was triggered without video
-    if ((b_native && [videoWindow class] == [VLCLibraryWindow class] && [videoWindow fullscreen] && [videoWindow windowShouldExitFullscreenWhenFinished])) {
+    if (b_native
+        && videoWindow.class == VLCLibraryWindow.class
+        && videoWindow.fullscreen
+        && videoWindow.windowShouldExitFullscreenWhenFinished) {
         [videoWindow toggleFullScreen:self];
     }
 
-    if ([videoWindow class] != [VLCLibraryWindow class]) {
+    if (videoWindow.class == VLCLibraryWindow.class
+        && !videoWindow.videoViewController.view.hidden) {
+        [(VLCLibraryWindow *)videoWindow disableVideoPlaybackAppearance];
+    } else {
         [videoWindow close];
     }
     [NSAnimationContext endGrouping];
 
     [_voutWindows removeObjectForKey:key];
-    if ([_voutWindows count] == 0) {
-        [_playerController setActiveVideoPlayback:NO];
+    if (_voutWindows.count == 0) {
+        _playerController.activeVideoPlayback = NO;
         _statusLevelWindowCounter = 0;
     }
 
@@ -516,12 +571,11 @@ static int WindowFloatOnTop(vlc_object_t *obj,
         b_mainWindowHasVideo = NO;
 
         // video in main window might get stopped while another vout is open
-        if ([_voutWindows count] > 0)
-            [[mainInstance libraryWindow] setNonembedded:YES];
+        if (_voutWindows.count > 0)
+            VLCMain.sharedInstance.libraryWindow.nonembedded = YES;
     }
 }
 
-
 - (void)setNativeVideoSize:(NSSize)size forWindow:(vlc_window_t *)p_wnd
 {
     VLCVideoWindowCommon *o_window = [_voutWindows objectForKey:[NSValue valueWithPointer:p_wnd]];
@@ -603,7 +657,9 @@ static int WindowFloatOnTop(vlc_object_t *obj,
         if((b_fullscreen && !([o_current_window fullscreen] || [o_current_window inFullscreenTransition])) ||
            (!b_fullscreen && [o_current_window fullscreen])) {
 
-            [o_current_window toggleFullScreen:self];
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [o_current_window toggleFullScreen:self];
+            });
         }
     } else {
         assert(o_current_window);
@@ -612,11 +668,15 @@ static int WindowFloatOnTop(vlc_object_t *obj,
             if (_playerController.playerState != VLC_PLAYER_STATE_STOPPED && [_playerController activeVideoPlayback]) {
                 // activate app, as method can also be triggered from outside the app (prevents nasty window layout)
                 [NSApp activateIgnoringOtherApps:YES];
-                [o_current_window enterFullscreenWithAnimation:b_animation];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [o_current_window enterFullscreenWithAnimation:b_animation];
+                });
             }
         } else {
             // leaving fullscreen is always allowed
-            [o_current_window leaveFullscreenWithAnimation:YES];
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [o_current_window leaveFullscreenWithAnimation:YES];
+            });
         }
     }
 }


=====================================
modules/gui/macosx/windows/video/VLCVideoWindowCommon.m
=====================================
@@ -492,6 +492,15 @@ NSString *VLCWindowShouldShowController = @"VLCWindowShouldShowController";
         [self orderOut: self];
 
     _inFullscreenTransition = NO;
+    
+    if ([self hasActiveVideo]) {
+        vout_thread_t *p_vout = [_playerController videoOutputThreadForKeyWindow];
+        if (p_vout) {
+            var_SetBool(p_vout, "fullscreen", true);
+            vout_Release(p_vout);
+        }
+    }
+
     [self setFullscreen:YES];
 }
 
@@ -618,6 +627,14 @@ NSString *VLCWindowShouldShowController = @"VLCWindowShouldShowController";
     [self setLevel:i_originalLevel];
 
     [self setAlphaValue: config_GetFloat("macosx-opaqueness")];
+
+    if ([self hasActiveVideo]) {
+        vout_thread_t *p_vout = [_playerController videoOutputThreadForKeyWindow];
+        if (p_vout) {
+            var_SetBool(p_vout, "fullscreen", false);
+            vout_Release(p_vout);
+        }
+    }
 }
 
 - (void)animationDidEnd:(NSAnimation*)animation



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/bf1ef7069fd472b553712e4121e7468ffab595d4...a091acfd81056502faee103023b53261dd05865b

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/bf1ef7069fd472b553712e4121e7468ffab595d4...a091acfd81056502faee103023b53261dd05865b
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list