Skip to content

Commit

Permalink
Include fix for Open Recent menu in release builds, iina#4688 (iina#4792
Browse files Browse the repository at this point in the history
)

This commit will:
- Add clearRecentDocuments and noteNewRecentDocumentURL methods to
  AppDelegate
- Change PrefGeneralViewController and PrefUtilsViewController to call
  AppDelegate.clearRecentDocuments instead of the NSDocumentController
  method
- Change AppDelegate.openFile and PlayerCore.fileLoaded to call
  AppDelegate.noteNewRecentDocumentURL instead of the
  NSDocumentController method
- Change saveRecentDocuments to not include a check for the
  recordRecentFiles preference
- Remove the compiler directives that only included this code in debug
  builds
- Switch to forced downcast operator instead of the conditional operator
  when casting to AppDelegate

These changes enhance the workaround for macOS Sonoma clearing the open
recent menu to cover the case where the user clears the list and also
removes conditionalization that restricted this workaround to debug
builds.

Co-authored-by: Saagar Jha <[email protected]>
  • Loading branch information
low-batt and saagarjha authored Jan 29, 2024
1 parent dc81e9e commit dbc76d9
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 31 deletions.
58 changes: 39 additions & 19 deletions iina/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {

Logger.log("App will launch")

#if DEBUG
// Workaround macOS Sonoma clearing the recent documents list when the IINA code is not signed
// with IINA's certificate as is the case for developer and nightly builds.
restoreRecentDocuments()
#endif

// register for url event
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleURLEvent(event:withReplyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
Expand Down Expand Up @@ -832,11 +832,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {
if panel.runModal() == .OK {
if Preference.bool(for: .recordRecentFiles) {
for url in panel.urls {
NSDocumentController.shared.noteNewRecentDocumentURL(url)
noteNewRecentDocumentURL(url)
}
#if DEBUG
saveRecentDocuments()
#endif
}
let isAlternative = (sender as? NSMenuItem)?.tag == AlternativeMenuItemTag
let playerCore = PlayerCore.activeOrNewForMenuAction(isAlternative: isAlternative)
Expand Down Expand Up @@ -959,16 +956,39 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {

// MARK: - Recent Documents

#if DEBUG
/// Empties the recent documents list for the application.
///
/// This is part of a workaround for macOS Sonoma clearing the list of recent documents. See the method
/// `restoreRecentDocuments` and the issue [#4688](https://github.com/iina/iina/issues/4688) for more
/// information..
/// - Parameter sender: The object that initiated the clearing of the recent documents.
@IBAction
func clearRecentDocuments(_ sender: Any?) {
NSDocumentController.shared.clearRecentDocuments(sender)
saveRecentDocuments()
}

/// Adds or replaces an Open Recent menu item corresponding to the data located by the URL.
///
/// This is part of a workaround for macOS Sonoma clearing the list of recent documents. See the method
/// `restoreRecentDocuments` and the issue [#4688](https://github.com/iina/iina/issues/4688) for more
/// information..
/// - Parameter url: The URL to evaluate.
func noteNewRecentDocumentURL(_ url: URL) {
NSDocumentController.shared.noteNewRecentDocumentURL(url)
saveRecentDocuments()
}

/// Restore the list of recently opened files.
///
/// For macOS Sonoma `sharedfilelistd` was changed to tie the list of recent documents to the app based on its certificate.
/// if `sharedfilelistd` determines the list is being accessed by a different app then it clears the list. See issue
/// [#4688](https://github.com/iina/iina/issues/4688) for details.
///
/// This new behavior does not cause a problem when the code is signed with IINA's certificate. However developer builds use an
/// ad hoc certificate. This causes the list of recently opened files to be cleared each time a developer runs a new build. As a
/// workaround a copy of the list of recent documents is saved in IINA's preference file to preserve the list across builds.
/// This new behavior does not cause a problem when the code is signed with IINA's certificate. However developer and nightly
/// builds use an ad hoc certificate. This causes the list of recently opened files to be cleared each time a different unsigned IINA build
/// is run. As a workaround a copy of the list of recent documents is saved in IINA's preference file to preserve the list and allow it to
/// be restored when `sharedfilelistd` clears its list.
///
/// If the following is true:
/// - Running under macOS Sonoma and above
Expand All @@ -978,10 +998,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {
///
/// Then this method assumes that the macOS daemon `sharedfilelistd` cleared the list and it populates the list of recent
/// document URLs with the list stored in IINA's settings.
/// - Note: This is not a perfect workaround. For example, running a version of IINA signed with IINA's certificate after running a
/// developer build will result in an empty list of recent files. This workaround is only intended to provide a better
/// experience for developers. Improving the workaround would require including it in the released version of IINA.
/// As the released version is working fine, we do not want to do that.
private func restoreRecentDocuments() {
guard #available(macOS 14, *), Preference.bool(for: .recordRecentFiles),
NSDocumentController.shared.recentDocumentURLs.isEmpty,
Expand Down Expand Up @@ -1012,10 +1028,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {
/// Save the list of recent documents in [NSDocumentController.shared.recentDocumentURLs](https://developer.apple.com/documentation/appkit/nsdocumentcontroller/1514976-recentdocumenturls)
/// to `recentDocuments` in the IINA settings property file.
///
/// This is a workaround for developers. See the method `restoreRecentDocuments` and the issue
/// [#4688](https://github.com/iina/iina/issues/4688) for more information..
/// This is part of a workaround for macOS Sonoma clearing the list of recent documents. See the method
/// `restoreRecentDocuments` and the issue [#4688](https://github.com/iina/iina/issues/4688) for more
/// information..
func saveRecentDocuments() {
guard #available(macOS 14, *), Preference.bool(for: .recordRecentFiles) else { return }
guard #available(macOS 14, *) else { return }
var recentDocuments: [Any] = []
for document in NSDocumentController.shared.recentDocumentURLs {
guard let bookmark = try? document.bookmarkData() else {
Expand All @@ -1026,9 +1043,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {
recentDocuments.append(bookmark)
}
Preference.set(recentDocuments, for: .recentDocuments)
Logger.log("Saved list of recent documents")
if recentDocuments.isEmpty {
Logger.log("Cleared list of recent documents")
} else {
Logger.log("Saved list of recent documents")
}
}
#endif
}


Expand Down
5 changes: 1 addition & 4 deletions iina/PlayerCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1607,10 +1607,7 @@ class PlayerCore: NSObject {
HistoryController.shared.add(url, duration: duration.second)
}
if Preference.bool(for: .recordRecentFiles) && Preference.bool(for: .trackAllFilesInRecentOpenMenu) {
NSDocumentController.shared.noteNewRecentDocumentURL(url)
#if DEBUG
DispatchQueue.main.async { (NSApp.delegate as? AppDelegate)?.saveRecentDocuments() }
#endif
DispatchQueue.main.sync { (NSApp.delegate as! AppDelegate).noteNewRecentDocumentURL(url) }
}

}
Expand Down
5 changes: 1 addition & 4 deletions iina/PrefGeneralViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ class PrefGeneralViewController: PreferenceViewController, PreferenceWindowEmbed

@IBAction func rememberRecentChanged(_ sender: NSButton) {
if sender.state == .off {
NSDocumentController.shared.clearRecentDocuments(self)
#if DEBUG
(NSApp.delegate as? AppDelegate)?.saveRecentDocuments()
#endif
(NSApp.delegate as! AppDelegate).clearRecentDocuments(self)
}
}
}
Expand Down
5 changes: 1 addition & 4 deletions iina/PrefUtilsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,7 @@ class PrefUtilsViewController: PreferenceViewController, PreferenceWindowEmbedda
Utility.quickAskPanel("clear_history", sheetWindow: view.window) { respond in
guard respond == .alertFirstButtonReturn else { return }
try? FileManager.default.removeItem(atPath: Utility.playbackHistoryURL.path)
NSDocumentController.shared.clearRecentDocuments(self)
#if DEBUG
(NSApp.delegate as? AppDelegate)?.saveRecentDocuments()
#endif
(NSApp.delegate as! AppDelegate).clearRecentDocuments(self)
Preference.set(nil, for: .iinaLastPlayedFilePath)
self.playHistoryClearedLabel.isHidden = false
}
Expand Down

0 comments on commit dbc76d9

Please sign in to comment.