summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--osdep/macOS_swift_bridge.h3
-rw-r--r--osdep/macos/remote_command_center.swift159
-rw-r--r--osdep/macosx_application.m15
-rw-r--r--osdep/macosx_application_objc.h3
-rw-r--r--osdep/macosx_events.m127
-rw-r--r--osdep/macosx_events_objc.h3
-rw-r--r--video/out/cocoa-cb/events_view.swift12
-rw-r--r--video/out/cocoa-cb/window.swift2
-rw-r--r--wscript5
-rw-r--r--wscript_build.py1
10 files changed, 197 insertions, 133 deletions
diff --git a/osdep/macOS_swift_bridge.h b/osdep/macOS_swift_bridge.h
index f0b549ca40..29cd8bf016 100644
--- a/osdep/macOS_swift_bridge.h
+++ b/osdep/macOS_swift_bridge.h
@@ -44,11 +44,8 @@ static int SWIFT_MBTN_BACK = MP_MBTN_BACK;
static int SWIFT_MBTN_FORWARD = MP_MBTN_FORWARD;
static int SWIFT_MBTN9 = MP_MBTN9;
-static int SWIFT_KEY_CLOSE_WIN = MP_KEY_CLOSE_WIN;
static int SWIFT_KEY_MOUSE_LEAVE = MP_KEY_MOUSE_LEAVE;
static int SWIFT_KEY_MOUSE_ENTER = MP_KEY_MOUSE_ENTER;
-static int SWIFT_KEY_STATE_DOWN = MP_KEY_STATE_DOWN;
-static int SWIFT_KEY_STATE_UP = MP_KEY_STATE_UP;
// 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));
diff --git a/osdep/macos/remote_command_center.swift b/osdep/macos/remote_command_center.swift
new file mode 100644
index 0000000000..585a2e5698
--- /dev/null
+++ b/osdep/macos/remote_command_center.swift
@@ -0,0 +1,159 @@
+/*
+ * 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 MediaPlayer
+
+@available(macOS 10.12.2, *)
+class RemoteCommandCenter: NSObject {
+
+ enum KeyType {
+ case normal
+ case repeatable
+ }
+
+ var config: [MPRemoteCommand:[String:Any]] = [
+ MPRemoteCommandCenter.shared().pauseCommand: [
+ "mpKey": MP_KEY_PAUSE,
+ "keyType": KeyType.normal
+ ],
+ MPRemoteCommandCenter.shared().playCommand: [
+ "mpKey": MP_KEY_PLAY,
+ "keyType": KeyType.normal
+ ],
+ MPRemoteCommandCenter.shared().stopCommand: [
+ "mpKey": MP_KEY_STOP,
+ "keyType": KeyType.normal
+ ],
+ MPRemoteCommandCenter.shared().nextTrackCommand: [
+ "mpKey": MP_KEY_NEXT,
+ "keyType": KeyType.normal
+ ],
+ MPRemoteCommandCenter.shared().previousTrackCommand: [
+ "mpKey": MP_KEY_PREV,
+ "keyType": KeyType.normal
+ ],
+ MPRemoteCommandCenter.shared().togglePlayPauseCommand: [
+ "mpKey": MP_KEY_PLAYPAUSE,
+ "keyType": KeyType.normal
+ ],
+ MPRemoteCommandCenter.shared().seekForwardCommand: [
+ "mpKey": MP_KEY_FORWARD,
+ "keyType": KeyType.repeatable,
+ "state": MP_KEY_STATE_UP
+ ],
+ MPRemoteCommandCenter.shared().seekBackwardCommand: [
+ "mpKey": MP_KEY_REWIND,
+ "keyType": KeyType.repeatable,
+ "state": MP_KEY_STATE_UP
+ ],
+ ]
+
+ var nowPlayingInfo: [String: Any] = [
+ MPNowPlayingInfoPropertyMediaType: NSNumber(value: MPNowPlayingInfoMediaType.video.rawValue),
+ MPNowPlayingInfoPropertyDefaultPlaybackRate: NSNumber(value: 1),
+ MPNowPlayingInfoPropertyPlaybackProgress: NSNumber(value: 0.0),
+ MPMediaItemPropertyPlaybackDuration: NSNumber(value: 0),
+ MPMediaItemPropertyTitle: "mpv",
+ MPMediaItemPropertyAlbumTitle: "mpv",
+ MPMediaItemPropertyArtist: "mpv",
+ ]
+
+ let disabledCommands: [MPRemoteCommand] = [
+ MPRemoteCommandCenter.shared().changePlaybackRateCommand,
+ MPRemoteCommandCenter.shared().changeRepeatModeCommand,
+ MPRemoteCommandCenter.shared().changeShuffleModeCommand,
+ MPRemoteCommandCenter.shared().skipForwardCommand,
+ MPRemoteCommandCenter.shared().skipBackwardCommand,
+ MPRemoteCommandCenter.shared().changePlaybackPositionCommand,
+ MPRemoteCommandCenter.shared().enableLanguageOptionCommand,
+ MPRemoteCommandCenter.shared().disableLanguageOptionCommand,
+ MPRemoteCommandCenter.shared().ratingCommand,
+ MPRemoteCommandCenter.shared().likeCommand,
+ MPRemoteCommandCenter.shared().dislikeCommand,
+ MPRemoteCommandCenter.shared().bookmarkCommand,
+ ]
+
+ let application: Application;
+
+ @objc init(app: Application) {
+ application = app
+
+ super.init()
+
+ for cmd in disabledCommands {
+ cmd.isEnabled = false
+ }
+ }
+
+ @objc func makeCurrent() {
+ MPNowPlayingInfoCenter.default().playbackState = .paused
+ MPNowPlayingInfoCenter.default().playbackState = .playing
+ }
+
+ @objc func start() {
+ for (cmd, _) in config {
+ cmd.isEnabled = true
+ cmd.addTarget { [unowned self] event in
+ return self.cmdHandler(event)
+ }
+ }
+
+ if let icon = application.getMPVIcon(), #available(macOS 10.13.2, *) {
+ let albumArt = MPMediaItemArtwork(boundsSize:icon.size) { _ in
+ return icon
+ }
+ nowPlayingInfo[MPMediaItemPropertyArtwork] = albumArt
+ }
+
+ MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
+ MPNowPlayingInfoCenter.default().playbackState = .playing
+ }
+
+ @objc func stop() {
+ for (cmd, _) in config {
+ cmd.isEnabled = false
+ cmd.removeTarget(nil)
+ }
+
+ MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
+ MPNowPlayingInfoCenter.default().playbackState = .unknown
+ }
+
+ func cmdHandler(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
+ guard let cmdConfig = config[event.command],
+ let mpKey = cmdConfig["mpKey"] as? Int32,
+ let keyType = cmdConfig["keyType"] as? KeyType else
+ {
+ return .commandFailed
+ }
+
+ var state = cmdConfig["state"] as? UInt32 ?? 0
+
+ if let currentState = cmdConfig["state"] as? UInt32, keyType == .repeatable {
+ state = MP_KEY_STATE_DOWN
+ config[event.command]?["state"] = MP_KEY_STATE_DOWN
+ if currentState == MP_KEY_STATE_DOWN {
+ state = MP_KEY_STATE_UP
+ config[event.command]?["state"] = MP_KEY_STATE_UP
+ }
+ }
+
+ application.handleMPKey(mpKey, withMask: Int32(state));
+
+ return .success
+ }
+} \ No newline at end of file
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m
index 8b3fac95a4..3d420a3152 100644
--- a/osdep/macosx_application.m
+++ b/osdep/macosx_application.m
@@ -105,6 +105,7 @@ static void terminate_cocoa_application(void)
@synthesize menuBar = _menu_bar;
@synthesize openCount = _open_count;
@synthesize cocoaCB = _cocoa_cb;
+@synthesize remoteCommandCenter = _remoteCommandCenter;
- (void)sendEvent:(NSEvent *)event
{
@@ -199,6 +200,11 @@ static const char macosx_icon[] =
[_eventsResponder queueCommand:cmd];
}
+- (void)handleMPKey:(int)key withMask:(int)mask
+{
+ [_eventsResponder handleMPKey:key withMask:mask];
+}
+
- (void)stopMPV:(char *)cmd
{
if (![_eventsResponder queueCommand:cmd])
@@ -216,7 +222,7 @@ static const char macosx_icon[] =
- (void)applicationWillBecomeActive:(NSNotification *)notification
{
- [_eventsResponder setHighestPriotityMediaKeysTap];
+ [_remoteCommandCenter makeCurrent];
}
- (void)handleQuitEvent:(NSAppleEventDescriptor *)event
@@ -293,6 +299,13 @@ static void init_cocoa_application(bool regular)
[NSApp setDelegate:NSApp];
[NSApp setMenuBar:[[MenuBar alloc] init]];
+#if HAVE_MACOS_10_12_2_FEATURES
+ // 10.12.2 runtime availability check
+ if ([NSApp respondsToSelector:@selector(touchBar)]) {
+ [NSApp setRemoteCommandCenter:[[RemoteCommandCenter alloc] initWithApp:NSApp]];
+ }
+#endif
+
// Will be set to Regular from cocoa_common during UI creation so that we
// don't create an icon when playing audio only files.
[NSApp setActivationPolicy: regular ?
diff --git a/osdep/macosx_application_objc.h b/osdep/macosx_application_objc.h
index 11959a83ea..4bd5b55b1a 100644
--- a/osdep/macosx_application_objc.h
+++ b/osdep/macosx_application_objc.h
@@ -20,6 +20,7 @@
#import "osdep/macosx_menubar_objc.h"
@class CocoaCB;
+@class RemoteCommandCenter;
struct mpv_event;
struct mpv_handle;
@@ -28,6 +29,7 @@ struct mpv_handle;
- (NSImage *)getMPVIcon;
- (void)processEvent:(struct mpv_event *)event;
- (void)queueCommand:(char *)cmd;
+- (void)handleMPKey:(int)key withMask:(int)mask;
- (void)stopMPV:(char *)cmd;
- (void)openFiles:(NSArray *)filenames;
- (void)setMpvHandle:(struct mpv_handle *)ctx;
@@ -37,4 +39,5 @@ struct mpv_handle;
@property(nonatomic, retain) MenuBar *menuBar;
@property(nonatomic, assign) size_t openCount;
@property(nonatomic, retain) CocoaCB *cocoaCB;
+@property(nonatomic, retain) RemoteCommandCenter *remoteCommandCenter;
@end
diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m
index 14aa7063fb..3f40e41f6c 100644
--- a/osdep/macosx_events.m
+++ b/osdep/macosx_events.m
@@ -49,15 +49,12 @@
struct mpv_handle *_ctx;
BOOL _is_application;
NSCondition *_input_lock;
- CFMachPortRef _mk_tap_port;
}
-- (BOOL)handleMediaKey:(NSEvent *)event;
- (NSEvent *)handleKey:(NSEvent *)event;
- (BOOL)setMpvHandle:(struct mpv_handle *)ctx;
- (void)readEvents;
- (void)startMediaKeys;
-- (void)restartMediaKeys;
- (void)stopMediaKeys;
- (int)mapKeyModifiers:(int)cocoaModifiers;
- (int)keyModifierMask:(NSEvent *)event;
@@ -121,53 +118,6 @@ static int convert_key(unsigned key, unsigned charcode)
return charcode;
}
-static int mk_code(NSEvent *event)
-{
- return (([event data1] & 0xFFFF0000) >> 16);
-}
-
-static int mk_flags(NSEvent *event)
-{
- return ([event data1] & 0x0000FFFF);
-}
-
-static int mk_down(NSEvent *event)
-{
- return (((mk_flags(event) & 0xFF00) >> 8)) == 0xA;
-}
-
-static CGEventRef tap_event_callback(CGEventTapProxy proxy, CGEventType type,
- CGEventRef event, void *ctx)
-{
- EventsResponder *responder = ctx;
-
- if (type == kCGEventTapDisabledByTimeout) {
- // The Mach Port receiving the taps became unresponsive for some
- // reason, restart listening on it.
- [responder restartMediaKeys];
- return event;
- }
-
- if (type == kCGEventTapDisabledByUserInput)
- return event;
-
- NSEvent *nse = [NSEvent eventWithCGEvent:event];
-
- if ([nse type] != NSEventTypeSystemDefined || [nse subtype] != 8)
- // This is not a media key
- return event;
-
- if (mk_down(nse) && [responder handleMediaKey:nse]) {
- // Handled this event, return nil so that it is removed from the
- // global queue.
- return nil;
- } else {
- // Was a media key but we were not interested in it. Leave it in the
- // global queue by returning the original event.
- return event;
- }
-}
-
void cocoa_init_media_keys(void)
{
[[EventsResponder sharedInstance] startMediaKeys];
@@ -337,77 +287,18 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx)
}
}
-- (void)restartMediaKeys
-{
- if (self->_mk_tap_port)
- CGEventTapEnable(self->_mk_tap_port, true);
-}
-
-- (void)setHighestPriotityMediaKeysTap
-{
- if (self->_mk_tap_port == nil)
- return;
-
- CGEventTapInformation *taps = ta_alloc_size(nil, sizeof(CGEventTapInformation));
- uint32_t numTaps = 0;
- CGError err = CGGetEventTapList(1, taps, &numTaps);
-
- if (err == kCGErrorSuccess && numTaps > 0) {
- pid_t processID = [NSProcessInfo processInfo].processIdentifier;
- if (taps[0].tappingProcess != processID) {
- [self stopMediaKeys];
- [self startMediaKeys];
- }
- }
- talloc_free(taps);
-}
-
- (void)startMediaKeys
{
- dispatch_async(dispatch_get_main_queue(), ^{
- // Install a Quartz Event Tap. This will notify mpv through the
- // returned Mach Port and cause mpv to execute the `tap_event_callback`
- // function.
- self->_mk_tap_port = CGEventTapCreate(kCGSessionEventTap,
- kCGHeadInsertEventTap,
- kCGEventTapOptionDefault,
- CGEventMaskBit(NX_SYSDEFINED),
- tap_event_callback,
- self);
-
- if (self->_mk_tap_port) {
- NSMachPort *port = (NSMachPort *)self->_mk_tap_port;
- [[NSRunLoop mainRunLoop] addPort:port forMode:NSRunLoopCommonModes];
- }
- });
+ if ([(Application *)NSApp remoteCommandCenter]) {
+ [[(Application *)NSApp remoteCommandCenter] start];
+ }
}
- (void)stopMediaKeys
{
- dispatch_async(dispatch_get_main_queue(), ^{
- NSMachPort *port = (NSMachPort *)self->_mk_tap_port;
- if (port) {
- CGEventTapEnable(self->_mk_tap_port, false);
- [[NSRunLoop mainRunLoop] removePort:port forMode:NSRunLoopCommonModes];
- CFRelease(self->_mk_tap_port);
- self->_mk_tap_port = nil;
- }
- });
-}
-
-- (BOOL)handleMediaKey:(NSEvent *)event
-{
- NSDictionary *keymapd = @{
- @(NX_KEYTYPE_PLAY): @(MP_KEY_PLAY),
- @(NX_KEYTYPE_REWIND): @(MP_KEY_PREV),
- @(NX_KEYTYPE_FAST): @(MP_KEY_NEXT),
- @(NX_KEYTYPE_PREVIOUS): @(MP_KEY_REWIND),
- @(NX_KEYTYPE_NEXT): @(MP_KEY_FORWARD),
- };
-
- return [self handleKey:mk_code(event)
- withMask:[self keyModifierMask:event]
- andMapping:keymapd];
+ if ([(Application *)NSApp remoteCommandCenter]) {
+ [[(Application *)NSApp remoteCommandCenter] stop];
+ }
}
- (int)mapKeyModifiers:(int)cocoaModifiers
@@ -452,12 +343,6 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx)
}
}
--(BOOL)handleKey:(int)key withMask:(int)mask andMapping:(NSDictionary *)mapping
-{
- int mpkey = [mapping[@(key)] intValue];
- return [self handleMPKey:mpkey withMask:mask];
-}
-
- (NSEvent*)handleKey:(NSEvent *)event
{
if ([event isARepeat]) return nil;
diff --git a/osdep/macosx_events_objc.h b/osdep/macosx_events_objc.h
index 42f6ee234a..efc4e8f7ec 100644
--- a/osdep/macosx_events_objc.h
+++ b/osdep/macosx_events_objc.h
@@ -32,10 +32,11 @@ struct input_ctx;
- (void)waitForInputContext;
- (void)wakeup;
- (void)putKey:(int)keycode;
-- (void)setHighestPriotityMediaKeysTap;
- (void)handleFilesArray:(NSArray *)files;
- (bool)queueCommand:(char *)cmd;
- (bool)processKeyEvent:(NSEvent *)event;
+- (BOOL)handleMPKey:(int)key withMask:(int)mask;
+
@end
diff --git a/video/out/cocoa-cb/events_view.swift b/video/out/cocoa-cb/events_view.swift
index 31533bbb98..73ccba527f 100644
--- a/video/out/cocoa-cb/events_view.swift
+++ b/video/out/cocoa-cb/events_view.swift
@@ -180,20 +180,20 @@ class EventsView: NSView {
}
func signalMouseDown(_ event: NSEvent) {
- signalMouseEvent(event, SWIFT_KEY_STATE_DOWN)
+ signalMouseEvent(event, MP_KEY_STATE_DOWN)
if event.clickCount > 1 {
- signalMouseEvent(event, SWIFT_KEY_STATE_UP)
+ signalMouseEvent(event, MP_KEY_STATE_UP)
}
}
func signalMouseUp(_ event: NSEvent) {
- signalMouseEvent(event, SWIFT_KEY_STATE_UP)
+ signalMouseEvent(event, MP_KEY_STATE_UP)
}
- func signalMouseEvent(_ event: NSEvent, _ state: Int32) {
- hasMouseDown = state == SWIFT_KEY_STATE_DOWN
+ func signalMouseEvent(_ event: NSEvent, _ state: UInt32) {
+ hasMouseDown = state == MP_KEY_STATE_DOWN
let mpkey = getMpvButton(event)
- cocoa_put_key_with_modifiers((mpkey | state), Int32(event.modifierFlags.rawValue));
+ cocoa_put_key_with_modifiers((mpkey | Int32(state)), Int32(event.modifierFlags.rawValue));
}
func signalMouseMovement(_ event: NSEvent) {
diff --git a/video/out/cocoa-cb/window.swift b/video/out/cocoa-cb/window.swift
index 94f80e59b4..6e53ef309c 100644
--- a/video/out/cocoa-cb/window.swift
+++ b/video/out/cocoa-cb/window.swift
@@ -486,7 +486,7 @@ class Window: NSWindow, NSWindowDelegate {
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
- cocoa_put_key(SWIFT_KEY_CLOSE_WIN)
+ cocoa_put_key(MP_KEY_CLOSE_WIN)
return false
}
diff --git a/wscript b/wscript
index 3aa1376995..ff946900da 100644
--- a/wscript
+++ b/wscript
@@ -919,6 +919,11 @@ standalone_features = [
'deps': 'cocoa',
'func': check_macos_sdk('10.11')
}, {
+ 'name': '--macos-10-12-2-features',
+ 'desc': 'macOS 10.12.2 SDK Features',
+ 'deps': 'cocoa',
+ 'func': check_macos_sdk('10.12.2')
+ }, {
'name': '--macos-10-14-features',
'desc': 'macOS 10.14 SDK Features',
'deps': 'cocoa',
diff --git a/wscript_build.py b/wscript_build.py
index 3ad85fd3b5..4c34d94c45 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -174,6 +174,7 @@ def build(ctx):
( "osdep/macos/mpv_helper.swift" ),
( "osdep/macos/swift_extensions.swift" ),
( "osdep/macos/swift_compat.swift" ),
+ ( "osdep/macos/remote_command_center.swift", "macos-10-12-2-features" ),
( "video/out/cocoa-cb/events_view.swift" ),
( "video/out/cocoa-cb/video_layer.swift" ),
( "video/out/cocoa-cb/window.swift" ),