Cancel relaunch when closing documens is cancelled

This commit is contained in:
1024jp 2021-09-22 14:57:00 +09:00
parent ff28b552e3
commit c9b7a5a034
5 changed files with 59 additions and 2 deletions

View File

@ -17,6 +17,7 @@ Change Log
- Improve VoiceOver accessibility.
- Update the AppleScript guide in the help.
- Change the behavior to include the last line in the calculation when specifying lines with a negative value in the Go to Line command or via AppleScript.
- Make sure the application relaunchs even other tasks interrupt before termination.
- [dev] Update the build environment to Xcode 13 (Swift 5.5).
- [non-AppStore ver.] Update Sparkle to 2.0.0-beta.3.

View File

@ -56,6 +56,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
}
// MARK: Public Properties
var needsRelaunch = false
// MARK: Private Properties
private var menuUpdateObservers: Set<AnyCancellable> = []
@ -179,6 +184,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
}
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
NSApp.reply(toApplicationShouldTerminate: true)
return .terminateLater
}
/// store last version before termination
func applicationWillTerminate(_ notification: Notification) {
@ -196,6 +206,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
if isLatest {
UserDefaults.standard[.lastVersion] = thisVersion
}
if self.needsRelaunch {
NSApp.relaunch()
}
}

View File

@ -201,6 +201,16 @@ final class DocumentController: NSDocumentController {
}
override func closeAllDocuments(withDelegate delegate: Any?, didCloseAllSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
let context = DelegateContext(delegate: delegate,
selector: didCloseAllSelector,
contextInfo: contextInfo)
super.closeAllDocuments(withDelegate: self, didCloseAllSelector: #selector(documentController(_:didCloseAll:contextInfo:)), contextInfo: bridgeWrapped(context))
}
/// return availability of actions
override func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
@ -256,6 +266,14 @@ final class DocumentController: NSDocumentController {
// MARK: Private Methods
private struct DelegateContext {
var delegate: Any?
var selector: Selector?
var contextInfo: UnsafeMutableRawPointer?
}
/// transient document to be replaced or nil
private var transientDocumentToReplace: Document? {
@ -316,6 +334,30 @@ final class DocumentController: NSDocumentController {
}
}
/// callback from document after calling `closeAllDocuments(withDelegate:didCloseAllSelector:contextInfo)`.
@objc private func documentController(_ documentController: NSDocumentController, didCloseAll: Bool, contextInfo: UnsafeMutableRawPointer) {
// cancel relaunching
if !didCloseAll {
(NSApp.delegate as? AppDelegate)?.needsRelaunch = false
}
// manually invoke the original delegate method
guard
let context: DelegateContext = bridgeUnwrapped(contextInfo),
let delegate = context.delegate as? NSObject,
let selector = context.selector,
let objcClass = objc_getClass(delegate.className) as? AnyClass,
let method = class_getMethodImplementation(objcClass, selector)
else { return assertionFailure() }
typealias Signature = @convention(c) (AnyObject, Selector, AnyObject, Bool, UnsafeMutableRawPointer?) -> Void
let function = unsafeBitCast(method, to: Signature.self)
function(delegate, selector, self, didCloseAll, context.contextInfo)
}
}

View File

@ -126,7 +126,8 @@ final class GeneralPaneController: NSViewController {
switch returnCode {
case .alertFirstButtonReturn: // = Restart Now
NSApp.relaunch()
(NSApp.delegate as? AppDelegate)?.needsRelaunch = true
NSApp.terminate(self)
case .alertSecondButtonReturn: // = Later
break // do nothing
case .alertThirdButtonReturn: // = Cancel

View File

@ -34,7 +34,6 @@ extension NSApplication {
let command = String(format: "sleep 2; open \"%@\"", escapedPath)
Process.launchedProcess(launchPath: "/bin/sh", arguments: ["-c", command])
self.terminate(nil)
}
}