mirror of
https://github.com/mpv-player/mpv
synced 2025-03-11 08:37:59 +00:00
mac/menu: rewrite menu bar in swift
This commit is contained in:
parent
bbbd6e272c
commit
fe35baa88e
12
meson.build
12
meson.build
@ -396,8 +396,7 @@ if features['cocoa']
|
||||
'osdep/path-mac.m',
|
||||
'osdep/utils-mac.c',
|
||||
'osdep/mac/application.m',
|
||||
'osdep/mac/events.m',
|
||||
'osdep/mac/menubar.m')
|
||||
'osdep/mac/events.m')
|
||||
endif
|
||||
|
||||
if posix
|
||||
@ -1516,6 +1515,7 @@ if features['cocoa'] and features['swift']
|
||||
swift_sources += files('osdep/mac/libmpv_helper.swift',
|
||||
'osdep/mac/log_helper.swift',
|
||||
'osdep/mac/mpv_helper.swift',
|
||||
'osdep/mac/menu_bar.swift',
|
||||
'osdep/mac/precise_timer.swift',
|
||||
'osdep/mac/swift_compat.swift',
|
||||
'osdep/mac/swift_extensions.swift',
|
||||
@ -1549,10 +1549,6 @@ if features['macos-media-player']
|
||||
swift_sources += files('osdep/mac/remote_command_center.swift')
|
||||
endif
|
||||
|
||||
if features['swift'] and swift_sources.length() > 0
|
||||
subdir('osdep/mac')
|
||||
endif
|
||||
|
||||
macos_touchbar = get_option('macos-touchbar').require(
|
||||
features['cocoa'] and cc.has_header('AppKit/NSTouchBar.h'),
|
||||
error_message: 'Either cocoa could not be found or AppKit/NSTouchBar.h could not be found!',
|
||||
@ -1562,6 +1558,10 @@ if features['macos-touchbar']
|
||||
sources += files('osdep/mac/touchbar.m')
|
||||
endif
|
||||
|
||||
if features['swift'] and swift_sources.length() > 0
|
||||
subdir('osdep/mac')
|
||||
endif
|
||||
|
||||
|
||||
# manpages
|
||||
manpage = 'DOCS/man/mpv.rst'
|
||||
|
@ -18,7 +18,6 @@
|
||||
#ifndef MAC_APPLICATION
|
||||
#define MAC_APPLICATION
|
||||
|
||||
#include "osdep/mac/menubar.h"
|
||||
#include "options/m_option.h"
|
||||
|
||||
enum {
|
||||
|
@ -17,9 +17,9 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "osdep/mac/application.h"
|
||||
#import "osdep/mac/menubar_objc.h"
|
||||
|
||||
@class CocoaCB;
|
||||
@class MenuBar;
|
||||
struct mpv_event;
|
||||
struct mpv_handle;
|
||||
|
||||
|
464
osdep/mac/menu_bar.swift
Normal file
464
osdep/mac/menu_bar.swift
Normal file
@ -0,0 +1,464 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
extension MenuBar {
|
||||
enum MenuKey {
|
||||
case normalSize
|
||||
case halfSize
|
||||
case doubleSize
|
||||
case minimize
|
||||
case zoom
|
||||
}
|
||||
|
||||
struct Config {
|
||||
let name: String
|
||||
let key: String
|
||||
let modifiers: NSEvent.ModifierFlags
|
||||
let action: Selector?
|
||||
let target: AnyObject?
|
||||
let command: String
|
||||
let url: String?
|
||||
let file: String?
|
||||
let alertTitle1: String?
|
||||
let alertText1: String?
|
||||
let alertTitle2: String?
|
||||
let alertText2: String?
|
||||
let alertTitle3: String?
|
||||
let alertText3: String?
|
||||
let commandSpecial: MenuKey?
|
||||
var menuItem: NSMenuItem?
|
||||
var configs: [Config]?
|
||||
|
||||
init(
|
||||
name: String = "",
|
||||
key: String = "",
|
||||
modifiers: NSEvent.ModifierFlags = .command,
|
||||
action: Selector? = nil,
|
||||
target: AnyObject? = nil,
|
||||
command: String = "",
|
||||
url: String? = nil,
|
||||
file: String? = nil,
|
||||
alertTitle1: String? = nil,
|
||||
alertText1: String? = nil,
|
||||
alertTitle2: String? = nil,
|
||||
alertText2: String? = nil,
|
||||
alertTitle3: String? = nil,
|
||||
alertText3: String? = nil,
|
||||
commandSpecial: MenuKey? = nil,
|
||||
menuItem: NSMenuItem? = nil,
|
||||
configs: [Config]? = nil
|
||||
) {
|
||||
self.name = name
|
||||
self.key = key
|
||||
self.modifiers = modifiers
|
||||
self.action = action
|
||||
self.target = target
|
||||
self.command = command
|
||||
self.url = url
|
||||
self.file = file
|
||||
self.alertTitle1 = alertTitle1
|
||||
self.alertText1 = alertText1
|
||||
self.alertTitle2 = alertTitle2
|
||||
self.alertText2 = alertText2
|
||||
self.alertTitle3 = alertTitle3
|
||||
self.alertText3 = alertText3
|
||||
self.commandSpecial = commandSpecial
|
||||
self.menuItem = menuItem
|
||||
self.configs = configs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MenuBar: NSObject {
|
||||
var menuConfigs: [Config] = []
|
||||
let appIcon: NSImage
|
||||
|
||||
@objc override init() {
|
||||
UserDefaults.standard.set(false, forKey: "NSFullScreenMenuItemEverywhere")
|
||||
UserDefaults.standard.set(true, forKey: "NSDisabledDictationMenuItem")
|
||||
UserDefaults.standard.set(true, forKey: "NSDisabledCharacterPaletteMenuItem")
|
||||
NSWindow.allowsAutomaticWindowTabbing = false
|
||||
appIcon = (NSApp as? Application)?.getMPVIcon() ?? NSImage(size: NSSize(width: 1, height: 1))
|
||||
|
||||
super.init()
|
||||
|
||||
let appMenuConfigs = [
|
||||
Config(name: "About mpv", action: #selector(about), target: self),
|
||||
Config(name: "separator"),
|
||||
Config(
|
||||
name: "Preferences…",
|
||||
key: ",",
|
||||
action: #selector(preferences(_:)),
|
||||
target: self,
|
||||
file: "mpv.conf",
|
||||
alertTitle1: "No Application found to open your config file.",
|
||||
alertText1: "Please open the mpv.conf file with your preferred text editor in the now open folder to edit your config.",
|
||||
alertTitle2: "No config file found.",
|
||||
alertText2: "Please create a mpv.conf file with your preferred text editor in the now open folder.",
|
||||
alertTitle3: "No config path or file found.",
|
||||
alertText3: "Please create the following path ~/.config/mpv/ and a mpv.conf file within with your preferred text editor."
|
||||
),
|
||||
Config(
|
||||
name: "Keyboard Shortcuts Config…",
|
||||
action: #selector(preferences(_:)),
|
||||
target: self,
|
||||
file: "input.conf",
|
||||
alertTitle1: "No Application found to open your config file.",
|
||||
alertText1: "Please open the input.conf file with your preferred text editor in the now open folder to edit your config.",
|
||||
alertTitle2: "No config file found.",
|
||||
alertText2: "Please create a input.conf file with your preferred text editor in the now open folder.",
|
||||
alertTitle3: "No config path or file found.",
|
||||
alertText3: "Please create the following path ~/.config/mpv/ and a input.conf file within with your preferred text editor."
|
||||
),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Services"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Hide mpv", key: "h", action: #selector(NSApp.hide(_:))),
|
||||
Config(name: "Hide Others", key: "h", modifiers: [.command, .option], action: #selector(NSApp.hideOtherApplications(_:))),
|
||||
Config(name: "Show All", action: #selector(NSApp.unhideAllApplications(_:))),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Quit and Remember Position", action: #selector(quit(_:)), target: self, command: "quit-watch-later"),
|
||||
Config(name: "Quit mpv", key: "q", action: #selector(quit(_:)), target: self, command: "quit"),
|
||||
]
|
||||
|
||||
let fileMenuConfigs = [
|
||||
Config(name: "Open File…", key: "o", action: #selector(openFile), target: self),
|
||||
Config(name: "Open URL…", key: "O", action: #selector(openUrl), target: self),
|
||||
Config(name: "Open Playlist…", action: #selector(openPlaylist), target: self),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Close", key: "w", action: #selector(NSWindow.performClose(_:))),
|
||||
Config(name: "Save Screenshot", action: #selector(command(_:)), target: self, command: "async screenshot"),
|
||||
]
|
||||
|
||||
let editMenuConfigs = [
|
||||
Config(name: "Undo", key: "z", action: Selector(("undo:"))),
|
||||
Config(name: "Redo", key: "Z", action: Selector(("redo:"))),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Cut", key: "x", action: #selector(NSText.cut(_:))),
|
||||
Config(name: "Copy", key: "c", action: #selector(NSText.copy(_:))),
|
||||
Config(name: "Paste", key: "v", action: #selector(NSText.paste(_:))),
|
||||
Config(name: "Select All", key: "a", action: #selector(NSResponder.selectAll(_:))),
|
||||
]
|
||||
|
||||
var viewMenuConfigs = [
|
||||
Config(name: "Toggle Fullscreen", action: #selector(command(_:)), target: self, command: "cycle fullscreen"),
|
||||
Config(name: "Toggle Float on Top", action: #selector(command(_:)), target: self, command: "cycle ontop"),
|
||||
Config(
|
||||
name: "Toggle Visibility on All Workspaces",
|
||||
action: #selector(command(_:)),
|
||||
target: self,
|
||||
command: "cycle on-all-workspaces"
|
||||
),
|
||||
]
|
||||
#if HAVE_MACOS_TOUCHBAR
|
||||
viewMenuConfigs += [
|
||||
Config(name: "separator"),
|
||||
Config(name: "Customize Touch Bar…", action: #selector(NSApp.toggleTouchBarCustomizationPalette(_:))),
|
||||
]
|
||||
#endif
|
||||
|
||||
let videoMenuConfigs = [
|
||||
Config(name: "Zoom Out", action: #selector(command(_:)), target: self, command: "add panscan -0.1"),
|
||||
Config(name: "Zoom In", action: #selector(command(_:)), target: self, command: "add panscan 0.1"),
|
||||
Config(name: "Reset Zoom", action: #selector(command(_:)), target: self, command: "set panscan 0"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Aspect Ratio 4:3", action: #selector(command(_:)), target: self, command: "set video-aspect-override \"4:3\""),
|
||||
Config(name: "Aspect Ratio 16:9", action: #selector(command(_:)), target: self, command: "set video-aspect-override \"16:9\""),
|
||||
Config(name: "Aspect Ratio 1.85:1", action: #selector(command(_:)), target: self, command: "set video-aspect-override \"1.85:1\""),
|
||||
Config(name: "Aspect Ratio 2.35:1", action: #selector(command(_:)), target: self, command: "set video-aspect-override \"2.35:1\""),
|
||||
Config(name: "Reset Aspect Ratio", action: #selector(command(_:)), target: self, command: "set video-aspect-override \"-1\""),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Rotate Left", action: #selector(command(_:)), target: self, command: "cycle-values video-rotate 0 270 180 90"),
|
||||
Config(name: "Rotate Right", action: #selector(command(_:)), target: self, command: "cycle-values video-rotate 90 180 270 0"),
|
||||
Config(name: "Reset Rotation", action: #selector(command(_:)), target: self, command: "set video-rotate 0"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Half Size", key: "0", commandSpecial: .halfSize),
|
||||
Config(name: "Normal Size", key: "1", commandSpecial: .normalSize),
|
||||
Config(name: "Double Size", key: "2", commandSpecial: .doubleSize),
|
||||
]
|
||||
|
||||
let audioMenuConfigs = [
|
||||
Config(name: "Next Audio Track", action: #selector(command(_:)), target: self, command: "cycle audio"),
|
||||
Config(name: "Previous Audio Track", action: #selector(command(_:)), target: self, command: "cycle audio down"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Toggle Mute", action: #selector(command(_:)), target: self, command: "cycle mute"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Play Audio Later", action: #selector(command(_:)), target: self, command: "add audio-delay 0.1"),
|
||||
Config(name: "Play Audio Earlier", action: #selector(command(_:)), target: self, command: "add audio-delay -0.1"),
|
||||
Config(name: "Reset Audio Delay", action: #selector(command(_:)), target: self, command: "set audio-delay 0.0"),
|
||||
]
|
||||
|
||||
let subtitleMenuConfigs = [
|
||||
Config(name: "Next Subtitle Track", action: #selector(command(_:)), target: self, command: "cycle sub"),
|
||||
Config(name: "Previous Subtitle Track", action: #selector(command(_:)), target: self, command: "cycle sub down"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Toggle Force Style", action: #selector(command(_:)), target: self, command: "cycle-values sub-ass-override \"force\" \"no\""),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Display Subtitles Later", action: #selector(command(_:)), target: self, command: "add sub-delay 0.1"),
|
||||
Config(name: "Display Subtitles Earlier", action: #selector(command(_:)), target: self, command: "add sub-delay -0.1"),
|
||||
Config(name: "Reset Subtitle Delay", action: #selector(command(_:)), target: self, command: "set sub-delay 0.0"),
|
||||
]
|
||||
|
||||
let playbackMenuConfigs = [
|
||||
Config(name: "Toggle Pause", action: #selector(command(_:)), target: self, command: "cycle pause"),
|
||||
Config(name: "Increase Speed", action: #selector(command(_:)), target: self, command: "add speed 0.1"),
|
||||
Config(name: "Decrease Speed", action: #selector(command(_:)), target: self, command: "add speed -0.1"),
|
||||
Config(name: "Reset Speed", action: #selector(command(_:)), target: self, command: "set speed 1.0"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Show Playlist", action: #selector(command(_:)), target: self, command: "script-message osc-playlist"),
|
||||
Config(name: "Show Chapters", action: #selector(command(_:)), target: self, command: "script-message osc-chapterlist"),
|
||||
Config(name: "Show Tracks", action: #selector(command(_:)), target: self, command: "script-message osc-tracklist"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Next File", action: #selector(command(_:)), target: self, command: "playlist-next"),
|
||||
Config(name: "Previous File", action: #selector(command(_:)), target: self, command: "playlist-prev"),
|
||||
Config(name: "Toggle Loop File", action: #selector(command(_:)), target: self, command: "cycle-values loop-file \"inf\" \"no\""),
|
||||
Config(name: "Toggle Loop Playlist", action: #selector(command(_:)), target: self, command: "cycle-values loop-playlist \"inf\" \"no\""),
|
||||
Config(name: "Shuffle", action: #selector(command(_:)), target: self, command: "playlist-shuffle"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Next Chapter", action: #selector(command(_:)), target: self, command: "add chapter 1"),
|
||||
Config(name: "Previous Chapter", action: #selector(command(_:)), target: self, command: "add chapter -1"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Step Forward", action: #selector(command(_:)), target: self, command: "frame-step"),
|
||||
Config(name: "Step Backward", action: #selector(command(_:)), target: self, command: "frame-back-step"),
|
||||
]
|
||||
|
||||
let windowMenuConfigs = [
|
||||
Config(name: "Minimize", key: "m", commandSpecial: .minimize),
|
||||
Config(name: "Zoom", key: "z", commandSpecial: .zoom),
|
||||
]
|
||||
|
||||
let helpMenuConfigs = [
|
||||
Config(name: "mpv Website…", action: #selector(url(_:)), target: self, url: "https://mpv.io"),
|
||||
Config(name: "mpv on GitHub…", action: #selector(url(_:)), target: self, url: "https://github.com/mpv-player/mpv"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Online Manual…", action: #selector(url(_:)), target: self, url: "https://mpv.io/manual/master/"),
|
||||
Config(name: "Online Wiki…", action: #selector(url(_:)), target: self, url: "https://github.com/mpv-player/mpv/wiki"),
|
||||
Config(name: "Release Notes…", action: #selector(url(_:)), target: self, url: "https://github.com/mpv-player/mpv/blob/master/RELEASE_NOTES"),
|
||||
Config(name: "Keyboard Shortcuts…", action: #selector(url(_:)), target: self, url: "https://github.com/mpv-player/mpv/blob/master/etc/input.conf"),
|
||||
Config(name: "separator"),
|
||||
Config(name: "Report Issue…", action: #selector(url(_:)), target: self, url: "https://github.com/mpv-player/mpv/issues/new/choose"),
|
||||
Config(
|
||||
name: "Show log File…",
|
||||
action: #selector(showFile(_:)),
|
||||
target: self,
|
||||
file: NSHomeDirectory() + "/Library/Logs/mpv.log",
|
||||
alertTitle1: "No log File found.",
|
||||
alertText1: "You deactivated logging for the Bundle."
|
||||
),
|
||||
]
|
||||
|
||||
menuConfigs = [
|
||||
Config(name: "Apple", configs: appMenuConfigs),
|
||||
Config(name: "File", configs: fileMenuConfigs),
|
||||
Config(name: "Edit", configs: editMenuConfigs),
|
||||
Config(name: "View", configs: viewMenuConfigs),
|
||||
Config(name: "Video", configs: videoMenuConfigs),
|
||||
Config(name: "Audio", configs: audioMenuConfigs),
|
||||
Config(name: "Subtitle", configs: subtitleMenuConfigs),
|
||||
Config(name: "Playback", configs: playbackMenuConfigs),
|
||||
Config(name: "Window", configs: windowMenuConfigs),
|
||||
Config(name: "Help", configs: helpMenuConfigs),
|
||||
]
|
||||
|
||||
NSApp.mainMenu = generateMainMenu()
|
||||
}
|
||||
|
||||
func generateMainMenu() -> NSMenu {
|
||||
let mainMenu = NSMenu(title: "MainMenu")
|
||||
NSApp.servicesMenu = NSMenu()
|
||||
|
||||
for (menuConfigIndex, menuConfig) in menuConfigs.enumerated() {
|
||||
let menu = NSMenu(title: menuConfig.name)
|
||||
let item = NSMenuItem(title: menuConfig.name, action: nil, keyEquivalent: menuConfig.key)
|
||||
mainMenu.addItem(item)
|
||||
mainMenu.setSubmenu(menu, for: item)
|
||||
menuConfigs[menuConfigIndex].menuItem = item
|
||||
|
||||
for (subConfigIndex, subConfig) in (menuConfig.configs ?? []).enumerated() {
|
||||
#if HAVE_MACOS_TOUCHBAR
|
||||
if subConfig.action == "toggleTouchBarCustomizationPalette:" {
|
||||
continue
|
||||
}
|
||||
#endif
|
||||
|
||||
if subConfig.name == "Show log File…" && ProcessInfo.processInfo.environment["MPVBUNDLE"] != "true" {
|
||||
continue
|
||||
}
|
||||
|
||||
if subConfig.name == "separator" {
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
} else {
|
||||
let subItem = NSMenuItem(title: subConfig.name, action: subConfig.action, keyEquivalent: subConfig.key)
|
||||
subItem.target = subConfig.target
|
||||
subItem.keyEquivalentModifierMask = subConfig.modifiers
|
||||
menu.addItem(subItem)
|
||||
menuConfigs[menuConfigIndex].configs?[subConfigIndex].menuItem = subItem
|
||||
|
||||
if subConfig.name == "Services" {
|
||||
subItem.submenu = NSApp.servicesMenu
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mainMenu
|
||||
}
|
||||
|
||||
@objc func about() {
|
||||
NSApp.orderFrontStandardAboutPanel(options: [
|
||||
.applicationName: "mpv",
|
||||
.applicationIcon: appIcon,
|
||||
.applicationVersion: String(cString: swift_mpv_version),
|
||||
.init(rawValue: "Copyright"): String(cString: swift_mpv_copyright),
|
||||
])
|
||||
}
|
||||
|
||||
@objc func preferences(_ menuItem: NSMenuItem) {
|
||||
guard let menuConfig = getConfigFromMenu(menuItem: menuItem) else { return }
|
||||
let configPaths: [String] = [
|
||||
NSHomeDirectory() + "/.mpv/",
|
||||
NSHomeDirectory() + "/.config/mpv/",
|
||||
]
|
||||
|
||||
for path in configPaths {
|
||||
let configFile = path + (menuConfig.file ?? "")
|
||||
|
||||
if FileManager.default.fileExists(atPath: configFile) {
|
||||
if NSWorkspace.shared.openFile(configFile) {
|
||||
return
|
||||
}
|
||||
NSWorkspace.shared.openFile(path)
|
||||
alert(title: menuConfig.alertTitle1 ?? "", text: menuConfig.alertText1 ?? "")
|
||||
return
|
||||
}
|
||||
|
||||
if NSWorkspace.shared.openFile(path) {
|
||||
alert(title: menuConfig.alertTitle2 ?? "", text: menuConfig.alertText2 ?? "")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
alert(title: menuConfig.alertTitle3 ?? "", text: menuConfig.alertText3 ?? "")
|
||||
}
|
||||
|
||||
@objc func quit(_ menuItem: NSMenuItem) {
|
||||
guard let menuConfig = getConfigFromMenu(menuItem: menuItem) else { return }
|
||||
menuConfig.command.withCString {
|
||||
(NSApp as? Application)?.stopMPV(UnsafeMutablePointer<CChar>(mutating: $0))
|
||||
}
|
||||
}
|
||||
|
||||
@objc func openFile() {
|
||||
let panel = NSOpenPanel()
|
||||
panel.allowsMultipleSelection = true
|
||||
panel.canChooseDirectories = true
|
||||
|
||||
if panel.runModal() == .OK {
|
||||
var files: [String] = []
|
||||
for url in panel.urls {
|
||||
files += [url.path]
|
||||
}
|
||||
(NSApp as? Application)?.openFiles(files)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func openPlaylist() {
|
||||
let panel = NSOpenPanel()
|
||||
|
||||
if panel.runModal() == .OK {
|
||||
"loadlist \"\(panel.urls[0].path)\"".withCString {
|
||||
(NSApp as? Application)?.queueCommand(UnsafeMutablePointer<CChar>(mutating: $0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func openUrl() {
|
||||
let alert = NSAlert()
|
||||
alert.messageText = "Open URL"
|
||||
alert.icon = appIcon
|
||||
alert.addButton(withTitle: "Ok")
|
||||
alert.addButton(withTitle: "Cancel")
|
||||
|
||||
let input = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 24))
|
||||
input.placeholderString = "URL"
|
||||
alert.accessoryView = input
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
|
||||
input.becomeFirstResponder()
|
||||
}
|
||||
|
||||
if alert.runModal() == .alertFirstButtonReturn && input.stringValue.count > 0 {
|
||||
(NSApp as? Application)?.openFiles([input.stringValue])
|
||||
}
|
||||
}
|
||||
|
||||
@objc func command(_ menuItem: NSMenuItem) {
|
||||
guard let menuConfig = getConfigFromMenu(menuItem: menuItem) else { return }
|
||||
menuConfig.command.withCString {
|
||||
(NSApp as? Application)?.queueCommand(UnsafeMutablePointer<CChar>(mutating: $0))
|
||||
}
|
||||
}
|
||||
|
||||
@objc func url(_ menuItem: NSMenuItem) {
|
||||
guard let menuConfig = getConfigFromMenu(menuItem: menuItem),
|
||||
let url = URL(string: menuConfig.url ?? "") else { return }
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
|
||||
@objc func showFile(_ menuItem: NSMenuItem) {
|
||||
guard let menuConfig = getConfigFromMenu(menuItem: menuItem) else { return }
|
||||
let url = URL(fileURLWithPath: menuConfig.file ?? "")
|
||||
if FileManager.default.fileExists(atPath: url.path) {
|
||||
NSWorkspace.shared.activateFileViewerSelecting([url])
|
||||
return
|
||||
}
|
||||
|
||||
alert(title: menuConfig.alertTitle1 ?? "", text: menuConfig.alertText1 ?? "")
|
||||
}
|
||||
|
||||
func alert(title: String, text: String) {
|
||||
let alert = NSAlert()
|
||||
alert.messageText = title
|
||||
alert.informativeText = text
|
||||
alert.icon = appIcon
|
||||
alert.addButton(withTitle: "Ok")
|
||||
alert.runModal()
|
||||
}
|
||||
|
||||
func getConfigFromMenu(menuItem: NSMenuItem) -> Config? {
|
||||
for menuConfig in menuConfigs {
|
||||
for subConfig in menuConfig.configs ?? [] {
|
||||
if subConfig.menuItem == menuItem {
|
||||
return subConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func register(_ selector: Selector, key: MenuKey) {
|
||||
for menuConfig in menuConfigs {
|
||||
for subConfig in menuConfig.configs ?? [] {
|
||||
if subConfig.commandSpecial == key {
|
||||
subConfig.menuItem?.action = selector
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAC_MENUBAR
|
||||
#define MAC_MENUBAR
|
||||
|
||||
// Menu Keys identifying menu items
|
||||
typedef enum {
|
||||
MPM_H_SIZE,
|
||||
MPM_N_SIZE,
|
||||
MPM_D_SIZE,
|
||||
MPM_MINIMIZE,
|
||||
MPM_ZOOM,
|
||||
} MPMenuKey;
|
||||
|
||||
#endif /* MAC_MENUBAR */
|
@ -1,853 +0,0 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#import "osdep/mac/menubar_objc.h"
|
||||
#import "osdep/mac/application_objc.h"
|
||||
|
||||
@implementation MenuBar
|
||||
{
|
||||
NSArray *menuTree;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
|
||||
[userDefaults setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
|
||||
[userDefaults setBool:YES forKey:@"NSDisabledDictationMenuItem"];
|
||||
[userDefaults setBool:YES forKey:@"NSDisabledCharacterPaletteMenuItem"];
|
||||
[NSWindow setAllowsAutomaticWindowTabbing: NO];
|
||||
|
||||
menuTree = @[
|
||||
@{
|
||||
@"name": @"Apple",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"About mpv",
|
||||
@"action" : @"about",
|
||||
@"key" : @"",
|
||||
@"target" : self
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Preferences…",
|
||||
@"action" : @"preferences:",
|
||||
@"key" : @",",
|
||||
@"target" : self,
|
||||
@"file" : @"mpv.conf",
|
||||
@"alertTitle1": @"No Application found to open your config file.",
|
||||
@"alertText1" : @"Please open the mpv.conf file with "
|
||||
"your preferred text editor in the now "
|
||||
"open folder to edit your config.",
|
||||
@"alertTitle2": @"No config file found.",
|
||||
@"alertText2" : @"Please create a mpv.conf file with your "
|
||||
"preferred text editor in the now open folder.",
|
||||
@"alertTitle3": @"No config path or file found.",
|
||||
@"alertText3" : @"Please create the following path ~/.config/mpv/ "
|
||||
"and a mpv.conf file within with your preferred "
|
||||
"text editor."
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Keyboard Shortcuts Config…",
|
||||
@"action" : @"preferences:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"file" : @"input.conf",
|
||||
@"alertTitle1": @"No Application found to open your config file.",
|
||||
@"alertText1" : @"Please open the input.conf file with "
|
||||
"your preferred text editor in the now "
|
||||
"open folder to edit your config.",
|
||||
@"alertTitle2": @"No config file found.",
|
||||
@"alertText2" : @"Please create a input.conf file with your "
|
||||
"preferred text editor in the now open folder.",
|
||||
@"alertTitle3": @"No config path or file found.",
|
||||
@"alertText3" : @"Please create the following path ~/.config/mpv/ "
|
||||
"and a input.conf file within with your preferred "
|
||||
"text editor."
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Services",
|
||||
@"key" : @"",
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Hide mpv",
|
||||
@"action" : @"hide:",
|
||||
@"key" : @"h",
|
||||
@"target" : NSApp
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Hide Others",
|
||||
@"action" : @"hideOtherApplications:",
|
||||
@"key" : @"h",
|
||||
@"modifiers" : [NSNumber numberWithUnsignedInteger:
|
||||
NSEventModifierFlagCommand |
|
||||
NSEventModifierFlagOption],
|
||||
@"target" : NSApp
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Show All",
|
||||
@"action" : @"unhideAllApplications:",
|
||||
@"key" : @"",
|
||||
@"target" : NSApp
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Quit and Remember Position",
|
||||
@"action" : @"quit:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"quit-watch-later"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Quit mpv",
|
||||
@"action" : @"quit:",
|
||||
@"key" : @"q",
|
||||
@"target" : self,
|
||||
@"cmd" : @"quit"
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"File",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Open File…",
|
||||
@"action" : @"openFile",
|
||||
@"key" : @"o",
|
||||
@"target" : self
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Open URL…",
|
||||
@"action" : @"openURL",
|
||||
@"key" : @"O",
|
||||
@"target" : self
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Open Playlist…",
|
||||
@"action" : @"openPlaylist",
|
||||
@"key" : @"",
|
||||
@"target" : self
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Close",
|
||||
@"action" : @"performClose:",
|
||||
@"key" : @"w"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Save Screenshot",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"async screenshot"
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Edit",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Undo",
|
||||
@"action" : @"undo:",
|
||||
@"key" : @"z"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Redo",
|
||||
@"action" : @"redo:",
|
||||
@"key" : @"Z"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Cut",
|
||||
@"action" : @"cut:",
|
||||
@"key" : @"x"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Copy",
|
||||
@"action" : @"copy:",
|
||||
@"key" : @"c"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Paste",
|
||||
@"action" : @"paste:",
|
||||
@"key" : @"v"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Select All",
|
||||
@"action" : @"selectAll:",
|
||||
@"key" : @"a"
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"View",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Fullscreen",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle fullscreen"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Float on Top",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle ontop"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Visibility on All Workspaces",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle on-all-workspaces"
|
||||
}],
|
||||
#if HAVE_MACOS_TOUCHBAR
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Customize Touch Bar…",
|
||||
@"action" : @"toggleTouchBarCustomizationPalette:",
|
||||
@"key" : @"",
|
||||
@"target" : NSApp
|
||||
}]
|
||||
#endif
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Video",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Zoom Out",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add panscan -0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Zoom In",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add panscan 0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Reset Zoom",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set panscan 0"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Aspect Ratio 4:3",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set video-aspect-override \"4:3\""
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Aspect Ratio 16:9",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set video-aspect-override \"16:9\""
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Aspect Ratio 1.85:1",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set video-aspect-override \"1.85:1\""
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Aspect Ratio 2.35:1",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set video-aspect-override \"2.35:1\""
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Reset Aspect Ratio",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set video-aspect-override \"-1\""
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Rotate Left",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle-values video-rotate 0 270 180 90"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Rotate Right",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle-values video-rotate 90 180 270 0"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Reset Rotation",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set video-rotate 0"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Half Size",
|
||||
@"key" : @"0",
|
||||
@"cmdSpecial" : [NSNumber numberWithInt:MPM_H_SIZE]
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Normal Size",
|
||||
@"key" : @"1",
|
||||
@"cmdSpecial" : [NSNumber numberWithInt:MPM_N_SIZE]
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Double Size",
|
||||
@"key" : @"2",
|
||||
@"cmdSpecial" : [NSNumber numberWithInt:MPM_D_SIZE]
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Audio",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Next Audio Track",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle audio"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Previous Audio Track",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle audio down"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Mute",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle mute"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Play Audio Later",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add audio-delay 0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Play Audio Earlier",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add audio-delay -0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Reset Audio Delay",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set audio-delay 0.0 "
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Subtitle",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Next Subtitle Track",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle sub"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Previous Subtitle Track",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle sub down"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Force Style",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle-values sub-ass-override \"force\" \"no\""
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Display Subtitles Later",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add sub-delay 0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Display Subtitles Earlier",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add sub-delay -0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Reset Subtitle Delay",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set sub-delay 0.0"
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Playback",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Pause",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle pause"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Increase Speed",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add speed 0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Decrease Speed",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add speed -0.1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Reset Speed",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"set speed 1.0"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Show Playlist",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"script-message osc-playlist"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Show Chapters",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"script-message osc-chapterlist"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Show Tracks",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"script-message osc-tracklist"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Next File",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"playlist-next"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Previous File",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"playlist-prev"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Loop File",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle-values loop-file \"inf\" \"no\""
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Toggle Loop Playlist",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"cycle-values loop-playlist \"inf\" \"no\""
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Shuffle",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"playlist-shuffle"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Next Chapter",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add chapter 1"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Previous Chapter",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"add chapter -1"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Step Forward",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"frame-step"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Step Backward",
|
||||
@"action" : @"cmd:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"cmd" : @"frame-back-step"
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Window",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Minimize",
|
||||
@"key" : @"m",
|
||||
@"cmdSpecial" : [NSNumber numberWithInt:MPM_MINIMIZE]
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Zoom",
|
||||
@"key" : @"z",
|
||||
@"cmdSpecial" : [NSNumber numberWithInt:MPM_ZOOM]
|
||||
}]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"name": @"Help",
|
||||
@"menu": @[
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"mpv Website…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://mpv.io"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"mpv on GitHub…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://github.com/mpv-player/mpv"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Online Manual…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://mpv.io/manual/master/"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Online Wiki…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://github.com/mpv-player/mpv/wiki"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Release Notes…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://github.com/mpv-player/mpv/blob/master/RELEASE_NOTES"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Keyboard Shortcuts…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://github.com/mpv-player/mpv/blob/master/etc/input.conf"
|
||||
}],
|
||||
@{ @"name": @"separator" },
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Report Issue…",
|
||||
@"action" : @"url:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"url" : @"https://github.com/mpv-player/mpv/issues/new/choose"
|
||||
}],
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"name" : @"Show log File…",
|
||||
@"action" : @"showFile:",
|
||||
@"key" : @"",
|
||||
@"target" : self,
|
||||
@"file" : @"~/Library/Logs/mpv.log",
|
||||
@"alertTitle" : @"No log File found.",
|
||||
@"alertText" : @"You deactivated logging for the Bundle."
|
||||
}]
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
[NSApp setMainMenu:[self mainMenu]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSMenu *)mainMenu
|
||||
{
|
||||
NSMenu *mainMenu = [[NSMenu alloc] initWithTitle:@"MainMenu"];
|
||||
[NSApp setServicesMenu:[[NSMenu alloc] init]];
|
||||
NSString* bundle = [[[NSProcessInfo processInfo] environment] objectForKey:@"MPVBUNDLE"];
|
||||
|
||||
for(id mMenu in menuTree) {
|
||||
NSMenu *menu = [[NSMenu alloc] initWithTitle:mMenu[@"name"]];
|
||||
NSMenuItem *mItem = [mainMenu addItemWithTitle:mMenu[@"name"]
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
[mainMenu setSubmenu:menu forItem:mItem];
|
||||
|
||||
for(id subMenu in mMenu[@"menu"]) {
|
||||
NSString *name = subMenu[@"name"];
|
||||
NSString *action = subMenu[@"action"];
|
||||
|
||||
#if HAVE_MACOS_TOUCHBAR
|
||||
if ([action isEqual:@"toggleTouchBarCustomizationPalette:"]) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ([name isEqual:@"Show log File…"] && ![bundle isEqual:@"true"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([name isEqual:@"separator"]) {
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
} else {
|
||||
NSMenuItem *iItem = [menu addItemWithTitle:name
|
||||
action:NSSelectorFromString(action)
|
||||
keyEquivalent:subMenu[@"key"]];
|
||||
[iItem setTarget:subMenu[@"target"]];
|
||||
[subMenu setObject:iItem forKey:@"menuItem"];
|
||||
|
||||
NSNumber *m = subMenu[@"modifiers"];
|
||||
if (m) {
|
||||
[iItem setKeyEquivalentModifierMask:m.unsignedIntegerValue];
|
||||
}
|
||||
|
||||
if ([subMenu[@"name"] isEqual:@"Services"]) {
|
||||
iItem.submenu = [NSApp servicesMenu];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mainMenu;
|
||||
}
|
||||
|
||||
- (void)about
|
||||
{
|
||||
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"mpv", @"ApplicationName",
|
||||
[(Application *)NSApp getMPVIcon], @"ApplicationIcon",
|
||||
[NSString stringWithUTF8String:mpv_copyright], @"Copyright",
|
||||
[NSString stringWithUTF8String:mpv_version], @"ApplicationVersion",
|
||||
nil];
|
||||
[NSApp orderFrontStandardAboutPanelWithOptions:options];
|
||||
}
|
||||
|
||||
- (void)preferences:(NSMenuItem *)menuItem
|
||||
{
|
||||
NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSMutableDictionary *mItemDict = [self getDictFromMenuItem:menuItem];
|
||||
NSArray *configPaths = @[
|
||||
[NSString stringWithFormat:@"%@/.mpv/", NSHomeDirectory()],
|
||||
[NSString stringWithFormat:@"%@/.config/mpv/", NSHomeDirectory()]];
|
||||
|
||||
for (id path in configPaths) {
|
||||
NSString *fileP = [path stringByAppendingString:mItemDict[@"file"]];
|
||||
if ([fileManager fileExistsAtPath:fileP]){
|
||||
if ([workspace openFile:fileP])
|
||||
return;
|
||||
[workspace openFile:path];
|
||||
[self alertWithTitle:mItemDict[@"alertTitle1"]
|
||||
andText:mItemDict[@"alertText1"]];
|
||||
return;
|
||||
}
|
||||
if ([workspace openFile:path]) {
|
||||
[self alertWithTitle:mItemDict[@"alertTitle2"]
|
||||
andText:mItemDict[@"alertText2"]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[self alertWithTitle:mItemDict[@"alertTitle3"]
|
||||
andText:mItemDict[@"alertText3"]];
|
||||
}
|
||||
|
||||
- (void)quit:(NSMenuItem *)menuItem
|
||||
{
|
||||
NSString *cmd = [self getDictFromMenuItem:menuItem][@"cmd"];
|
||||
[(Application *)NSApp stopMPV:(char *)[cmd UTF8String]];
|
||||
}
|
||||
|
||||
- (void)openFile
|
||||
{
|
||||
NSOpenPanel *panel = [[NSOpenPanel alloc] init];
|
||||
[panel setCanChooseDirectories:YES];
|
||||
[panel setAllowsMultipleSelection:YES];
|
||||
|
||||
if ([panel runModal] == NSModalResponseOK){
|
||||
NSMutableArray *fileArray = [[NSMutableArray alloc] init];
|
||||
for (id url in [panel URLs])
|
||||
[fileArray addObject:[url path]];
|
||||
[(Application *)NSApp openFiles:fileArray];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openPlaylist
|
||||
{
|
||||
NSOpenPanel *panel = [[NSOpenPanel alloc] init];
|
||||
|
||||
if ([panel runModal] == NSModalResponseOK){
|
||||
NSString *pl = [NSString stringWithFormat:@"loadlist \"%@\"",
|
||||
[panel URLs][0].path];
|
||||
[(Application *)NSApp queueCommand:(char *)[pl UTF8String]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openURL
|
||||
{
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:@"Open URL"];
|
||||
[alert addButtonWithTitle:@"Ok"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setIcon:[(Application *)NSApp getMPVIcon]];
|
||||
|
||||
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
|
||||
[input setPlaceholderString:@"URL"];
|
||||
[alert setAccessoryView:input];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
[input becomeFirstResponder];
|
||||
});
|
||||
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn && [input stringValue].length > 0) {
|
||||
NSArray *url = [NSArray arrayWithObjects:[input stringValue], nil];
|
||||
[(Application *)NSApp openFiles:url];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cmd:(NSMenuItem *)menuItem
|
||||
{
|
||||
NSString *cmd = [self getDictFromMenuItem:menuItem][@"cmd"];
|
||||
[(Application *)NSApp queueCommand:(char *)[cmd UTF8String]];
|
||||
}
|
||||
|
||||
- (void)url:(NSMenuItem *)menuItem
|
||||
{
|
||||
NSString *url = [self getDictFromMenuItem:menuItem][@"url"];
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
|
||||
}
|
||||
|
||||
- (void)showFile:(NSMenuItem *)menuItem
|
||||
{
|
||||
NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSMutableDictionary *mItemDict = [self getDictFromMenuItem:menuItem];
|
||||
NSString *file = [mItemDict[@"file"] stringByExpandingTildeInPath];
|
||||
|
||||
if ([fileManager fileExistsAtPath:file]){
|
||||
NSURL *url = [NSURL fileURLWithPath:file];
|
||||
NSArray *urlArray = [NSArray arrayWithObjects:url, nil];
|
||||
|
||||
[workspace activateFileViewerSelectingURLs:urlArray];
|
||||
return;
|
||||
}
|
||||
|
||||
[self alertWithTitle:mItemDict[@"alertTitle"]
|
||||
andText:mItemDict[@"alertText"]];
|
||||
}
|
||||
|
||||
- (void)alertWithTitle:(NSString *)title andText:(NSString *)text
|
||||
{
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:title];
|
||||
[alert setInformativeText:text];
|
||||
[alert addButtonWithTitle:@"Ok"];
|
||||
[alert setIcon:[(Application *)NSApp getMPVIcon]];
|
||||
[alert runModal];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)getDictFromMenuItem:(NSMenuItem *)menuItem
|
||||
{
|
||||
for(id mMenu in menuTree) {
|
||||
for(id subMenu in mMenu[@"menu"]) {
|
||||
if([subMenu[@"menuItem"] isEqual:menuItem])
|
||||
return subMenu;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)registerSelector:(SEL)action forKey:(MPMenuKey)key
|
||||
{
|
||||
for(id mMenu in menuTree) {
|
||||
for(id subMenu in mMenu[@"menu"]) {
|
||||
if([subMenu[@"cmdSpecial"] isEqual:[NSNumber numberWithInt:key]]) {
|
||||
[subMenu[@"menuItem"] setAction:action];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "osdep/mac/menubar.h"
|
||||
|
||||
@interface MenuBar : NSObject
|
||||
|
||||
- (void)registerSelector:(SEL)action forKey:(MPMenuKey)key;
|
||||
|
||||
@end
|
@ -19,6 +19,10 @@ if get_option('optimization') != '0'
|
||||
swift_flags += '-O'
|
||||
endif
|
||||
|
||||
if macos_touchbar.allowed()
|
||||
swift_flags += ['-D', 'HAVE_MACOS_TOUCHBAR']
|
||||
endif
|
||||
|
||||
extra_flags = get_option('swift-flags').split()
|
||||
swift_flags += extra_flags
|
||||
|
||||
|
@ -49,6 +49,9 @@ static int SWIFT_MBTN9 = MP_MBTN9;
|
||||
static int SWIFT_KEY_MOUSE_LEAVE = MP_KEY_MOUSE_LEAVE;
|
||||
static int SWIFT_KEY_MOUSE_ENTER = MP_KEY_MOUSE_ENTER;
|
||||
|
||||
static const char *swift_mpv_version = mpv_version;
|
||||
static const char *swift_mpv_copyright = mpv_copyright;
|
||||
|
||||
// only used from Swift files and therefore seen as unused by the c compiler
|
||||
static void SWIFT_TARRAY_STRING_APPEND(void *t, char ***a, int *i, char *s) __attribute__ ((unused));
|
||||
|
||||
|
@ -105,11 +105,11 @@ class Window: NSWindow, NSWindowDelegate {
|
||||
unfScreen = screen
|
||||
|
||||
if let app = NSApp as? Application {
|
||||
app.menuBar.register(#selector(setHalfWindowSize), for: MPM_H_SIZE)
|
||||
app.menuBar.register(#selector(setNormalWindowSize), for: MPM_N_SIZE)
|
||||
app.menuBar.register(#selector(setDoubleWindowSize), for: MPM_D_SIZE)
|
||||
app.menuBar.register(#selector(performMiniaturize(_:)), for: MPM_MINIMIZE)
|
||||
app.menuBar.register(#selector(performZoom(_:)), for: MPM_ZOOM)
|
||||
app.menuBar.register(#selector(setHalfWindowSize), key: .halfSize)
|
||||
app.menuBar.register(#selector(setNormalWindowSize), key: .normalSize)
|
||||
app.menuBar.register(#selector(setDoubleWindowSize), key: .doubleSize)
|
||||
app.menuBar.register(#selector(performMiniaturize(_:)), key: .minimize)
|
||||
app.menuBar.register(#selector(performZoom(_:)), key: .zoom)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user