You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

559 lines
16 KiB

/*****************************************************************************
* VLCMain.m: MacOS X interface module
*****************************************************************************
* Copyright (C) 2002-2020 VLC authors and VideoLAN
*
* Authors: Derk-Jan Hartman <hartman at videolan.org>
* Felix Paul Kühne <fkuehne at videolan dot org>
* Pierre d'Herbemont <pdherbemont # videolan org>
* David Fuhrmann <david dot fuhrmann at googlemail dot com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#import "main/VLCMain.h"
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <stdatomic.h>
#include <sys/sysctl.h>
#include <vlc_common.h>
#include <vlc_actions.h>
#include <vlc_dialog.h>
#include <vlc_url.h>
#include <vlc_variables.h>
#include <vlc_preparser.h>
#import "extensions/NSString+Helpers.h"
#import "library/VLCLibraryController.h"
#import "library/VLCLibraryWindow.h"
#import "library/VLCLibraryWindowController.h"
#import "main/CompatibilityFixes.h"
#import "main/VLCMain+OldPrefs.h"
#import "main/VLCApplication.h"
#import "menus/VLCMainMenu.h"
#import "menus/VLCStatusBarIcon.h"
#import "os-integration/VLCClickerManager.h"
#import "panels/dialogs/VLCCoreDialogProvider.h"
#import "panels/VLCAudioEffectsWindowController.h"
#import "panels/VLCBookmarksWindowController.h"
#import "panels/VLCVideoEffectsWindowController.h"
#import "panels/VLCTrackSynchronizationWindowController.h"
#import "playlist/VLCPlaylistController.h"
#import "playlist/VLCPlayerController.h"
#import "playlist/VLCPlaylistModel.h"
#import "playlist/VLCPlaybackContinuityController.h"
#import "preferences/prefs.h"
#import "preferences/VLCSimplePrefsController.h"
#import "windows/VLCDetachedAudioWindow.h"
#import "windows/VLCOpenWindowController.h"
#import "windows/VLCOpenInputMetadata.h"
#import "windows/convertandsave/VLCConvertAndSaveWindowController.h"
#import "windows/extensions/VLCExtensionsManager.h"
#import "windows/logging/VLCLogWindowController.h"
#import "windows/video/VLCVoutView.h"
#import "windows/video/VLCVideoOutputProvider.h"
#ifdef HAVE_SPARKLE
#import <Sparkle/Sparkle.h> /* we're the update delegate */
NSString *const kIntel64UpdateURLString = @"https://update.videolan.org/vlc/sparkle/vlc-intel64.xml";
NSString *const kARM64UpdateURLString = @"https://update.videolan.org/vlc/sparkle/vlc-arm64.xml";
#endif
NSString *VLCConfigurationChangedNotification = @"VLCConfigurationChangedNotification";
#pragma mark -
#pragma mark Private extension
@interface VLCMain ()
#ifdef HAVE_SPARKLE
<SUUpdaterDelegate, NSApplicationDelegate>
#else
<NSApplicationDelegate>
#endif
{
intf_thread_t *_p_intf;
BOOL _launched;
VLCMainMenu *_mainmenu;
VLCPrefs *_prefs;
VLCSimplePrefsController *_sprefs;
VLCOpenWindowController *_open;
VLCCoreDialogProvider *_coredialogs;
VLCBookmarksWindowController *_bookmarks;
VLCPlaybackContinuityController *_continuityController;
VLCLogWindowController *_messagePanelController;
VLCStatusBarIcon *_statusBarIcon;
VLCTrackSynchronizationWindowController *_trackSyncPanel;
VLCAudioEffectsWindowController *_audioEffectsPanel;
VLCVideoEffectsWindowController *_videoEffectsPanel;
VLCConvertAndSaveWindowController *_convertAndSaveWindow;
VLCClickerManager *_clickerManager;
VLCDetachedAudioWindow *_detachedAudioWindow;
bool _interfaceIsTerminating; /* Makes sure applicationWillTerminate will be called only once */
}
+ (void)killInstance;
- (void)applicationWillTerminate:(NSNotification *)notification;
@end
#pragma mark -
#pragma mark VLC Interface Object Callbacks
/*****************************************************************************
* OpenIntf: initialize interface
*****************************************************************************/
static intf_thread_t *p_interface_thread;
static vlc_preparser_t *p_network_preparser;
intf_thread_t *getIntf()
{
return p_interface_thread;
}
vlc_preparser_t *getNetworkPreparser()
{
return p_network_preparser;
}
int OpenIntf (vlc_object_t *p_this)
{
__block int retcode = VLC_SUCCESS;
macosx: VLCMain: use CFRunLoop to avoid servicing dispatch The main dispatch_queue is a serial queue and cannot be re-entered, so we cannot start the NSApp runloop there since it will block into the callback while servicing the main queue, and thus no more blocks will be able to be executed on this main dispatch_queue. It is visible with the callstack there: thread #1, queue = 'com.apple.main-thread' frame #0: 0x0000000183c3e1f4 libsystem_kernel.dylib`mach_msg2_trap + 8 frame #1: 0x0000000183c50b24 libsystem_kernel.dylib`mach_msg2_internal + 80 frame #2: 0x0000000183c46e34 libsystem_kernel.dylib`mach_msg_overwrite + 476 frame #3: 0x0000000183c3e578 libsystem_kernel.dylib`mach_msg + 24 frame #4: 0x0000000183d5e680 CoreFoundation`__CFRunLoopServiceMachPort + 160 frame #5: 0x0000000183d5cf44 CoreFoundation`__CFRunLoopRun + 1208 frame #6: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #7: 0x000000018e50019c HIToolbox`RunCurrentEventLoopInMode + 292 frame #8: 0x000000018e4fffd8 HIToolbox`ReceiveNextEventCommon + 648 frame #9: 0x000000018e4ffd30 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #10: 0x00000001875bbd68 AppKit`_DPSNextEvent + 660 frame #11: 0x0000000187db1808 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 700 frame #12: 0x00000001875af09c AppKit`-[NSApplication run] + 476 frame #13: 0x00000001030b791c libmacosx_plugin.dylib`__OpenIntf_block_invoke_2(.block_descriptor=<unavailable>) at VLCMain.m:166:17 [opt] frame #14: 0x0000000183acc750 libdispatch.dylib`_dispatch_call_block_and_release + 32 frame #15: 0x0000000183ace3e8 libdispatch.dylib`_dispatch_client_callout + 20 frame #16: 0x0000000183adcbb8 libdispatch.dylib`_dispatch_main_queue_drain + 988 frame #17: 0x0000000183adc7cc libdispatch.dylib`_dispatch_main_queue_callback_4CF + 44 frame #18: 0x0000000183d9fad4 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 frame #19: 0x0000000183d5d258 CoreFoundation`__CFRunLoopRun + 1996 frame #20: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #21: 0x0000000183dda45c CoreFoundation`CFRunLoopRun + 64 frame #22: 0x0000000100003084 vlc-osx-static`main(i_argc=1, ppsz_argv=0x000000016fdff0c8) at darwinvlc.m:309:9 [opt] frame #23: 0x00000001838f60e0 dyld`start + 2360 By running the CFRunLoop instead, we don't have this serial execution constraint and can re-enter the loop while servicing the main dispatch queue from inside the [NSApp run] runloop. It now has the following callstack when running: thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x0000000183c3e1f4 libsystem_kernel.dylib`mach_msg2_trap + 8 frame #1: 0x0000000183c50b24 libsystem_kernel.dylib`mach_msg2_internal + 80 frame #2: 0x0000000183c46e34 libsystem_kernel.dylib`mach_msg_overwrite + 476 frame #3: 0x0000000183c3e578 libsystem_kernel.dylib`mach_msg + 24 frame #4: 0x0000000183d5e680 CoreFoundation`__CFRunLoopServiceMachPort + 160 frame #5: 0x0000000183d5cf44 CoreFoundation`__CFRunLoopRun + 1208 frame #6: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #7: 0x000000018e50019c HIToolbox`RunCurrentEventLoopInMode + 292 frame #8: 0x000000018e4fffd8 HIToolbox`ReceiveNextEventCommon + 648 frame #9: 0x000000018e4ffd30 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #10: 0x00000001875bbd68 AppKit`_DPSNextEvent + 660 frame #11: 0x0000000187db1808 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 700 frame #12: 0x00000001875af09c AppKit`-[NSApplication run] + 476 frame #13: 0x00000001030b76c8 libmacosx_plugin.dylib`__OpenIntf_block_invoke(.block_descriptor=0x00006000038813c0) at VLCMain.m:166:13 [opt] frame #14: 0x0000000183d5e070 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 frame #15: 0x0000000183d5df84 CoreFoundation`__CFRunLoopDoBlocks + 356 frame #16: 0x0000000183d5d414 CoreFoundation`__CFRunLoopRun + 2440 frame #17: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #18: 0x0000000183dda45c CoreFoundation`CFRunLoopRun + 64 frame #19: 0x0000000100003084 vlc-osx-static`main(i_argc=1, ppsz_argv=0x000000016fdff0c8) at darwinvlc.m:309:9 [opt] frame #20: 0x00000001838f60e0 dyld`start + 2360 And now dispatch will correctly work inside this. Regression from 3a6bd45b9e8d1f4c5e24b6031a8df44523e6c4b1 which introduced the dispatch call and then changed also in 9cae3668c7fc1fc00939f0683c0c2293556a8d39 which also modified the dispatch call in the destructor. Fixes #28812
2 years ago
__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
@autoreleasepool {
intf_thread_t *p_intf = (intf_thread_t*) p_this;
p_interface_thread = p_intf;
const struct vlc_preparser_cfg cfg = {
.types = VLC_PREPARSER_TYPE_PARSE,
.max_parser_threads = 1,
.timeout = 0,
};
p_network_preparser = vlc_preparser_New(p_this, &cfg);
if (p_network_preparser == nil)
{
retcode = VLC_ENOMEM;
dispatch_semaphore_signal(sem);
return;
}
msg_Dbg(p_intf, "Starting macosx interface");
@try {
VLCApplication * const application = VLCApplication.sharedApplication;
NSCAssert(application != nil, @"VLCApplication must not be nil");
VLCMain * const main = VLCMain.sharedInstance;
NSCAssert(main != nil, @"VLCMain must not be nil");
msg_Dbg(p_intf, "Finished loading macosx interface");
} @catch (NSException *exception) {
msg_Err(p_intf, "Loading the macosx interface failed. Do you have a valid window server?");
retcode = VLC_EGENERIC;
dispatch_semaphore_signal(sem);
return;
}
macosx: VLCMain: use CFRunLoop to avoid servicing dispatch The main dispatch_queue is a serial queue and cannot be re-entered, so we cannot start the NSApp runloop there since it will block into the callback while servicing the main queue, and thus no more blocks will be able to be executed on this main dispatch_queue. It is visible with the callstack there: thread #1, queue = 'com.apple.main-thread' frame #0: 0x0000000183c3e1f4 libsystem_kernel.dylib`mach_msg2_trap + 8 frame #1: 0x0000000183c50b24 libsystem_kernel.dylib`mach_msg2_internal + 80 frame #2: 0x0000000183c46e34 libsystem_kernel.dylib`mach_msg_overwrite + 476 frame #3: 0x0000000183c3e578 libsystem_kernel.dylib`mach_msg + 24 frame #4: 0x0000000183d5e680 CoreFoundation`__CFRunLoopServiceMachPort + 160 frame #5: 0x0000000183d5cf44 CoreFoundation`__CFRunLoopRun + 1208 frame #6: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #7: 0x000000018e50019c HIToolbox`RunCurrentEventLoopInMode + 292 frame #8: 0x000000018e4fffd8 HIToolbox`ReceiveNextEventCommon + 648 frame #9: 0x000000018e4ffd30 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #10: 0x00000001875bbd68 AppKit`_DPSNextEvent + 660 frame #11: 0x0000000187db1808 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 700 frame #12: 0x00000001875af09c AppKit`-[NSApplication run] + 476 frame #13: 0x00000001030b791c libmacosx_plugin.dylib`__OpenIntf_block_invoke_2(.block_descriptor=<unavailable>) at VLCMain.m:166:17 [opt] frame #14: 0x0000000183acc750 libdispatch.dylib`_dispatch_call_block_and_release + 32 frame #15: 0x0000000183ace3e8 libdispatch.dylib`_dispatch_client_callout + 20 frame #16: 0x0000000183adcbb8 libdispatch.dylib`_dispatch_main_queue_drain + 988 frame #17: 0x0000000183adc7cc libdispatch.dylib`_dispatch_main_queue_callback_4CF + 44 frame #18: 0x0000000183d9fad4 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 frame #19: 0x0000000183d5d258 CoreFoundation`__CFRunLoopRun + 1996 frame #20: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #21: 0x0000000183dda45c CoreFoundation`CFRunLoopRun + 64 frame #22: 0x0000000100003084 vlc-osx-static`main(i_argc=1, ppsz_argv=0x000000016fdff0c8) at darwinvlc.m:309:9 [opt] frame #23: 0x00000001838f60e0 dyld`start + 2360 By running the CFRunLoop instead, we don't have this serial execution constraint and can re-enter the loop while servicing the main dispatch queue from inside the [NSApp run] runloop. It now has the following callstack when running: thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x0000000183c3e1f4 libsystem_kernel.dylib`mach_msg2_trap + 8 frame #1: 0x0000000183c50b24 libsystem_kernel.dylib`mach_msg2_internal + 80 frame #2: 0x0000000183c46e34 libsystem_kernel.dylib`mach_msg_overwrite + 476 frame #3: 0x0000000183c3e578 libsystem_kernel.dylib`mach_msg + 24 frame #4: 0x0000000183d5e680 CoreFoundation`__CFRunLoopServiceMachPort + 160 frame #5: 0x0000000183d5cf44 CoreFoundation`__CFRunLoopRun + 1208 frame #6: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #7: 0x000000018e50019c HIToolbox`RunCurrentEventLoopInMode + 292 frame #8: 0x000000018e4fffd8 HIToolbox`ReceiveNextEventCommon + 648 frame #9: 0x000000018e4ffd30 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #10: 0x00000001875bbd68 AppKit`_DPSNextEvent + 660 frame #11: 0x0000000187db1808 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 700 frame #12: 0x00000001875af09c AppKit`-[NSApplication run] + 476 frame #13: 0x00000001030b76c8 libmacosx_plugin.dylib`__OpenIntf_block_invoke(.block_descriptor=0x00006000038813c0) at VLCMain.m:166:13 [opt] frame #14: 0x0000000183d5e070 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 frame #15: 0x0000000183d5df84 CoreFoundation`__CFRunLoopDoBlocks + 356 frame #16: 0x0000000183d5d414 CoreFoundation`__CFRunLoopRun + 2440 frame #17: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #18: 0x0000000183dda45c CoreFoundation`CFRunLoopRun + 64 frame #19: 0x0000000100003084 vlc-osx-static`main(i_argc=1, ppsz_argv=0x000000016fdff0c8) at darwinvlc.m:309:9 [opt] frame #20: 0x00000001838f60e0 dyld`start + 2360 And now dispatch will correctly work inside this. Regression from 3a6bd45b9e8d1f4c5e24b6031a8df44523e6c4b1 which introduced the dispatch call and then changed also in 9cae3668c7fc1fc00939f0683c0c2293556a8d39 which also modified the dispatch call in the destructor. Fixes #28812
2 years ago
dispatch_semaphore_signal(sem);
[NSApp run];
}
});
macosx: VLCMain: use CFRunLoop to avoid servicing dispatch The main dispatch_queue is a serial queue and cannot be re-entered, so we cannot start the NSApp runloop there since it will block into the callback while servicing the main queue, and thus no more blocks will be able to be executed on this main dispatch_queue. It is visible with the callstack there: thread #1, queue = 'com.apple.main-thread' frame #0: 0x0000000183c3e1f4 libsystem_kernel.dylib`mach_msg2_trap + 8 frame #1: 0x0000000183c50b24 libsystem_kernel.dylib`mach_msg2_internal + 80 frame #2: 0x0000000183c46e34 libsystem_kernel.dylib`mach_msg_overwrite + 476 frame #3: 0x0000000183c3e578 libsystem_kernel.dylib`mach_msg + 24 frame #4: 0x0000000183d5e680 CoreFoundation`__CFRunLoopServiceMachPort + 160 frame #5: 0x0000000183d5cf44 CoreFoundation`__CFRunLoopRun + 1208 frame #6: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #7: 0x000000018e50019c HIToolbox`RunCurrentEventLoopInMode + 292 frame #8: 0x000000018e4fffd8 HIToolbox`ReceiveNextEventCommon + 648 frame #9: 0x000000018e4ffd30 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #10: 0x00000001875bbd68 AppKit`_DPSNextEvent + 660 frame #11: 0x0000000187db1808 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 700 frame #12: 0x00000001875af09c AppKit`-[NSApplication run] + 476 frame #13: 0x00000001030b791c libmacosx_plugin.dylib`__OpenIntf_block_invoke_2(.block_descriptor=<unavailable>) at VLCMain.m:166:17 [opt] frame #14: 0x0000000183acc750 libdispatch.dylib`_dispatch_call_block_and_release + 32 frame #15: 0x0000000183ace3e8 libdispatch.dylib`_dispatch_client_callout + 20 frame #16: 0x0000000183adcbb8 libdispatch.dylib`_dispatch_main_queue_drain + 988 frame #17: 0x0000000183adc7cc libdispatch.dylib`_dispatch_main_queue_callback_4CF + 44 frame #18: 0x0000000183d9fad4 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 frame #19: 0x0000000183d5d258 CoreFoundation`__CFRunLoopRun + 1996 frame #20: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #21: 0x0000000183dda45c CoreFoundation`CFRunLoopRun + 64 frame #22: 0x0000000100003084 vlc-osx-static`main(i_argc=1, ppsz_argv=0x000000016fdff0c8) at darwinvlc.m:309:9 [opt] frame #23: 0x00000001838f60e0 dyld`start + 2360 By running the CFRunLoop instead, we don't have this serial execution constraint and can re-enter the loop while servicing the main dispatch queue from inside the [NSApp run] runloop. It now has the following callstack when running: thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x0000000183c3e1f4 libsystem_kernel.dylib`mach_msg2_trap + 8 frame #1: 0x0000000183c50b24 libsystem_kernel.dylib`mach_msg2_internal + 80 frame #2: 0x0000000183c46e34 libsystem_kernel.dylib`mach_msg_overwrite + 476 frame #3: 0x0000000183c3e578 libsystem_kernel.dylib`mach_msg + 24 frame #4: 0x0000000183d5e680 CoreFoundation`__CFRunLoopServiceMachPort + 160 frame #5: 0x0000000183d5cf44 CoreFoundation`__CFRunLoopRun + 1208 frame #6: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #7: 0x000000018e50019c HIToolbox`RunCurrentEventLoopInMode + 292 frame #8: 0x000000018e4fffd8 HIToolbox`ReceiveNextEventCommon + 648 frame #9: 0x000000018e4ffd30 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #10: 0x00000001875bbd68 AppKit`_DPSNextEvent + 660 frame #11: 0x0000000187db1808 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 700 frame #12: 0x00000001875af09c AppKit`-[NSApplication run] + 476 frame #13: 0x00000001030b76c8 libmacosx_plugin.dylib`__OpenIntf_block_invoke(.block_descriptor=0x00006000038813c0) at VLCMain.m:166:13 [opt] frame #14: 0x0000000183d5e070 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 frame #15: 0x0000000183d5df84 CoreFoundation`__CFRunLoopDoBlocks + 356 frame #16: 0x0000000183d5d414 CoreFoundation`__CFRunLoopRun + 2440 frame #17: 0x0000000183d5c434 CoreFoundation`CFRunLoopRunSpecific + 608 frame #18: 0x0000000183dda45c CoreFoundation`CFRunLoopRun + 64 frame #19: 0x0000000100003084 vlc-osx-static`main(i_argc=1, ppsz_argv=0x000000016fdff0c8) at darwinvlc.m:309:9 [opt] frame #20: 0x00000001838f60e0 dyld`start + 2360 And now dispatch will correctly work inside this. Regression from 3a6bd45b9e8d1f4c5e24b6031a8df44523e6c4b1 which introduced the dispatch call and then changed also in 9cae3668c7fc1fc00939f0683c0c2293556a8d39 which also modified the dispatch call in the destructor. Fixes #28812
2 years ago
CFRunLoopWakeUp(CFRunLoopGetMain());
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return retcode;
}
void CloseIntf (vlc_object_t *p_this)
{
void (^release_intf)() = ^{
@autoreleasepool {
msg_Dbg(p_this, "Closing macosx interface");
[VLCMain.sharedInstance applicationWillTerminate:nil];
[VLCMain killInstance];
}
p_interface_thread = nil;
vlc_preparser_Delete(p_network_preparser);
p_network_preparser = nil;
};
if (CFRunLoopGetCurrent() == CFRunLoopGetMain())
release_intf();
else
dispatch_sync(dispatch_get_main_queue(), release_intf);
}
/*****************************************************************************
* VLCMain implementation
*****************************************************************************/
@implementation VLCMain
#pragma mark -
#pragma mark Initialization
static VLCMain *sharedInstance = nil;
+ (VLCMain *)sharedInstance;
{
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedInstance = [[VLCMain alloc] init];
});
return sharedInstance;
}
+ (void)killInstance
{
sharedInstance = nil;
}
+ (void)relaunchApplication
{
const char *path = [[[NSBundle mainBundle] executablePath] UTF8String];
/* For some reason we need to fork(), not just execl(), which reports a ENOTSUP then. */
if (fork() != 0) {
exit(0);
}
execl(path, path, (char *)NULL);
}
- (id)init
{
self = [super init];
11 years ago
if (self) {
_p_intf = getIntf();
VLCApplication.sharedApplication.delegate = self;
_playlistController = [[VLCPlaylistController alloc] initWithPlaylist:vlc_intf_GetMainPlaylist(_p_intf)];
_libraryController = [[VLCLibraryController alloc] init];
_continuityController = [[VLCPlaybackContinuityController alloc] init];
// first initialize extensions dialog provider, then core dialog
// provider which will register both at the core
_extensionsManager = [[VLCExtensionsManager alloc] init];
_coredialogs = [[VLCCoreDialogProvider alloc] init];
_mainmenu = [[VLCMainMenu alloc] init];
_voutProvider = [[VLCVideoOutputProvider alloc] init];
// Load them here already to apply stored profiles
_videoEffectsPanel = [[VLCVideoEffectsWindowController alloc] init];
_audioEffectsPanel = [[VLCAudioEffectsWindowController alloc] init];
if ([NSApp currentSystemPresentationOptions] & NSApplicationPresentationFullScreen)
[_playlistController.playerController setFullscreen:YES];
11 years ago
}
return self;
}
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
_clickerManager = [[VLCClickerManager alloc] init];
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:_mainmenu topLevelObjects:nil];
#ifdef HAVE_SPARKLE
[[SUUpdater sharedUpdater] setDelegate:self];
#endif
NSImage *appIconImage = [VLCApplication.sharedApplication vlcAppIconImage];
[VLCApplication.sharedApplication
setApplicationIconImage:appIconImage];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_launched = YES;
if (_libraryWindowController == nil) {
_libraryWindowController = [[VLCLibraryWindowController alloc] initWithLibraryWindow];
}
[_libraryWindowController.window makeKeyAndOrderFront:nil];
if (!_p_intf)
return;
[self migrateOldPreferences];
_statusBarIcon = [[VLCStatusBarIcon alloc] init];
/* on macOS 11 and later, check whether the user attempts to deploy
* the x86_64 binary on ARM-64 - if yes, log it */
if (OSX_BIGSUR_AND_HIGHER) {
if ([self processIsTranslated] > 0) {
msg_Warn(getIntf(), "Process is translated!");
}
}
}
- (int)processIsTranslated
{
int ret = 0;
size_t size = sizeof(ret);
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
if (errno == ENOENT)
return 0;
return -1;
}
return ret;
}
#pragma mark -
#pragma mark Termination
- (BOOL)isTerminating
{
return _interfaceIsTerminating;
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
if (_interfaceIsTerminating)
return;
_interfaceIsTerminating = true;
NSNotificationCenter *notiticationCenter = NSNotificationCenter.defaultCenter;
if (notification == nil) {
[notiticationCenter postNotificationName: NSApplicationWillTerminateNotification object: nil];
}
[notiticationCenter removeObserver: self];
// closes all open vouts
_voutProvider = nil;
_continuityController = nil;
/* write cached user defaults to disk */
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
}
#pragma mark -
#pragma mark Sparkle delegate
#ifdef HAVE_SPARKLE
/* received directly before the update gets installed, so let's shut down a bit */
- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update
{
[NSApp activateIgnoringOtherApps:YES];
[_playlistController stopPlayback];
}
/* don't be enthusiastic about an update if we currently play a video */
- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)bundle
{
if ([_playlistController.playerController activeVideoPlayback])
return NO;
return YES;
}
/* use the correct feed depending on the hardware architecture */
- (nullable NSString *)feedURLStringForUpdater:(SUUpdater *)updater
{
#ifdef __x86_64__
if (OSX_BIGSUR_AND_HIGHER) {
if ([self processIsTranslated] > 0) {
msg_Dbg(getIntf(), "Process is translated. On update, VLC will install the native ARM-64 binary.");
return kARM64UpdateURLString;
}
}
return kIntel64UpdateURLString;
#elif __arm64__
return kARM64UpdateURLString;
#else
#error unsupported architecture
#endif
}
- (void)updaterDidNotFindUpdate:(SUUpdater *)updater
{
msg_Dbg(getIntf(), "No update found");
}
- (void)updater:(SUUpdater *)updater failedToDownloadUpdate:(SUAppcastItem *)item error:(NSError *)error
{
msg_Warn(getIntf(), "Failed to download update with error %li", error.code);
}
- (void)updater:(SUUpdater *)updater didAbortWithError:(NSError *)error
{
msg_Err(getIntf(), "Updater aborted with error %li", error.code);
}
#endif
#pragma mark -
#pragma mark File opening over dock icon
- (void)application:(NSApplication *)o_app openFiles:(NSArray *)o_names
{
// Only add items here which are getting dropped to to the application icon
// or are given at startup. If a file is passed via command line, libvlccore
// will add the item, but cocoa also calls this function. In this case, the
// invocation is ignored here.
NSArray *resultItems = o_names;
if (_launched == NO) {
NSArray *launchArgs = [[NSProcessInfo processInfo] arguments];
if (launchArgs) {
NSSet *launchArgsSet = [NSSet setWithArray:launchArgs];
NSMutableSet *itemSet = [NSMutableSet setWithArray:o_names];
[itemSet minusSet:launchArgsSet];
resultItems = [itemSet allObjects];
}
}
NSArray *o_sorted_names = [resultItems sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)];
NSMutableArray *o_result = [NSMutableArray arrayWithCapacity: [o_sorted_names count]];
for (NSString *filepath in o_sorted_names) {
VLCOpenInputMetadata *inputMetadata;
inputMetadata = [VLCOpenInputMetadata inputMetaWithPath:filepath];
if (!inputMetadata)
continue;
[o_result addObject:inputMetadata];
}
[_playlistController addPlaylistItems:o_result];
}
/* When user click in the Dock icon our double click in the finder */
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)hasVisibleWindows
{
if (!hasVisibleWindows)
[[self libraryWindow] makeKeyAndOrderFront:self];
return YES;
}
#pragma mark -
#pragma mark Other objects getters
- (VLCMainMenu *)mainMenu
{
return _mainmenu;
}
- (VLCLibraryWindow *)libraryWindow
{
return (VLCLibraryWindow *)_libraryWindowController.window;
}
- (VLCLogWindowController *)debugMsgPanel
{
if (!_messagePanelController)
_messagePanelController = [[VLCLogWindowController alloc] init];
return _messagePanelController;
}
- (VLCTrackSynchronizationWindowController *)trackSyncPanel
{
if (!_trackSyncPanel)
_trackSyncPanel = [[VLCTrackSynchronizationWindowController alloc] init];
return _trackSyncPanel;
}
- (VLCAudioEffectsWindowController *)audioEffectsPanel
{
return _audioEffectsPanel;
}
- (VLCVideoEffectsWindowController *)videoEffectsPanel
{
return _videoEffectsPanel;
}
- (VLCBookmarksWindowController *)bookmarks
{
if (!_bookmarks)
_bookmarks = [[VLCBookmarksWindowController alloc] init];
return _bookmarks;
}
- (VLCOpenWindowController *)open
{
if (!_open)
_open = [[VLCOpenWindowController alloc] init];
return _open;
}
- (VLCConvertAndSaveWindowController *)convertAndSaveWindow
{
if (_convertAndSaveWindow == nil)
_convertAndSaveWindow = [[VLCConvertAndSaveWindowController alloc] init];
return _convertAndSaveWindow;
}
- (VLCSimplePrefsController *)simplePreferences
{
if (!_sprefs)
_sprefs = [[VLCSimplePrefsController alloc] init];
return _sprefs;
}
- (VLCPrefs *)preferences
{
if (!_prefs)
_prefs = [[VLCPrefs alloc] init];
return _prefs;
}
- (VLCCoreDialogProvider *)coreDialogProvider
{
return _coredialogs;
}
- (VLCDetachedAudioWindow *)detachedAudioWindow
{
if (_detachedAudioWindow == nil) {
NSWindowController * const windowController = [[NSWindowController alloc] initWithWindowNibName:NSStringFromClass(VLCDetachedAudioWindow.class)];
[windowController loadWindow];
_detachedAudioWindow = (VLCDetachedAudioWindow *)windowController.window;
}
return _detachedAudioWindow;
}
@end