162 lines
5.7 KiB
Swift
162 lines
5.7 KiB
Swift
import AppKit
|
|
import Darwin
|
|
|
|
@objc final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
static weak var shared: AppDelegate?
|
|
|
|
var windowController: PreviewWindowController?
|
|
var pendingExitCode: AppExitCode = .success
|
|
private var invocation: Invocation = .standalone(files: [])
|
|
private var didFinishLaunch = false
|
|
|
|
enum Invocation {
|
|
case job(URL)
|
|
case standalone(files: [URL])
|
|
}
|
|
|
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
|
AppDelegate.shared = self
|
|
NSApp.setActivationPolicy(.regular)
|
|
buildMenu()
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
|
|
let wc = PreviewWindowController(standalone: true)
|
|
windowController = wc
|
|
wc.showWindow(nil)
|
|
NotificationCenter.default.addObserver(self, selector: #selector(openFromDrag(_:)), name: .targetPrintOpenURLs, object: nil)
|
|
|
|
switch invocation {
|
|
case .job(let url):
|
|
do {
|
|
try wc.loadJob(from: url)
|
|
// SPEC §4.5: present NSPrintPanel immediately, no extra click.
|
|
wc.presentPrint()
|
|
} catch {
|
|
PreviewWindowController.presentError(error, on: wc.window)
|
|
pendingExitCode = (error as? AppError)?.exitCode ?? .invalidJob
|
|
// Show the alert, then terminate with the documented exit code.
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
|
|
NSApp.terminate(self)
|
|
}
|
|
}
|
|
case .standalone(let files):
|
|
if !files.isEmpty {
|
|
wc.openURLs(files)
|
|
}
|
|
}
|
|
didFinishLaunch = true
|
|
}
|
|
|
|
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true }
|
|
|
|
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
|
// Honour SPEC §4 exit codes after the alert / print panel has dismissed.
|
|
DispatchQueue.main.async {
|
|
Darwin.exit(self.pendingExitCode.rawValue)
|
|
}
|
|
return .terminateNow
|
|
}
|
|
|
|
func application(_ sender: NSApplication, openFile filename: String) -> Bool {
|
|
openPaths([filename])
|
|
return true
|
|
}
|
|
|
|
func application(_ sender: NSApplication, openFiles filenames: [String]) {
|
|
openPaths(filenames)
|
|
sender.reply(toOpenOrPrint: .success)
|
|
}
|
|
|
|
private func openPaths(_ filenames: [String]) {
|
|
let urls = filenames.map { URL(fileURLWithPath: $0) }
|
|
if didFinishLaunch {
|
|
windowController?.openURLs(urls)
|
|
} else {
|
|
// Launched by document open / file association before didFinishLaunching.
|
|
if let job = urls.first(where: { ["targetjob", "json"].contains($0.pathExtension.lowercased()) }) {
|
|
invocation = .job(job)
|
|
} else {
|
|
invocation = .standalone(files: urls)
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc private func openFromDrag(_ note: Notification) {
|
|
if let urls = note.object as? [URL] {
|
|
windowController?.openURLs(urls)
|
|
}
|
|
}
|
|
|
|
func consumeArguments(_ args: [String]) {
|
|
var verbose = false
|
|
var job: URL?
|
|
var files: [URL] = []
|
|
var i = 1
|
|
while i < args.count {
|
|
let a = args[i]
|
|
if a == "--verbose" {
|
|
verbose = true
|
|
} else if a == "--job" {
|
|
i += 1
|
|
guard i < args.count else { break }
|
|
job = URL(fileURLWithPath: args[i])
|
|
} else if a.hasPrefix("--job=") {
|
|
job = URL(fileURLWithPath: String(a.dropFirst("--job=".count)))
|
|
} else if a.hasPrefix("-") {
|
|
TPLog.error("Unknown argument \(a)")
|
|
} else {
|
|
files.append(URL(fileURLWithPath: a))
|
|
}
|
|
i += 1
|
|
}
|
|
TPLog.setVerbose(verbose)
|
|
if let job = job {
|
|
invocation = .job(job)
|
|
} else {
|
|
invocation = .standalone(files: files)
|
|
}
|
|
}
|
|
|
|
// MARK: - Menu (File → Open / Print)
|
|
|
|
private func buildMenu() {
|
|
let main = NSMenu()
|
|
let appItem = NSMenuItem()
|
|
let appMenu = NSMenu()
|
|
appMenu.addItem(withTitle: "About TargetPrint", action: #selector(showAbout), keyEquivalent: "")
|
|
appMenu.addItem(NSMenuItem.separator())
|
|
appMenu.addItem(withTitle: "Quit TargetPrint", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")
|
|
appItem.submenu = appMenu
|
|
main.addItem(appItem)
|
|
|
|
let fileItem = NSMenuItem()
|
|
let fileMenu = NSMenu(title: "File")
|
|
fileMenu.addItem(withTitle: "Open…", action: #selector(openDocument(_:)), keyEquivalent: "o")
|
|
fileMenu.addItem(NSMenuItem.separator())
|
|
fileMenu.addItem(withTitle: "Print…", action: #selector(printDocument(_:)), keyEquivalent: "p")
|
|
fileMenu.addItem(withTitle: "Close", action: #selector(NSWindow.performClose(_:)), keyEquivalent: "w")
|
|
fileItem.submenu = fileMenu
|
|
main.addItem(fileItem)
|
|
|
|
NSApp.mainMenu = main
|
|
}
|
|
|
|
@objc func openDocument(_ sender: Any?) {
|
|
PreviewWindowController.presentOpenPanel { [weak self] urls in
|
|
self?.windowController?.openURLs(urls)
|
|
}
|
|
}
|
|
|
|
@objc func printDocument(_ sender: Any?) {
|
|
windowController?.presentPrint()
|
|
}
|
|
|
|
@objc func showAbout(_ sender: Any?) {
|
|
NSApp.orderFrontStandardAboutPanel(options: [
|
|
.applicationName: "TargetPrint",
|
|
.applicationVersion: "0.0.1",
|
|
.credits: NSAttributedString(string: "ICCery Colour Print Utility\nPrints profiling targets with unmanaged colour and 1:1 geometry."),
|
|
])
|
|
}
|
|
}
|