diff --git a/modules/gui/macosx/SPMediaKeyTap.h b/modules/gui/macosx/SPMediaKeyTap.h index 8b748a29ed891bfc5483896a30ce91706f927437..e5e0909ee6855081ad306176af6eb388e36b13bc 100644 --- a/modules/gui/macosx/SPMediaKeyTap.h +++ b/modules/gui/macosx/SPMediaKeyTap.h @@ -18,24 +18,15 @@ #define SPSystemDefinedEventMediaKeys 8 @interface SPMediaKeyTap : NSObject { - -EventHandlerRef _app_switching_ref; - -EventHandlerRef _app_terminating_ref; - -CFMachPortRef _eventPort; - -CFRunLoopSourceRef _eventPortSource; - -CFRunLoopRef _tapThreadRL; - -BOOL _shouldInterceptMediaKeyEvents; - -id _delegate; - -// The app that is frontmost in this list owns media keys - -NSMutableArray *_mediaKeyAppList; + EventHandlerRef _app_switching_ref; + EventHandlerRef _app_terminating_ref; + CFMachPortRef _eventPort; + CFRunLoopSourceRef _eventPortSource; + CFRunLoopRef _tapThreadRL; + BOOL _shouldInterceptMediaKeyEvents; + id _delegate; + // The app that is frontmost in this list owns media keys + NSMutableArray *_mediaKeyAppList; } + (NSArray*)defaultMediaKeyUserBundleIdentifiers; @@ -45,11 +36,19 @@ NSMutableArray *_mediaKeyAppList; -(void)startWatchingMediaKeys; -(void)stopWatchingMediaKeys; -(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event; --(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting; @end @interface NSObject (SPMediaKeyTapDelegate) -(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event; @end +#ifdef __cplusplus +extern "C" { +#endif + extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey; +extern NSString *kIgnoreMediaKeysDefaultsKey; + +#ifdef __cplusplus +} +#endif diff --git a/modules/gui/macosx/SPMediaKeyTap.m b/modules/gui/macosx/SPMediaKeyTap.m index 52a66502bb3a9fc3008c3f55ce5b316e21820e1c..1402640ec077d592f63af851ace32112fcaa42bb 100644 --- a/modules/gui/macosx/SPMediaKeyTap.m +++ b/modules/gui/macosx/SPMediaKeyTap.m @@ -11,10 +11,11 @@ // Copyright (c) 2010 Spotify AB #import "SPMediaKeyTap.h" -#import "SPInvocationGrabbing.h" // https://gist.github.com/511181 +#import "SPInvocationGrabbing.h" @interface SPMediaKeyTap () -(BOOL)shouldInterceptMediaKeyEvents; +-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting; -(void)startWatchingAppSwitching; -(void)stopWatchingAppSwitching; -(void)eventTapThread; @@ -38,6 +39,9 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv [self startWatchingAppSwitching]; singleton = self; _mediaKeyAppList = [NSMutableArray new]; + _tapThreadRL=nil; + _eventPort=nil; + _eventPortSource=nil; return self; } -(void)dealloc; @@ -68,6 +72,9 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv } -(void)startWatchingMediaKeys;{ + // Prevent having multiple mediaKeys threads + [self stopWatchingMediaKeys]; + [self setShouldInterceptMediaKeyEvents:YES]; // Add an event tap to intercept the system defined media key events @@ -88,6 +95,22 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv -(void)stopWatchingMediaKeys; { // TODO: Shut down thread, remove event tap port and source + + if(_tapThreadRL){ + CFRunLoopStop(_tapThreadRL); + _tapThreadRL=nil; + } + + if(_eventPort){ + CFMachPortInvalidate(_eventPort); + CFRelease(_eventPort); + _eventPort=nil; + } + + if(_eventPortSource){ + CFRelease(_eventPortSource); + _eventPortSource=nil; + } } #pragma mark - @@ -95,18 +118,21 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv +(BOOL)usesGlobalMediaKeyTap { - return YES; #ifdef _DEBUG + // breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot return NO; #else // XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy. - return floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/; + return + ![[NSUserDefaults standardUserDefaults] boolForKey:kIgnoreMediaKeysDefaultsKey] + && floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/; #endif } + (NSArray*)defaultMediaKeyUserBundleIdentifiers; { return [NSArray arrayWithObjects: + [[NSBundle mainBundle] bundleIdentifier], // your app @"com.spotify.client", @"com.apple.iTunes", @"com.apple.QuickTimePlayerX", @@ -117,6 +143,14 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv @"com.apple.Aperture", @"com.plexsquared.Plex", @"com.soundcloud.desktop", + @"org.niltsh.MPlayerX", + @"com.ilabs.PandorasHelper", + @"com.mahasoftware.pandabar", + @"com.bitcartel.pandorajam", + @"org.clementine-player.clementine", + @"fm.last.Last.fm", + @"com.beatport.BeatportPro", + @"com.Timenut.SongKey", @"com.macromedia.fireworks", // the tap messes up their mouse input nil ]; @@ -222,6 +256,8 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv #pragma mark Task switching callbacks NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys"; +NSString *kIgnoreMediaKeysDefaultsKey = @"SPIgnoreMediaKeys"; + -(void)mediaKeyAppListChanged; @@ -247,7 +283,6 @@ NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMe Boolean same; OSErr err = SameProcess(&mySerial, &topSerial, &same); [self setShouldInterceptMediaKeyEvents:(err == noErr && same)]; - } -(void)appIsNowFrontmost:(ProcessSerialNumber)psn; { @@ -301,7 +336,6 @@ static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef &deadPSN ); - [self appTerminated:deadPSN]; return CallNextEventHandler(nextHandler, evt); }