mirror of https://github.com/mpv-player/mpv
mac/app: cleanup and optimise App launch and termination
NSApp.terminate() is not a requirement to properly shut down a cocoa App since it only calls exit() internally. though when not used the cocoa termination events won't trigger, which we don't need. this prevented us to exit with a proper exit code. rework the whole termination logic to end up at one point where we can return the exit code from the mpv_main function. Fixes #7456
This commit is contained in:
parent
d6c621b03b
commit
3c51497954
|
@ -19,6 +19,8 @@ import Cocoa
|
||||||
|
|
||||||
class Application: NSApplication, NSApplicationDelegate {
|
class Application: NSApplication, NSApplicationDelegate {
|
||||||
var appHub: AppHub { get { return AppHub.shared } }
|
var appHub: AppHub { get { return AppHub.shared } }
|
||||||
|
var eventManager: NSAppleEventManager { get { return NSAppleEventManager.shared() } }
|
||||||
|
var isBundle: Bool { get { return ProcessInfo.processInfo.environment["MPVBUNDLE"] == "true" } }
|
||||||
var playbackThreadId: mp_thread!
|
var playbackThreadId: mp_thread!
|
||||||
var argc: Int32?
|
var argc: Int32?
|
||||||
var argv: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
|
var argv: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
|
||||||
|
@ -31,34 +33,6 @@ class Application: NSApplication, NSApplicationDelegate {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
|
||||||
let eventManager = NSAppleEventManager.shared()
|
|
||||||
eventManager.removeEventHandler(forEventClass: AEEventClass(kCoreEventClass), andEventID: kAEQuitApplication)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initApplication(_ regular: Bool) {
|
|
||||||
NSApp = self
|
|
||||||
NSApp.delegate = self
|
|
||||||
|
|
||||||
// Will be set to Regular from cocoa_common during UI creation so that we
|
|
||||||
// don't create an icon when playing audio only files.
|
|
||||||
NSApp.setActivationPolicy(regular ? .regular : .accessory)
|
|
||||||
|
|
||||||
atexit_b({
|
|
||||||
// Because activation policy has just been set to behave like a real
|
|
||||||
// application, that policy must be reset on exit to prevent, among
|
|
||||||
// other things, the menubar created here from remaining on screen.
|
|
||||||
DispatchQueue.main.async { NSApp.setActivationPolicy(.prohibited) }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func terminateApplication() {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
NSApp.hide(NSApp)
|
|
||||||
NSApp.terminate(NSApp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func sendEvent(_ event: NSEvent) {
|
override func sendEvent(_ event: NSEvent) {
|
||||||
if modalWindow != nil || !appHub.input.processKey(event: event) {
|
if modalWindow != nil || !appHub.input.processKey(event: event) {
|
||||||
super.sendEvent(event)
|
super.sendEvent(event)
|
||||||
|
@ -77,29 +51,36 @@ class Application: NSApplication, NSApplicationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationWillFinishLaunching(_ notification: Notification) {
|
func applicationWillFinishLaunching(_ notification: Notification) {
|
||||||
let eventManager = NSAppleEventManager.shared()
|
// register quit and exit events
|
||||||
eventManager.setEventHandler(
|
eventManager.setEventHandler(
|
||||||
self,
|
self,
|
||||||
andSelector: #selector(handleQuit(event:replyEvent:)),
|
andSelector: #selector(handleQuit(event:replyEvent:)),
|
||||||
forEventClass: AEEventClass(kCoreEventClass),
|
forEventClass: AEEventClass(kCoreEventClass),
|
||||||
andEventID: kAEQuitApplication
|
andEventID: kAEQuitApplication
|
||||||
)
|
)
|
||||||
|
atexit_b({
|
||||||
|
// clean up after exit() was called
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NSApp.hide(NSApp)
|
||||||
|
NSApp.setActivationPolicy(.prohibited)
|
||||||
|
self.eventManager.removeEventHandler(forEventClass: AEEventClass(kCoreEventClass), andEventID: kAEQuitApplication)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// quit from App icon
|
// quit from App icon, external quit from NSWorkspace
|
||||||
@objc func handleQuit(event: NSAppleEventDescriptor?, replyEvent: NSAppleEventDescriptor?) {
|
@objc func handleQuit(event: NSAppleEventDescriptor?, replyEvent: NSAppleEventDescriptor?) {
|
||||||
|
// send quit to core, terminates mpv_main called in playbackThread,
|
||||||
if !appHub.input.command("quit") {
|
if !appHub.input.command("quit") {
|
||||||
terminateApplication()
|
appHub.log.warning("Could not properly shut down mpv")
|
||||||
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func bundleStartedFromFinder() -> Bool {
|
|
||||||
return ProcessInfo.processInfo.environment["MPVBUNDLE"] == "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupBundle() {
|
func setupBundle() {
|
||||||
|
if !isBundle { return }
|
||||||
|
|
||||||
// started from finder the first argument after the binary may start with -psn_
|
// started from finder the first argument after the binary may start with -psn_
|
||||||
// remove it and all following
|
|
||||||
if CommandLine.argc > 1 && CommandLine.arguments[1].hasPrefix("-psn_") {
|
if CommandLine.argc > 1 && CommandLine.arguments[1].hasPrefix("-psn_") {
|
||||||
argc? = 1
|
argc? = 1
|
||||||
argv?[1] = nil
|
argv?[1] = nil
|
||||||
|
@ -113,28 +94,24 @@ class Application: NSApplication, NSApplicationDelegate {
|
||||||
let playbackThread: @convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? = { (ptr: UnsafeMutableRawPointer) in
|
let playbackThread: @convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? = { (ptr: UnsafeMutableRawPointer) in
|
||||||
let application: Application = TypeHelper.bridge(ptr: ptr)
|
let application: Application = TypeHelper.bridge(ptr: ptr)
|
||||||
mp_thread_set_name("core/playback")
|
mp_thread_set_name("core/playback")
|
||||||
let r: Int32 = mpv_main(application.argc ?? 1, application.argv)
|
let exitCode: Int32 = mpv_main(application.argc ?? 1, application.argv)
|
||||||
application.terminateApplication()
|
// exit of any proper shut down
|
||||||
// normally never reached - unless the cocoa mainloop hasn't started yet
|
exit(exitCode)
|
||||||
exit(r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func main(_ argc: Int32, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>) -> Int {
|
@objc func main(_ argc: Int32, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>) -> Int {
|
||||||
self.argc = argc
|
self.argc = argc
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
|
|
||||||
if bundleStartedFromFinder() {
|
NSApp = self
|
||||||
setupBundle()
|
NSApp.delegate = self
|
||||||
initApplication(true)
|
NSApp.setActivationPolicy(isBundle ? .regular : .accessory)
|
||||||
} else {
|
setupBundle()
|
||||||
initApplication(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_create(&playbackThreadId, nil, playbackThread, TypeHelper.bridge(obj: self))
|
pthread_create(&playbackThreadId, nil, playbackThread, TypeHelper.bridge(obj: self))
|
||||||
appHub.input.wait()
|
appHub.input.wait()
|
||||||
NSApp.run()
|
NSApp.run()
|
||||||
|
|
||||||
// This should never be reached: NSApp.run() blocks until the process is quit
|
// should never be reached
|
||||||
print("""
|
print("""
|
||||||
There was either a problem initializing Cocoa or the Runloop was stopped unexpectedly. \
|
There was either a problem initializing Cocoa or the Runloop was stopped unexpectedly. \
|
||||||
Please report this issues to a developer.\n
|
Please report this issues to a developer.\n
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#include "osdep/mac/app_bridge.h"
|
#include "osdep/mac/app_bridge.h"
|
||||||
|
|
||||||
// This is needed because Cocoa absolutely requires creating the NSApplication
|
// Cocoa absolutely requires creating the NSApplication singleton and running it on the main thread.
|
||||||
// singleton and running it in the "main" thread. It is apparently not
|
|
||||||
// possible to do this on a separate thread at all. It is not known how
|
|
||||||
// Apple managed this colossal fuckup.
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
return cocoa_main(argc, argv);
|
return cocoa_main(argc, argv);
|
||||||
|
|
Loading…
Reference in New Issue