/src/mac/tomahawkapp_mac.mm

http://github.com/tomahawk-player/tomahawk · Objective C++ · 303 lines · 213 code · 55 blank · 35 comment · 21 complexity · def141860319e072c3e7da9a11b96ac6 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
  4. *
  5. * Tomahawk is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Tomahawk is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "TomahawkApp_Mac.h"
  19. #include "MacDelegate.h"
  20. #include "MacShortcutHandler.h"
  21. #include "config.h"
  22. #include "TomahawkWindow.h"
  23. #include "audio/AudioEngine.h"
  24. #import <AppKit/NSApplication.h>
  25. #import <Foundation/NSAutoreleasePool.h>
  26. #import <Foundation/NSBundle.h>
  27. #import <Foundation/NSError.h>
  28. #import <Foundation/NSFileManager.h>
  29. #import <Foundation/NSPathUtilities.h>
  30. #import <Foundation/NSThread.h>
  31. #import <Foundation/NSTimer.h>
  32. #import <Foundation/NSAppleEventManager.h>
  33. #import <Foundation/NSURL.h>
  34. #import <AppKit/NSEvent.h>
  35. #import <AppKit/NSNibDeclarations.h>
  36. #ifdef HAVE_SPARKLE
  37. #import <Sparkle/SUUpdater.h>
  38. #endif
  39. #include <QDebug>
  40. #include <QApplication>
  41. #include <QObject>
  42. #include <QMetaObject>
  43. @interface MacApplication :NSApplication {
  44. AppDelegate* delegate_;
  45. Tomahawk::MacShortcutHandler* shortcut_handler_;
  46. Tomahawk::PlatformInterface* application_handler_;
  47. }
  48. - (Tomahawk::MacShortcutHandler*) shortcutHandler;
  49. - (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler;
  50. - (Tomahawk::PlatformInterface*) application_handler;
  51. - (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler;
  52. #ifdef HAVE_SPARKLE
  53. // SUUpdaterDelegate
  54. - (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update;
  55. #endif
  56. @end
  57. @implementation AppDelegate
  58. - (id) init {
  59. if ((self = [super init])) {
  60. application_handler_ = nil;
  61. shortcut_handler_ = nil;
  62. //dock_menu_ = nil;
  63. }
  64. return self;
  65. }
  66. - (id) initWithHandler: (Tomahawk::PlatformInterface*)handler {
  67. application_handler_ = handler;
  68. // Register defaults for the whitelist of apps that want to use media keys
  69. [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
  70. [SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], @"SPApplicationsNeedingMediaKeys",
  71. nil]];
  72. return self;
  73. }
  74. - (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag {
  75. if (application_handler_) {
  76. application_handler_->activate();
  77. }
  78. return YES;
  79. }
  80. - (void) setDockMenu: (NSMenu*)menu {
  81. dock_menu_ = menu;
  82. }
  83. - (NSMenu*) applicationDockMenu: (NSApplication*)sender {
  84. return dock_menu_;
  85. }
  86. - (Tomahawk::MacShortcutHandler*) shortcutHandler {
  87. return shortcut_handler_;
  88. }
  89. - (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler {
  90. // should be the same as MacApplication's
  91. shortcut_handler_ = handler;
  92. }
  93. - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  94. key_tap_ = [[SPMediaKeyTap alloc] initWithDelegate:self];
  95. if([SPMediaKeyTap usesGlobalMediaKeyTap])
  96. [key_tap_ startWatchingMediaKeys];
  97. else
  98. qWarning()<<"Media key monitoring disabled";
  99. }
  100. - (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event {
  101. NSAssert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys, @"Unexpected NSEvent in mediaKeyTap:receivedMediaKeyEvent:");
  102. int key_code = (([event data1] & 0xFFFF0000) >> 16);
  103. int key_flags = ([event data1] & 0x0000FFFF);
  104. BOOL key_is_pressed = (((key_flags & 0xFF00) >> 8)) == 0xA;
  105. // not used. keep just in case
  106. // int key_repeat = (key_flags & 0x1);
  107. if (!shortcut_handler_) {
  108. qWarning() << "No shortcut handler when we get a media key event...";
  109. return;
  110. }
  111. if (key_is_pressed) {
  112. shortcut_handler_->macMediaKeyPressed(key_code);
  113. }
  114. }
  115. - (BOOL) application: (NSApplication*)app openFile:(NSString*)filename {
  116. if (application_handler_->loadUrl(QString::fromUtf8([filename UTF8String]))) {
  117. return YES;
  118. }
  119. return NO;
  120. }
  121. - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender {
  122. return NSTerminateNow;
  123. }
  124. @end
  125. @implementation MacApplication
  126. - (id) init {
  127. if ((self = [super init])) {
  128. [self setShortcutHandler:nil];
  129. [self setApplicationHandler:nil];
  130. NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
  131. [em
  132. setEventHandler:self
  133. andSelector:@selector(getUrl:withReplyEvent:)
  134. forEventClass:kInternetEventClass
  135. andEventID:kAEGetURL];
  136. [em
  137. setEventHandler:self
  138. andSelector:@selector(getUrl:withReplyEvent:)
  139. forEventClass:'WWW!'
  140. andEventID:'OURL'];
  141. NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
  142. OSStatus httpResult = LSSetDefaultHandlerForURLScheme((CFStringRef)@"tomahawk", (CFStringRef)bundleID);
  143. Q_UNUSED(httpResult);
  144. //TODO: Check httpResult and httpsResult for errors
  145. }
  146. return self;
  147. }
  148. - (Tomahawk::MacShortcutHandler*) shortcutHandler {
  149. return shortcut_handler_;
  150. }
  151. - (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler {
  152. // should be the same as AppDelegate's
  153. shortcut_handler_ = handler;
  154. }
  155. - (Tomahawk::PlatformInterface*) application_handler {
  156. return application_handler_;
  157. }
  158. - (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler {
  159. delegate_ = [[AppDelegate alloc] initWithHandler:handler];
  160. // App-shortcut-handler set before delegate is set.
  161. // this makes sure the delegate's shortcut_handler is set
  162. [delegate_ setShortcutHandler:shortcut_handler_];
  163. [self setDelegate:delegate_];
  164. }
  165. -(void) sendEvent: (NSEvent*)event {
  166. // If event tap is not installed, handle events that reach the app instead
  167. BOOL shouldHandleMediaKeyEventLocally = ![SPMediaKeyTap usesGlobalMediaKeyTap];
  168. if(shouldHandleMediaKeyEventLocally && [event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys) {
  169. [(id)[self delegate] mediaKeyTap: nil receivedMediaKeyEvent: event];
  170. }
  171. [super sendEvent: event];
  172. }
  173. #ifdef HAVE_SPARKLE
  174. - (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update
  175. {
  176. tLog() << "NSApp in willInstallUpdate, deleting Phonon objects";
  177. AudioEngine::instance()->stop();
  178. delete AudioEngine::instance();
  179. }
  180. #endif
  181. @end
  182. void Tomahawk::macMain() {
  183. [[NSAutoreleasePool alloc] init];
  184. // Creates and sets the magic global variable so QApplication will find it.
  185. [MacApplication sharedApplication];
  186. #ifdef HAVE_SPARKLE
  187. // Creates and sets the magic global variable for Sparkle.
  188. [[SUUpdater sharedUpdater] setDelegate: NSApp];
  189. #endif
  190. }
  191. void Tomahawk::setShortcutHandler(Tomahawk::MacShortcutHandler* handler) {
  192. [NSApp setShortcutHandler: handler];
  193. }
  194. void Tomahawk::setApplicationHandler(Tomahawk::PlatformInterface* handler) {
  195. [NSApp setApplicationHandler: handler];
  196. }
  197. void Tomahawk::checkForUpdates() {
  198. #ifdef HAVE_SPARKLE
  199. [[SUUpdater sharedUpdater] checkForUpdates: NSApp];
  200. #endif
  201. }
  202. #ifdef LION
  203. #define SET_LION_FULLSCREEN NSWindowCollectionBehaviorFullScreenPrimary
  204. #define LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE NSWindowWillEnterFullScreenNotification
  205. #define LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE NSWindowDidExitFullScreenNotification
  206. #else
  207. #define SET_LION_FULLSCREEN (NSUInteger)(1 << 7) // Defined as NSWindowCollectionBehaviorFullScreenPrimary in lion's NSWindow.h
  208. #define LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE @"NSWindowWillEnterFullScreenNotification"
  209. #define LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE @"NSWindowDidExitFullScreenNotification"
  210. #endif
  211. void Tomahawk::enableFullscreen( QObject* receiver )
  212. {
  213. // We don't support anything below leopard, so if it's not [snow] leopard it must be lion
  214. // Can't check for lion as Qt 4.7 doesn't have the enum val, not checking for Unknown as it will be lion
  215. // on 4.8
  216. if ( QSysInfo::MacintoshVersion != QSysInfo::MV_SNOWLEOPARD &&
  217. QSysInfo::MacintoshVersion != QSysInfo::MV_LEOPARD )
  218. {
  219. qDebug() << "Enabling Lion Full-screeen";
  220. // Can't include TomahawkApp.h in a .mm file, pulls in InfoSystem.h which uses
  221. // the objc keyword 'id'
  222. foreach( QWidget* w, QApplication::topLevelWidgets() )
  223. {
  224. if ( qobject_cast< TomahawkWindow* >( w ) )
  225. {
  226. NSView *nsview = (NSView *)w->winId();
  227. NSWindow *nswindow = [nsview window];
  228. [nswindow setCollectionBehavior:SET_LION_FULLSCREEN];
  229. if ( !receiver )
  230. continue;
  231. [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE
  232. object:nswindow
  233. queue:nil
  234. usingBlock:^(NSNotification * note) {
  235. NSLog(@"Became Full Screen!");
  236. QMetaObject::invokeMethod( receiver, "fullScreenEntered", Qt::DirectConnection );
  237. }];
  238. [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE
  239. object:nswindow
  240. queue:nil
  241. usingBlock:^(NSNotification * note) {
  242. NSLog(@"Left Full Screen!");
  243. QMetaObject::invokeMethod( receiver, "fullScreenExited", Qt::DirectConnection );
  244. }];
  245. }
  246. }
  247. }
  248. }