Added ITDebugLogs to MainController and PreferencesController.
[MenuTunes.git] / MainController.m
1 #import "MainController.h"
2 #import "MenuController.h"
3 #import "PreferencesController.h"
4 #import <ITKit/ITHotKeyCenter.h>
5 #import <ITKit/ITHotKey.h>
6 #import <ITKit/ITKeyCombo.h>
7 #import "StatusWindowController.h"
8 #import "StatusItemHack.h"
9
10 @interface MainController(Private)
11 - (ITMTRemote *)loadRemote;
12 - (void)timerUpdate;
13 - (void)setLatestSongIdentifier:(NSString *)newIdentifier;
14 - (void)showCurrentTrackInfo;
15 - (void)applicationLaunched:(NSNotification *)note;
16 - (void)applicationTerminated:(NSNotification *)note;
17 @end
18
19 static MainController *sharedController;
20
21 @implementation MainController
22
23 + (MainController *)sharedController
24 {
25     return sharedController;
26 }
27
28 /*************************************************************************/
29 #pragma mark -
30 #pragma mark INITIALIZATION/DEALLOCATION METHODS
31 /*************************************************************************/
32
33 - (id)init
34 {
35     if ( ( self = [super init] ) ) {
36         sharedController = self;
37         
38         remoteArray = [[NSMutableArray alloc] initWithCapacity:1];
39         statusWindowController = [[StatusWindowController alloc] init];
40         menuController = [[MenuController alloc] init];
41         df = [[NSUserDefaults standardUserDefaults] retain];
42     }
43     return self;
44 }
45
46 - (void)applicationDidFinishLaunching:(NSNotification *)note
47 {
48     //Turn on debug mode if needed
49     if ([df boolForKey:@"ITDebugMode"]) {
50         SetITDebugMode(YES);
51     }
52     
53     currentRemote = [self loadRemote];
54     [currentRemote begin];
55     
56     //Setup for notification of the remote player launching or quitting
57     [[[NSWorkspace sharedWorkspace] notificationCenter]
58             addObserver:self
59             selector:@selector(applicationTerminated:)
60             name:NSWorkspaceDidTerminateApplicationNotification
61             object:nil];
62     
63     [[[NSWorkspace sharedWorkspace] notificationCenter]
64             addObserver:self
65             selector:@selector(applicationLaunched:)
66             name:NSWorkspaceDidLaunchApplicationNotification
67             object:nil];
68     
69     if ( ! [df objectForKey:@"menu"] ) {  // If this is nil, defaults have never been registered.
70         [[PreferencesController sharedPrefs] registerDefaults];
71     }
72     
73     [StatusItemHack install];
74     statusItem = [[ITStatusItem alloc]
75             initWithStatusBar:[NSStatusBar systemStatusBar]
76             withLength:NSSquareStatusItemLength];
77     
78     if ([currentRemote playerRunningState] == ITMTRemotePlayerRunning) {
79         [self applicationLaunched:nil];
80     } else {
81         if ([df boolForKey:@"LaunchPlayerWithMT"])
82             [self showPlayer];
83         else
84             [self applicationTerminated:nil];
85     }
86     
87     [statusItem setImage:[NSImage imageNamed:@"MenuNormal"]];
88     [statusItem setAlternateImage:[NSImage imageNamed:@"MenuInverted"]];
89 }
90
91 - (ITMTRemote *)loadRemote
92 {
93     NSString *folderPath = [[NSBundle mainBundle] builtInPlugInsPath];
94     ITDebugLog(@"Gathering remotes.");
95     if (folderPath) {
96         NSArray      *bundlePathList = [NSBundle pathsForResourcesOfType:@"remote" inDirectory:folderPath];
97         NSEnumerator *enumerator     = [bundlePathList objectEnumerator];
98         NSString     *bundlePath;
99
100         while ( (bundlePath = [enumerator nextObject]) ) {
101             NSBundle* remoteBundle = [NSBundle bundleWithPath:bundlePath];
102
103             if (remoteBundle) {
104                 Class remoteClass = [remoteBundle principalClass];
105
106                 if ([remoteClass conformsToProtocol:@protocol(ITMTRemote)] &&
107                     [remoteClass isKindOfClass:[NSObject class]]) {
108                     id remote = [remoteClass remote];
109                     ITDebugLog(@"Adding remote at path %@", bundlePath);
110                     [remoteArray addObject:remote];
111                 }
112             }
113         }
114
115 //      if ( [remoteArray count] > 0 ) {  // UNCOMMENT WHEN WE HAVE > 1 PLUGIN
116 //          if ( [remoteArray count] > 1 ) {
117 //              [remoteArray sortUsingSelector:@selector(sortAlpha:)];
118 //          }
119 //          [self loadModuleAccessUI]; //Comment out this line to disable remote visibility
120 //      }
121     }
122 //  NSLog(@"%@", [remoteArray objectAtIndex:0]);  //DEBUG
123     return [remoteArray objectAtIndex:0];
124 }
125
126 /*************************************************************************/
127 #pragma mark -
128 #pragma mark INSTANCE METHODS
129 /*************************************************************************/
130
131 /*- (void)startTimerInNewThread
132 {
133     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
134     NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
135     refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5
136                              target:self
137                              selector:@selector(timerUpdate)
138                              userInfo:nil
139                              repeats:YES] retain];
140     [runLoop run];
141     ITDebugLog(@"Timer started.");
142     [pool release];
143 }*/
144
145 - (BOOL)songIsPlaying
146 {
147     return ( ! ([[currentRemote playerStateUniqueIdentifier] isEqualToString:@"0-0"]) );
148 }
149
150 - (BOOL)radioIsPlaying
151 {
152     return ( [currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist );
153 }
154
155 - (BOOL)songChanged
156 {
157     return ( ! [[currentRemote playerStateUniqueIdentifier] isEqualToString:_latestSongIdentifier] );
158 }
159
160 - (NSString *)latestSongIdentifier
161 {
162     return _latestSongIdentifier;
163 }
164
165 - (void)setLatestSongIdentifier:(NSString *)newIdentifier
166 {
167     ITDebugLog(@"Setting latest song identifier to %@", newIdentifier);
168     [_latestSongIdentifier autorelease];
169     _latestSongIdentifier = [newIdentifier copy];
170 }
171
172 - (void)timerUpdate
173 {
174     if ( [self songChanged] ) {
175         ITDebugLog(@"The song changed.");
176         [self setLatestSongIdentifier:[currentRemote playerStateUniqueIdentifier]];
177         latestPlaylistClass = [currentRemote currentPlaylistClass];
178         [menuController rebuildSubmenus];
179
180         if ( [df boolForKey:@"showSongInfoOnChange"] ) {
181 //            [self performSelector:@selector(showCurrentTrackInfo) withObject:nil afterDelay:0.0];
182         }
183     }
184 }
185
186 - (void)menuClicked
187 {
188     ITDebugLog(@"Menu clicked.");
189     if ([currentRemote playerRunningState] == ITMTRemotePlayerRunning) {
190         [statusItem setMenu:[menuController menu]];
191     } else {
192         [statusItem setMenu:[menuController menuForNoPlayer]];
193     }
194 }
195
196 //
197 //
198 // Menu Selectors
199 //
200 //
201
202 - (void)playPause
203 {
204     ITMTRemotePlayerPlayingState state = [currentRemote playerPlayingState];
205     ITDebugLog(@"Play/Pause toggled");
206     if (state == ITMTRemotePlayerPlaying) {
207         [currentRemote pause];
208     } else if ((state == ITMTRemotePlayerForwarding) || (state == ITMTRemotePlayerRewinding)) {
209         [currentRemote pause];
210         [currentRemote play];
211     } else {
212         [currentRemote play];
213     }
214     [self timerUpdate];
215 }
216
217 - (void)nextSong
218 {
219     ITDebugLog(@"Going to next song.");
220     [currentRemote goToNextSong];
221     [self timerUpdate];
222 }
223
224 - (void)prevSong
225 {
226     ITDebugLog(@"Going to previous song.");
227     [currentRemote goToPreviousSong];
228     [self timerUpdate];
229 }
230
231 - (void)fastForward
232 {
233     ITDebugLog(@"Fast forwarding.");
234     [currentRemote forward];
235     [self timerUpdate];
236 }
237
238 - (void)rewind
239 {
240     ITDebugLog(@"Rewinding.");
241     [currentRemote rewind];
242     [self timerUpdate];
243 }
244
245 - (void)selectPlaylistAtIndex:(int)index
246 {
247     ITDebugLog(@"Selecting playlist %i", index);
248     [currentRemote switchToPlaylistAtIndex:index];
249     [self timerUpdate];
250 }
251
252 - (void)selectSongAtIndex:(int)index
253 {
254     ITDebugLog(@"Selecting song %i", index);
255     [currentRemote switchToSongAtIndex:index];
256     [self timerUpdate];
257 }
258
259 - (void)selectSongRating:(int)rating
260 {
261     ITDebugLog(@"Selecting song rating %i", rating);
262     [currentRemote setCurrentSongRating:(float)rating / 100.0];
263     [self timerUpdate];
264 }
265
266 - (void)selectEQPresetAtIndex:(int)index
267 {
268     ITDebugLog(@"Selecting EQ preset %i", index);
269     [currentRemote switchToEQAtIndex:index];
270     [self timerUpdate];
271 }
272
273 - (void)showPlayer
274 {
275     ITDebugLog(@"Beginning show player.");
276     if ( ( playerRunningState == ITMTRemotePlayerRunning) ) {
277         ITDebugLog(@"Showing player interface.");
278         [currentRemote showPrimaryInterface];
279     } else {
280         ITDebugLog(@"Launching player.");
281         if (![[NSWorkspace sharedWorkspace] launchApplication:[currentRemote playerFullName]]) {
282             ITDebugLog(@"Error Launching Player");
283         }
284     }
285     ITDebugLog(@"Finished show player.");
286 }
287
288 - (void)showPreferences
289 {
290     ITDebugLog(@"Show preferences.");
291     [[PreferencesController sharedPrefs] setController:self];
292     [[PreferencesController sharedPrefs] showPrefsWindow:self];
293 }
294
295 - (void)quitMenuTunes
296 {
297     ITDebugLog(@"Quitting MenuTunes.");
298     [NSApp terminate:self];
299 }
300
301 //
302 //
303
304 - (void)closePreferences
305 {
306     ITDebugLog(@"Preferences closed.");
307     if ( ( playerRunningState == ITMTRemotePlayerRunning) ) {
308         [self setupHotKeys];
309     }
310 }
311
312 - (ITMTRemote *)currentRemote
313 {
314     return currentRemote;
315 }
316
317 //
318 //
319 // Hot key setup
320 //
321 //
322
323 - (void)clearHotKeys
324 {
325     NSEnumerator *hotKeyEnumerator = [[[ITHotKeyCenter sharedCenter] allHotKeys] objectEnumerator];
326     ITHotKey *nextHotKey;
327     ITDebugLog(@"Clearing hot keys.");
328     while ( (nextHotKey = [hotKeyEnumerator nextObject]) ) {
329         [[ITHotKeyCenter sharedCenter] unregisterHotKey:nextHotKey];
330     }
331     ITDebugLog(@"Done clearing hot keys.");
332 }
333
334 - (void)setupHotKeys
335 {
336     ITHotKey *hotKey;
337     ITDebugLog(@"Setting up hot keys.");
338     if ([df objectForKey:@"PlayPause"] != nil) {
339         ITDebugLog(@"Setting up play pause hot key.");
340         hotKey = [[ITHotKey alloc] init];
341         [hotKey setName:@"PlayPause"];
342         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"PlayPause"]]];
343         [hotKey setTarget:self];
344         [hotKey setAction:@selector(playPause)];
345         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
346     }
347     
348     if ([df objectForKey:@"NextTrack"] != nil) {
349         ITDebugLog(@"Setting up next track hot key.");
350         hotKey = [[ITHotKey alloc] init];
351         [hotKey setName:@"NextTrack"];
352         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"NextTrack"]]];
353         [hotKey setTarget:self];
354         [hotKey setAction:@selector(nextSong)];
355         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
356     }
357     
358     if ([df objectForKey:@"PrevTrack"] != nil) {
359         ITDebugLog(@"Setting up previous track hot key.");
360         hotKey = [[ITHotKey alloc] init];
361         [hotKey setName:@"PrevTrack"];
362         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"PrevTrack"]]];
363         [hotKey setTarget:self];
364         [hotKey setAction:@selector(prevSong)];
365         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
366     }
367     
368     if ([df objectForKey:@"ShowPlayer"] != nil) {
369         ITDebugLog(@"Setting up show player hot key.");
370         hotKey = [[ITHotKey alloc] init];
371         [hotKey setName:@"ShowPlayer"];
372         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"ShowPlayer"]]];
373         [hotKey setTarget:self];
374         [hotKey setAction:@selector(showPlayer)];
375         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
376     }
377     
378     if ([df objectForKey:@"TrackInfo"] != nil) {
379         ITDebugLog(@"Setting up track info hot key.");
380         hotKey = [[ITHotKey alloc] init];
381         [hotKey setName:@"TrackInfo"];
382         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"TrackInfo"]]];
383         [hotKey setTarget:self];
384         [hotKey setAction:@selector(showCurrentTrackInfo)];
385         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
386     }
387     
388     if ([df objectForKey:@"UpcomingSongs"] != nil) {
389         ITDebugLog(@"Setting up upcoming songs hot key.");
390         hotKey = [[ITHotKey alloc] init];
391         [hotKey setName:@"UpcomingSongs"];
392         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"UpcomingSongs"]]];
393         [hotKey setTarget:self];
394         [hotKey setAction:@selector(showUpcomingSongs)];
395         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
396     }
397     
398     if ([df objectForKey:@"ToggleLoop"] != nil) {
399         ITDebugLog(@"Setting up toggle loop hot key.");
400         hotKey = [[ITHotKey alloc] init];
401         [hotKey setName:@"ToggleLoop"];
402         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"ToggleLoop"]]];
403         [hotKey setTarget:self];
404         [hotKey setAction:@selector(toggleLoop)];
405         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
406     }
407     
408     if ([df objectForKey:@"ToggleShuffle"] != nil) {
409         ITDebugLog(@"Setting up toggle shuffle hot key.");
410         hotKey = [[ITHotKey alloc] init];
411         [hotKey setName:@"ToggleShuffle"];
412         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"ToggleShuffle"]]];
413         [hotKey setTarget:self];
414         [hotKey setAction:@selector(toggleShuffle)];
415         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
416     }
417     
418     if ([df objectForKey:@"IncrementVolume"] != nil) {
419         ITDebugLog(@"Setting up increment volume hot key.");
420         hotKey = [[ITHotKey alloc] init];
421         [hotKey setName:@"IncrementVolume"];
422         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"IncrementVolume"]]];
423         [hotKey setTarget:self];
424         [hotKey setAction:@selector(incrementVolume)];
425         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
426     }
427     
428     if ([df objectForKey:@"DecrementVolume"] != nil) {
429         ITDebugLog(@"Setting up decrement volume hot key.");
430         hotKey = [[ITHotKey alloc] init];
431         [hotKey setName:@"DecrementVolume"];
432         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"DecrementVolume"]]];
433         [hotKey setTarget:self];
434         [hotKey setAction:@selector(decrementVolume)];
435         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
436     }
437     
438     if ([df objectForKey:@"IncrementRating"] != nil) {
439         ITDebugLog(@"Setting up increment rating hot key.");
440         hotKey = [[ITHotKey alloc] init];
441         [hotKey setName:@"IncrementRating"];
442         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"IncrementRating"]]];
443         [hotKey setTarget:self];
444         [hotKey setAction:@selector(incrementRating)];
445         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
446     }
447     
448     if ([df objectForKey:@"DecrementRating"] != nil) {
449         ITDebugLog(@"Setting up decrement rating hot key.");
450         hotKey = [[ITHotKey alloc] init];
451         [hotKey setName:@"DecrementRating"];
452         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"DecrementRating"]]];
453         [hotKey setTarget:self];
454         [hotKey setAction:@selector(decrementRating)];
455         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
456     }
457     ITDebugLog(@"Finished setting up hot keys.");
458 }
459
460 - (void)showCurrentTrackInfo
461 {
462     ITMTRemotePlayerSource  source      = [currentRemote currentSource];
463     NSString               *title       = [currentRemote currentSongTitle];
464     NSString               *album       = nil;
465     NSString               *artist      = nil;
466     NSString               *time        = nil;
467     int                     trackNumber = 0;
468     int                     trackTotal  = 0;
469     int                     rating      = -1;
470     ITDebugLog(@"Showing track info status window.");
471     if ( title ) {
472
473         if ( [df boolForKey:@"showAlbum"] ) {
474             album = [currentRemote currentSongAlbum];
475         }
476
477         if ( [df boolForKey:@"showArtist"] ) {
478             artist = [currentRemote currentSongArtist];
479         }
480
481         if ( [df boolForKey:@"showTime"] ) {
482             time = [currentRemote currentSongLength];
483         }
484
485         if ( [df boolForKey:@"showNumber"] ) {
486             trackNumber = [currentRemote currentSongTrack];
487             trackTotal  = [currentRemote currentAlbumTrackCount];
488         }
489
490         if ( [df boolForKey:@"showRating"] ) {
491             rating = ( [currentRemote currentSongRating] * 5 );
492         }
493         
494     } else {
495         title = NSLocalizedString(@"noSongPlaying", @"No song is playing.");
496     }
497
498     [statusWindowController showSongInfoWindowWithSource:source
499                                                    title:title
500                                                    album:album
501                                                   artist:artist
502                                                     time:time
503                                              trackNumber:trackNumber
504                                               trackTotal:trackTotal
505                                                   rating:rating];
506 }
507
508 - (void)showUpcomingSongs
509 {
510     int curPlaylist = [currentRemote currentPlaylistIndex];
511     int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:curPlaylist];
512     ITDebugLog(@"Showing upcoming songs status window.");
513     if (numSongs > 0) {
514         NSMutableArray *songList = [NSMutableArray arrayWithCapacity:5];
515         int numSongsInAdvance = [df integerForKey:@"SongsInAdvance"];
516         int curTrack = [currentRemote currentSongIndex];
517         int i;
518
519         for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
520             if (i <= numSongs) {
521                 [songList addObject:[currentRemote songTitleAtIndex:i]];
522             }
523         }
524         
525         [statusWindowController showUpcomingSongsWindowWithTitles:songList];
526         
527     } else {
528         [statusWindowController showUpcomingSongsWindowWithTitles:[NSArray arrayWithObject:NSLocalizedString(@"noUpcomingSongs", @"No upcoming songs.")]];
529     }
530 }
531
532 - (void)incrementVolume
533 {
534     float volume  = [currentRemote volume];
535     float dispVol = volume;
536     ITDebugLog(@"Incrementing volume.");
537     volume  += 0.110;
538     dispVol += 0.100;
539     
540     if (volume > 1.0) {
541         volume  = 1.0;
542         dispVol = 1.0;
543     }
544
545     ITDebugLog(@"Setting volume to %f", volume);
546     [currentRemote setVolume:volume];
547
548     // Show volume status window
549     [statusWindowController showVolumeWindowWithLevel:dispVol];
550 }
551
552 - (void)decrementVolume
553 {
554     float volume  = [currentRemote volume];
555     float dispVol = volume;
556     ITDebugLog(@"Decrementing volume.");
557     volume  -= 0.090;
558     dispVol -= 0.100;
559
560     if (volume < 0.0) {
561         volume  = 0.0;
562         dispVol = 0.0;
563     }
564     
565     ITDebugLog(@"Setting volume to %f", volume);
566     [currentRemote setVolume:volume];
567     
568     //Show volume status window
569     [statusWindowController showVolumeWindowWithLevel:dispVol];
570 }
571
572 - (void)incrementRating
573 {
574     float rating = [currentRemote currentSongRating];
575     ITDebugLog(@"Incrementing rating.");
576     rating += 0.2;
577     if (rating > 1.0) {
578         rating = 1.0;
579     }
580     ITDebugLog(@"Setting rating to %f", rating);
581     [currentRemote setCurrentSongRating:rating];
582     
583     //Show rating status window
584     [statusWindowController showRatingWindowWithRating:rating];
585 }
586
587 - (void)decrementRating
588 {
589     float rating = [currentRemote currentSongRating];
590     ITDebugLog(@"Decrementing rating.");
591     rating -= 0.2;
592     if (rating < 0.0) {
593         rating = 0.0;
594     }
595     ITDebugLog(@"Setting rating to %f", rating);
596     [currentRemote setCurrentSongRating:rating];
597     
598     //Show rating status window
599     [statusWindowController showRatingWindowWithRating:rating];
600 }
601
602 - (void)toggleLoop
603 {
604     ITMTRemotePlayerRepeatMode repeatMode = [currentRemote repeatMode];
605     ITDebugLog(@"Toggling repeat mode.");
606     switch (repeatMode) {
607         case ITMTRemotePlayerRepeatOff:
608             repeatMode = ITMTRemotePlayerRepeatAll;
609         break;
610         case ITMTRemotePlayerRepeatAll:
611             repeatMode = ITMTRemotePlayerRepeatOne;
612         break;
613         case ITMTRemotePlayerRepeatOne:
614             repeatMode = ITMTRemotePlayerRepeatOff;
615         break;
616     }
617     ITDebugLog(@"Setting repeat mode to %i", repeatMode);
618     [currentRemote setRepeatMode:repeatMode];
619     
620     //Show loop status window
621     [statusWindowController showRepeatWindowWithMode:repeatMode];
622 }
623
624 - (void)toggleShuffle
625 {
626     bool newShuffleEnabled = ![currentRemote shuffleEnabled];
627     ITDebugLog(@"Toggling shuffle mode.");
628     [currentRemote setShuffleEnabled:newShuffleEnabled];
629     //Show shuffle status window
630     ITDebugLog(@"Setting shuffle mode to %i", newShuffleEnabled);
631     [statusWindowController showRepeatWindowWithMode:newShuffleEnabled];
632 }
633
634 /*************************************************************************/
635 #pragma mark -
636 #pragma mark WORKSPACE NOTIFICATION HANDLERS
637 /*************************************************************************/
638
639 - (void)applicationLaunched:(NSNotification *)note
640 {
641     if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) {
642         ITDebugLog(@"Remote application launched.");
643         [currentRemote begin];
644         [self setLatestSongIdentifier:@""];
645         [self timerUpdate];
646         refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5
647                              target:self
648                              selector:@selector(timerUpdate)
649                              userInfo:nil
650                              repeats:YES] retain];
651         //[NSThread detachNewThreadSelector:@selector(startTimerInNewThread) toTarget:self withObject:nil];
652         [self setupHotKeys];
653         playerRunningState = ITMTRemotePlayerRunning;
654     }
655 }
656
657  - (void)applicationTerminated:(NSNotification *)note
658  {
659      if (!note || [[[note userInfo] objectForKey:@"NSApplicationName"] isEqualToString:[currentRemote playerFullName]]) {
660         ITDebugLog(@"Remote application terminated.");
661         [currentRemote halt];
662         [refreshTimer invalidate];
663         [refreshTimer release];
664         refreshTimer = nil;
665         [self clearHotKeys];
666         playerRunningState = ITMTRemotePlayerNotRunning;
667      }
668  }
669
670
671 /*************************************************************************/
672 #pragma mark -
673 #pragma mark NSApplication DELEGATE METHODS
674 /*************************************************************************/
675
676 - (void)applicationWillTerminate:(NSNotification *)note
677 {
678     [self clearHotKeys];
679     [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
680 }
681
682
683 /*************************************************************************/
684 #pragma mark -
685 #pragma mark DEALLOCATION METHOD
686 /*************************************************************************/
687
688 - (void)dealloc
689 {
690     [self applicationTerminated:nil];
691     [statusItem release];
692     [statusWindowController release];
693     [menuController release];
694     [super dealloc];
695 }
696
697
698 @end