// StatusMenuController.swift // GreenshotMac // // The menu bar item, equivalent to Greenshot's tray icon and context menu. import AppKit @MainActor final class StatusMenuController: NSObject, NSMenuDelegate { private let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) private var preferencesController: PreferencesWindowController? override init() { super.init() if let button = statusItem.button { button.image = NSImage(systemSymbolName: "camera.viewfinder", accessibilityDescription: "GreenshotMac") button.image?.isTemplate = true button.toolTip = "GreenshotMac" } statusItem.menu = buildMenu() } private func buildMenu() -> NSMenu { let menu = NSMenu() menu.delegate = self menu.addItem(item(title: "Capture region", action: #selector(captureRegion), hotkey: HotkeyBindings.shared.spec(for: .region))) menu.addItem(item(title: "Capture window", action: #selector(captureWindow), hotkey: HotkeyBindings.shared.spec(for: .window))) menu.addItem(item(title: "Capture full screen", action: #selector(captureFullscreen), hotkey: HotkeyBindings.shared.spec(for: .fullscreen))) menu.addItem(item(title: "Capture last region", action: #selector(captureLastRegion), hotkey: HotkeyBindings.shared.spec(for: .lastRegion))) menu.addItem(.separator()) menu.addItem(item(title: "Open image from file…", action: #selector(openImageFile), hotkey: nil)) menu.addItem(item(title: "Open last screenshot in Finder", action: #selector(revealLast), hotkey: nil)) menu.addItem(.separator()) let destinationItem = NSMenuItem(title: "Default destination", action: nil, keyEquivalent: "") destinationItem.submenu = destinationMenu() menu.addItem(destinationItem) menu.addItem(item(title: "Preferences…", action: #selector(showPreferences), hotkey: nil)) menu.addItem(.separator()) menu.addItem(item(title: "About GreenshotMac", action: #selector(showAbout), hotkey: nil)) menu.addItem(item(title: "Quit GreenshotMac", action: #selector(quit), hotkey: nil)) return menu } private func destinationMenu() -> NSMenu { let menu = NSMenu() for destination in DestinationID.allCases { let menuItem = NSMenuItem(title: destination.title, action: #selector(selectDestination(_:)), keyEquivalent: "") menuItem.target = self menuItem.representedObject = destination.rawValue menuItem.state = Configuration.shared.defaultDestination == destination ? .on : .off menu.addItem(menuItem) } return menu } private func item(title: String, action: Selector, hotkey: HotkeySpec?) -> NSMenuItem { let menuItem = NSMenuItem(title: title, action: action, keyEquivalent: "") menuItem.target = self if let hotkey, !hotkey.isEmpty { menuItem.toolTip = HotkeyManager.description(of: hotkey) } return menuItem } func menuWillOpen(_ menu: NSMenu) { for menuItem in menu.items where menuItem.title == "Default destination" { menuItem.submenu = destinationMenu() } if let revealItem = menu.items.first(where: { $0.title == "Open last screenshot in Finder" }) { revealItem.isEnabled = Notifier.mostRecentSavedURL != nil } } // MARK: - Actions @objc private func captureRegion() { CaptureCoordinator.shared.captureRegion() } @objc private func captureWindow() { CaptureCoordinator.shared.captureWindow() } @objc private func captureFullscreen() { CaptureCoordinator.shared.captureFullscreen() } @objc private func captureLastRegion() { CaptureCoordinator.shared.captureLastRegion() } @objc private func openImageFile() { CaptureCoordinator.shared.openImageFile() } @objc private func revealLast() { Notifier.revealMostRecent() } @objc private func selectDestination(_ sender: NSMenuItem) { guard let raw = sender.representedObject as? String, let destination = DestinationID(rawValue: raw) else { return } Configuration.shared.defaultDestination = destination } @objc private func showPreferences() { if preferencesController == nil { preferencesController = PreferencesWindowController() } preferencesController?.showWindow(nil) preferencesController?.window?.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) } @objc private func showAbout() { NSApp.activate(ignoringOtherApps: true) NSApp.orderFrontStandardAboutPanel(options: [ .applicationName: "GreenshotMac", .credits: NSAttributedString( string: "A native macOS screenshot tool modelled on Greenshot for Windows.\n" + "Licensed under the GNU General Public License v3.", attributes: [.font: NSFont.systemFont(ofSize: 11)]) ]) } @objc private func quit() { NSApp.terminate(nil) } }