diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bdd42b2e3..5484302ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -181,7 +181,7 @@ set(CLEMENTINE-LANGUAGES # OSD and DBus. if(APPLE) - set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} osd_mac.mm) + set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} osd_mac.mm mac_startup.mm) else(APPLE) if(WIN32) set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} osd_win.cpp) @@ -318,6 +318,7 @@ if (APPLE) ${GROWL} /System/Library/Frameworks/Carbon.framework /System/Library/Frameworks/Foundation.framework + /System/Library/Frameworks/AppKit.framework ) include_directories(${GROWL}/Headers) endif (APPLE) diff --git a/src/globalshortcuts/globalshortcuts.cpp b/src/globalshortcuts/globalshortcuts.cpp index 7e41ba84f..839e282a9 100644 --- a/src/globalshortcuts/globalshortcuts.cpp +++ b/src/globalshortcuts/globalshortcuts.cpp @@ -17,6 +17,8 @@ #include "globalshortcuts.h" #include "qxtglobalshortcut.h" +#include "mac_startup.h" + #include #ifdef QT_DBUS_LIB @@ -34,6 +36,10 @@ GlobalShortcuts::GlobalShortcuts(QObject *parent) } void GlobalShortcuts::Init() { +#ifdef Q_OS_DARWIN + mac::SetShortcutHandler(this); + return; +#endif if (RegisterGnome()) return; if (RegisterQxt()) return; } @@ -78,3 +84,10 @@ void GlobalShortcuts::GnomeMediaKeyPressed(const QString&, const QString& key) { if (key == "Next") emit Next(); if (key == "Previous") emit Previous(); } + +void GlobalShortcuts::MacMediaKeyPressed(const QString& key) { + if (key == "Play") emit PlayPause(); + // Stop doesn't exist on a mac keyboard. + if (key == "Next") emit Next(); + if (key == "Previous") emit Previous(); +} diff --git a/src/globalshortcuts/globalshortcuts.h b/src/globalshortcuts/globalshortcuts.h index a3895dd72..e31fa0a12 100644 --- a/src/globalshortcuts/globalshortcuts.h +++ b/src/globalshortcuts/globalshortcuts.h @@ -29,6 +29,8 @@ public: static const char* kGsdPath; static const char* kGsdInterface; + void MacMediaKeyPressed(const QString& key); + signals: void PlayPause(); void Stop(); diff --git a/src/mac_startup.h b/src/mac_startup.h new file mode 100644 index 000000000..561628b2f --- /dev/null +++ b/src/mac_startup.h @@ -0,0 +1,13 @@ +#ifndef MAC_STARTUP_H +#define MAC_STARTUP_H + +class GlobalShortcuts; + +namespace mac { + +void MacMain(); +void SetShortcutHandler(GlobalShortcuts* handler); + +} // namespace mac + +#endif diff --git a/src/mac_startup.mm b/src/mac_startup.mm new file mode 100644 index 000000000..c9d778e09 --- /dev/null +++ b/src/mac_startup.mm @@ -0,0 +1,87 @@ +#import +#import +#import + +#include "globalshortcuts/globalshortcuts.h" +#include "mac_startup.h" + +// Capture global media keys on Mac (Cocoa only!) +// See: http://www.rogueamoeba.com/utm/2007/09/29/apple-keyboard-media-key-event-handling/ + +@interface MacApplication :NSApplication { + GlobalShortcuts* handler_; +} + +- (GlobalShortcuts*) handler; +- (void) SetHandler: (GlobalShortcuts*)handler; + +-(void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat; +@end + +@implementation MacApplication + +- (id) init { + if ((self = [super init])) { + [self SetHandler:nil]; + } + return self; +} + +- (GlobalShortcuts*) handler { + return handler_; +} + +- (void) SetHandler: (GlobalShortcuts*)handler { + handler_ = handler; +} + +-(void) sendEvent: (NSEvent*)event { + if ([event type] == NSSystemDefined && [event subtype] == 8) { + int keycode = (([event data1] & 0xFFFF0000) >> 16); + int keyflags = ([event data1] & 0x0000FFFF); + int keystate = (((keyflags & 0xFF00) >> 8)) == 0xA; + int keyrepeat = (keyflags & 0x1); + + [self mediaKeyEvent: keycode state: keystate repeat: keyrepeat]; + } + + [super sendEvent: event]; +} + +-(void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat { + if (!handler_) { + return; + } + if (state == 0) { + switch (key) { + case NX_KEYTYPE_PLAY: + // Play pressed. + handler_->MacMediaKeyPressed("Play"); + break; + case NX_KEYTYPE_FAST: + // Next pressed. + handler_->MacMediaKeyPressed("Next"); + break; + case NX_KEYTYPE_REWIND: + handler_->MacMediaKeyPressed("Previous"); + break; + default: + break; + } + } +} + +@end + +namespace mac { + +void MacMain() { + // Creates and sets the magic global variable so QApplication will find it. + [MacApplication sharedApplication]; +} + +void SetShortcutHandler(GlobalShortcuts* handler) { + [NSApp SetHandler: handler]; +} + +} // namespace mac diff --git a/src/main.cpp b/src/main.cpp index d92312557..c1c756027 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,8 @@ # include "osd.h" #endif +#include "mac_startup.h" + // Load sqlite plugin on windows #ifdef WIN32 # include @@ -67,6 +69,12 @@ void LoadTranslation(const QString& prefix, const QString& path) { } int main(int argc, char *argv[]) { +#ifdef Q_OS_DARWIN + // Do Mac specific startup to get media keys working. + // This must go before QApplication initialisation. + mac::MacMain(); +#endif + QCoreApplication::setApplicationName("Clementine"); QCoreApplication::setApplicationVersion("0.2"); QCoreApplication::setOrganizationName("Clementine");