PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 3ms RepoModel.GetById 38ms app.codeStats 0ms

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