3 ¥ Make preferences window pretty
5 ¥ Apple Events! Apple Events! Apple Events!
9 #import "PreferencesController.h"
10 #import "HotKeyCenter.h"
11 #import "StatusWindowController.h"
13 @interface MenuTunes(Private)
14 - (void)registerDefaultsIfNeeded;
16 - (void)rebuildUpcomingSongsMenu;
17 - (void)rebuildPlaylistMenu;
18 - (void)rebuildEQPresetsMenu;
20 - (NSString *)runScriptAndReturnResult:(NSString *)script;
22 - (void)sendAEWithEventClass:(AEEventClass)eventClass andEventID:(AEEventID)eventID;
26 @implementation MenuTunes
28 /*************************************************************************/
30 #pragma mark INITIALIZATION METHODS
31 /*************************************************************************/
33 - (void)applicationDidFinishLaunching:(NSNotification *)note
35 asComponent = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);
37 [self registerDefaultsIfNeeded];
39 menu = [[NSMenu alloc] initWithTitle:@""];
40 iTunesPSN = [self iTunesPSN]; //Get PSN of iTunes if it's running
42 if (!((iTunesPSN.highLongOfPSN == kNoProcess) && (iTunesPSN.lowLongOfPSN == 0)))
45 refreshTimer = [NSTimer scheduledTimerWithTimeInterval:3.5
47 selector:@selector(timerUpdate)
53 menu = [[NSMenu alloc] initWithTitle:@""];
54 [[menu addItemWithTitle:@"Open iTunes" action:@selector(openiTunes:) keyEquivalent:@""] setTarget:self];
55 [[menu addItemWithTitle:@"Preferences" action:@selector(showPreferences:) keyEquivalent:@""] setTarget:self];
56 [[menu addItemWithTitle:@"Quit" action:@selector(quitMenuTunes:) keyEquivalent:@""] setTarget:self];
57 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(iTunesLaunched:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
61 statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
62 [[[statusItem _button] cell] setType:NSNullCellType];
63 [statusItem setImage:[NSImage imageNamed:@"menu"]];
64 [[statusItem _button] setAlternateImage:[NSImage imageNamed:@"selected_image"]];
65 [statusItem setHighlightMode:YES];
66 [statusItem setMenu:menu];
67 // Below line of code is for creating builds for Beta Testers
68 // [statusItem setToolTip:@"This Nontransferable Beta (Built on __DATE__) of iThink Software's MenuTunes is Registered to: Beta Tester (betatester@somedomain.com)."];
73 /*************************************************************************/
75 #pragma mark INSTANCE METHODS
76 /*************************************************************************/
78 - (void)registerDefaultsIfNeeded
80 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
81 if (![defaults objectForKey:@"menu"]) {
83 [NSArray arrayWithObjects:
96 @"Current Track Info",
100 if (![defaults objectForKey:@"showName"])
102 [defaults setBool:YES forKey:@"showName"];
105 if (![defaults objectForKey:@"showArtist"])
107 [defaults setBool:YES forKey:@"showArtist"];
110 if (![defaults objectForKey:@"showAlbum"])
112 [defaults setBool:NO forKey:@"showAlbum"];
115 if (![defaults objectForKey:@"showTime"])
117 [defaults setBool:NO forKey:@"showTime"];
121 //Recreate the status item menu
124 NSArray *myMenu = [[NSUserDefaults standardUserDefaults] arrayForKey:@"menu"];
128 didHaveAlbumName = ([[self runScriptAndReturnResult:@"return album of current track"] length] > 0);
129 didHaveArtistName = ([[self runScriptAndReturnResult:@"return artist of current track"] length] > 0);
132 while ([menu numberOfItems] > 0) {
133 [menu removeItemAtIndex:0];
136 playPauseMenuItem = nil;
137 upcomingSongsItem = nil;
139 [playlistMenu release];
145 for (i = 0; i < [myMenu count]; i++) {
146 NSString *item = [myMenu objectAtIndex:i];
147 if ([item isEqualToString:@"Play/Pause"]) {
148 playPauseMenuItem = [menu addItemWithTitle:@"Play"
149 action:@selector(playPause:)
151 [playPauseMenuItem setTarget:self];
152 } else if ([item isEqualToString:@"Next Track"]) {
153 [[menu addItemWithTitle:@"Next Track"
154 action:@selector(nextSong:)
155 keyEquivalent:@""] setTarget:self];
156 } else if ([item isEqualToString:@"Previous Track"]) {
157 [[menu addItemWithTitle:@"Previous Track"
158 action:@selector(prevSong:)
159 keyEquivalent:@""] setTarget:self];
160 } else if ([item isEqualToString:@"Fast Forward"]) {
161 [[menu addItemWithTitle:@"Fast Forward"
162 action:@selector(fastForward:)
163 keyEquivalent:@""] setTarget:self];
164 } else if ([item isEqualToString:@"Rewind"]) {
165 [[menu addItemWithTitle:@"Rewind"
166 action:@selector(rewind:)
167 keyEquivalent:@""] setTarget:self];
168 } else if ([item isEqualToString:@"Upcoming Songs"]) {
169 upcomingSongsItem = [menu addItemWithTitle:@"Upcoming Songs"
172 } else if ([item isEqualToString:@"Playlists"]) {
173 playlistItem = [menu addItemWithTitle:@"Playlists"
176 } else if ([item isEqualToString:@"EQ Presets"]) {
177 eqItem = [menu addItemWithTitle:@"EQ Presets"
180 } else if ([item isEqualToString:@"PreferencesÉ"]) {
181 [[menu addItemWithTitle:@"PreferencesÉ"
182 action:@selector(showPreferences:)
183 keyEquivalent:@""] setTarget:self];
184 } else if ([item isEqualToString:@"Quit"]) {
185 [[menu addItemWithTitle:@"Quit"
186 action:@selector(quitMenuTunes:)
187 keyEquivalent:@""] setTarget:self];
188 } else if ([item isEqualToString:@"Current Track Info"]) {
189 trackInfoIndex = [menu numberOfItems];
190 [menu addItemWithTitle:@"No Song"
193 } else if ([item isEqualToString:@"<separator>"]) {
194 [menu addItem:[NSMenuItem separatorItem]];
198 curTrackIndex = -1; //Force update of everything
199 [self timerUpdate]; //Updates dynamic info in the menu
205 //Updates the menu with current player state, song, and upcoming songs
208 NSMenuItem *menuItem;
209 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
211 if ((iTunesPSN.highLongOfPSN == kNoProcess) && (iTunesPSN.lowLongOfPSN == 0)) {
215 if (upcomingSongsItem) {
216 [self rebuildUpcomingSongsMenu];
219 [self rebuildPlaylistMenu];
222 [self rebuildEQPresetsMenu];
225 if (trackInfoIndex > -1)
227 NSString *curSongName, *curAlbumName = @"", *curArtistName = @"";
228 curSongName = [self runScriptAndReturnResult:@"return name of current track"];
230 if ([defaults boolForKey:@"showArtist"]) {
231 curAlbumName = [self runScriptAndReturnResult:@"return album of current track"];
234 if ([defaults boolForKey:@"showAlbum"]) {
235 curArtistName = [self runScriptAndReturnResult:@"return artist of current track"];
238 if ([curSongName length] > 0) {
239 int index = [menu indexOfItemWithTitle:@"Now Playing"];
242 if ([defaults boolForKey:@"showName"]) {
243 [menu removeItemAtIndex:index + 1];
245 if (didHaveAlbumName) {
246 [menu removeItemAtIndex:index + 1];
248 if (didHaveArtistName) {
249 [menu removeItemAtIndex:index + 1];
251 if ([defaults boolForKey:@"showTime"]) {
252 [menu removeItemAtIndex:index + 1];
255 if (!isPlayingRadio) {
256 if ([defaults boolForKey:@"showTime"]) {
257 menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", [self runScriptAndReturnResult:@"return time of current track"]]
260 [menu insertItem:menuItem atIndex:trackInfoIndex + 1];
264 if ([curArtistName length] > 0) {
265 menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curArtistName]
268 [menu insertItem:menuItem atIndex:trackInfoIndex + 1];
272 if ([curAlbumName length] > 0) {
273 menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curAlbumName]
276 [menu insertItem:menuItem atIndex:trackInfoIndex + 1];
280 menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curSongName]
283 [menu insertItem:menuItem atIndex:trackInfoIndex + 1];
287 menuItem = [[NSMenuItem alloc] initWithTitle:@"Now Playing" action:nil keyEquivalent:@""];
288 [menu removeItemAtIndex:[menu indexOfItemWithTitle:@"No Song"]];
289 [menu insertItem:menuItem atIndex:trackInfoIndex];
293 } else if ([menu indexOfItemWithTitle:@"No Song"] == -1) {
294 [menu removeItemAtIndex:trackInfoIndex];
296 if ([defaults boolForKey:@"showName"] == YES) {
297 [menu removeItemAtIndex:trackInfoIndex];
300 if ([defaults boolForKey:@"showTime"] == YES) {
301 [menu removeItemAtIndex:trackInfoIndex];
304 if (didHaveArtistName && [defaults boolForKey:@"showArtist"]) {
305 [menu removeItemAtIndex:trackInfoIndex];
308 if (didHaveAlbumName && [defaults boolForKey:@"showAlbum"]) {
309 [menu removeItemAtIndex:trackInfoIndex];
312 menuItem = [[NSMenuItem alloc] initWithTitle:@"No Song" action:nil keyEquivalent:@""];
313 [menu insertItem:menuItem atIndex:trackInfoIndex];
317 if ([defaults boolForKey:@"showArtist"]) {
318 didHaveAlbumName = (([curAlbumName length] > 0) ? YES : NO);
321 if ([defaults boolForKey:@"showAlbum"]) {
322 didHaveArtistName = (([curArtistName length] > 0) ? YES : NO);
327 //Rebuild the upcoming songs submenu. Can be improved a lot.
328 - (void)rebuildUpcomingSongsMenu
330 int numSongs = [[self runScriptAndReturnResult:@"return number of tracks in current playlist"] intValue];
331 int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
332 if (!isPlayingRadio) {
334 int curTrack = [[self runScriptAndReturnResult:@"return index of current track"] intValue];
337 [upcomingSongsMenu release];
338 upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
339 [upcomingSongsItem setSubmenu:upcomingSongsMenu];
340 [upcomingSongsItem setEnabled:YES];
342 for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
344 NSString *curSong = [self runScriptAndReturnResult:[NSString stringWithFormat:@"return name of track %i of current playlist", i]];
345 NSMenuItem *songItem;
346 songItem = [[NSMenuItem alloc] initWithTitle:curSong action:@selector(playTrack:) keyEquivalent:@""];
347 [songItem setTarget:self];
348 [songItem setRepresentedObject:[NSNumber numberWithInt:i]];
349 [upcomingSongsMenu addItem:songItem];
357 [upcomingSongsItem setSubmenu:nil];
358 [upcomingSongsItem setEnabled:NO];
362 - (void)rebuildPlaylistMenu
364 int numPlaylists = [[self runScriptAndReturnResult:@"return number of playlists"] intValue];
365 int i, curPlaylist = [[self runScriptAndReturnResult:@"return index of current playlist"] intValue];
372 if (playlistMenu && (numPlaylists == [playlistMenu numberOfItems]))
375 [playlistMenu release];
376 playlistMenu = [[NSMenu alloc] initWithTitle:@""];
378 for (i = 1; i <= numPlaylists; i++) {
379 NSString *playlistName = [self runScriptAndReturnResult:[NSString stringWithFormat:@"return name of playlist %i", i]];
380 NSMenuItem *tempItem;
381 tempItem = [[NSMenuItem alloc] initWithTitle:playlistName action:@selector(selectPlaylist:) keyEquivalent:@""];
382 [tempItem setTarget:self];
383 [tempItem setRepresentedObject:[NSNumber numberWithInt:i]];
384 [playlistMenu addItem:tempItem];
387 [playlistItem setSubmenu:playlistMenu];
390 [[playlistMenu itemAtIndex:curPlaylist - 1] setState:NSOnState];
394 //Build a menu with the list of all available EQ presets
395 - (void)rebuildEQPresetsMenu
397 int numSets = [[self runScriptAndReturnResult:@"return number of EQ presets"] intValue];
400 if (eqMenu && (numSets == [eqMenu numberOfItems]))
404 eqMenu = [[NSMenu alloc] initWithTitle:@""];
406 for (i = 1; i <= numSets; i++) {
407 NSString *setName = [self runScriptAndReturnResult:[NSString stringWithFormat:@"return name of EQ preset %i", i]];
408 NSMenuItem *tempItem;
409 tempItem = [[NSMenuItem alloc] initWithTitle:setName action:@selector(selectEQPreset:) keyEquivalent:@""];
410 [tempItem setTarget:self];
411 [tempItem setRepresentedObject:[NSNumber numberWithInt:i]];
412 [eqMenu addItem:tempItem];
415 [eqItem setSubmenu:eqMenu];
417 [[eqMenu itemAtIndex:[[self runScriptAndReturnResult:@"return index of current EQ preset"] intValue] - 1] setState:NSOnState];
422 [[HotKeyCenter sharedCenter] removeHotKey:@"PlayPause"];
423 [[HotKeyCenter sharedCenter] removeHotKey:@"NextTrack"];
424 [[HotKeyCenter sharedCenter] removeHotKey:@"PrevTrack"];
425 [[HotKeyCenter sharedCenter] removeHotKey:@"TrackInfo"];
426 [[HotKeyCenter sharedCenter] removeHotKey:@"UpcomingSongs"];
431 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
433 if ([defaults objectForKey:@"PlayPause"] != nil) {
434 [[HotKeyCenter sharedCenter] addHotKey:@"PlayPause"
435 combo:[defaults keyComboForKey:@"PlayPause"]
436 target:self action:@selector(playPause:)];
439 if ([defaults objectForKey:@"NextTrack"] != nil) {
440 [[HotKeyCenter sharedCenter] addHotKey:@"NextTrack"
441 combo:[defaults keyComboForKey:@"NextTrack"]
442 target:self action:@selector(nextSong:)];
445 if ([defaults objectForKey:@"PrevTrack"] != nil) {
446 [[HotKeyCenter sharedCenter] addHotKey:@"PrevTrack"
447 combo:[defaults keyComboForKey:@"PrevTrack"]
448 target:self action:@selector(prevSong:)];
451 if ([defaults objectForKey:@"TrackInfo"] != nil) {
452 [[HotKeyCenter sharedCenter] addHotKey:@"TrackInfo"
453 combo:[defaults keyComboForKey:@"TrackInfo"]
454 target:self action:@selector(showCurrentTrackInfo)];
457 if ([defaults objectForKey:@"UpcomingSongs"] != nil) {
458 [[HotKeyCenter sharedCenter] addHotKey:@"UpcomingSongs"
459 combo:[defaults keyComboForKey:@"UpcomingSongs"]
460 target:self action:@selector(showUpcomingSongs)];
464 //Runs an AppleScript and returns the result as an NSString after stripping quotes, if needed. It takes in script and automatically adds the tell iTunes and end tell statements.
465 - (NSString *)runScriptAndReturnResult:(NSString *)script
467 AEDesc scriptDesc, resultDesc;
472 script = [NSString stringWithFormat:@"tell application \"iTunes\"\n%@\nend tell", script];
474 AECreateDesc(typeChar, [script cString], [script cStringLength],
477 OSADoScript(asComponent, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
479 length = AEGetDescDataSize(&resultDesc);
480 buffer = malloc(length);
482 AEGetDescData(&resultDesc, buffer, length);
483 AEDisposeDesc(&scriptDesc);
484 AEDisposeDesc(&resultDesc);
485 result = [NSString stringWithCString:buffer length:length];
486 if ( (! [result isEqualToString:@""]) &&
487 ([result characterAtIndex:0] == '\"') &&
488 ([result characterAtIndex:[result length] - 1] == '\"') ) {
489 result = [result substringWithRange:NSMakeRange(1, [result length] - 2)];
496 //Called when the timer fires.
500 if (GetProcessPID(&iTunesPSN, &pid) == noErr) {
501 int trackPlayingIndex = [[self runScriptAndReturnResult:@"return index of current track"] intValue];
503 if (trackPlayingIndex != curTrackIndex) {
504 bool wasPlayingRadio = isPlayingRadio;
505 isPlayingRadio = [[self runScriptAndReturnResult:@"return class of current playlist"] isEqualToString:@"radio tuner playlist"];
506 if (isPlayingRadio && !wasPlayingRadio) {
508 for (i = 0; i < [playlistMenu numberOfItems]; i++)
510 [[playlistMenu itemAtIndex:i] setState:NSOffState];
513 if (wasPlayingRadio) {
514 NSMenuItem *temp = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
515 [menu insertItem:temp atIndex:trackInfoIndex + 1];
519 curTrackIndex = trackPlayingIndex;
523 int playlist = [[self runScriptAndReturnResult:@"return index of current playlist"] intValue];
524 if (playlist != curPlaylistIndex) {
525 bool wasPlayingRadio = isPlayingRadio;
526 isPlayingRadio = [[self runScriptAndReturnResult:@"return class of current playlist"] isEqualToString:@"radio tuner playlist"];
527 if (isPlayingRadio && !wasPlayingRadio) {
529 for (i = 0; i < [playlistMenu numberOfItems]; i++)
531 [[playlistMenu itemAtIndex:i] setState:NSOffState];
534 if (wasPlayingRadio) {
535 NSMenuItem *temp = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
536 [menu insertItem:temp atIndex:trackInfoIndex + 1];
540 curTrackIndex = trackPlayingIndex;
541 curPlaylistIndex = playlist;
544 //Update Play/Pause menu item
545 if (playPauseMenuItem){
546 if ([[self runScriptAndReturnResult:@"return player state"] isEqualToString:@"playing"]) {
547 [playPauseMenuItem setTitle:@"Pause"];
549 [playPauseMenuItem setTitle:@"Play"];
554 menu = [[NSMenu alloc] initWithTitle:@""];
555 [[menu addItemWithTitle:@"Open iTunes" action:@selector(openiTunes:) keyEquivalent:@""] setTarget:self];
556 [[menu addItemWithTitle:@"Preferences" action:@selector(showPreferences:) keyEquivalent:@""] setTarget:self];
557 [[menu addItemWithTitle:@"Quit" action:@selector(quitMenuTunes:) keyEquivalent:@""] setTarget:self];
558 [statusItem setMenu:menu];
560 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(iTunesLaunched:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
561 [refreshTimer invalidate];
567 - (void)iTunesLaunched:(NSNotification *)note
569 NSDictionary *info = [note userInfo];
571 iTunesPSN.highLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberHigh"] longValue];
572 iTunesPSN.lowLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberLow"] longValue];
575 refreshTimer = [NSTimer scheduledTimerWithTimeInterval:3.5 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
577 [self rebuildMenu]; //Rebuild the menu since no songs will be playing
578 [statusItem setMenu:menu]; //Set the menu back to the main one
579 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
582 //Return the PSN of iTunes, if it's running
583 - (ProcessSerialNumber)iTunesPSN
585 ProcessSerialNumber procNum;
586 procNum.highLongOfPSN = kNoProcess;
587 procNum.lowLongOfPSN = 0;
589 while ( (GetNextProcess(&procNum) == noErr) ) {
590 CFStringRef procName;
591 if ( (CopyProcessName(&procNum, &procName) == noErr) ) {
592 if ([(NSString *)procName isEqualToString:@"iTunes"]) {
595 [(NSString *)procName release];
601 //Send an AppleEvent with a given event ID
602 - (void)sendAEWithEventClass:(AEEventClass)eventClass
603 andEventID:(AEEventID)eventID
605 OSType iTunesType = 'hook';
606 AppleEvent event, reply;
608 AEBuildAppleEvent(eventClass, eventID, typeApplSignature, &iTunesType, sizeof(iTunesType), kAutoGenerateReturnID, kAnyTransactionID, &event, nil, "");
610 AESend(&event, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
611 AEDisposeDesc(&event);
612 AEDisposeDesc(&reply);
616 // Selectors - called from status item menu
619 - (void)playTrack:(id)sender
621 [self runScriptAndReturnResult:[NSString stringWithFormat:@"play track %i of current playlist", [[sender representedObject] intValue]]];
625 - (void)selectPlaylist:(id)sender
627 int playlist = [[sender representedObject] intValue];
628 if (!isPlayingRadio) {
629 int curPlaylist = [[self runScriptAndReturnResult:@"return index of current playlist"] intValue];
630 [[playlistMenu itemAtIndex:curPlaylist - 1] setState:NSOffState];
632 [self runScriptAndReturnResult:[NSString stringWithFormat:@"play playlist %i", playlist]];
633 [[playlistMenu itemAtIndex:playlist - 1] setState:NSOnState];
636 - (void)selectEQPreset:(id)sender
638 int curSet = [[self runScriptAndReturnResult:@"return index of current EQ preset"] intValue];
639 int item = [[sender representedObject] intValue];
640 [self runScriptAndReturnResult:[NSString stringWithFormat:@"set current EQ preset to EQ preset %i", item]];
641 [self runScriptAndReturnResult:@"set EQ enabled to 1"];
642 [[eqMenu itemAtIndex:curSet - 1] setState:NSOffState];
643 [[eqMenu itemAtIndex:item - 1] setState:NSOnState];
646 - (void)playPause:(id)sender
648 NSString *state = [self runScriptAndReturnResult:@"return player state"];
649 if ([state isEqualToString:@"playing"]) {
650 [self sendAEWithEventClass:'hook' andEventID:'Paus'];
651 [playPauseMenuItem setTitle:@"Play"];
652 } else if ([state isEqualToString:@"fast forwarding"] || [state
653 isEqualToString:@"rewinding"]) {
654 [self sendAEWithEventClass:'hook' andEventID:'Paus'];
655 [self sendAEWithEventClass:'hook' andEventID:'Play'];
657 [self sendAEWithEventClass:'hook' andEventID:'Play'];
658 [playPauseMenuItem setTitle:@"Pause"];
662 - (void)nextSong:(id)sender
664 [self sendAEWithEventClass:'hook' andEventID:'Next'];
667 - (void)prevSong:(id)sender
669 [self sendAEWithEventClass:'hook' andEventID:'Prev'];
672 - (void)fastForward:(id)sender
674 [self sendAEWithEventClass:'hook' andEventID:'Fast'];
677 - (void)rewind:(id)sender
679 [self sendAEWithEventClass:'hook' andEventID:'Rwnd'];
682 - (void)quitMenuTunes:(id)sender
684 [NSApp terminate:self];
687 - (void)openiTunes:(id)sender
689 [[NSWorkspace sharedWorkspace] launchApplication:@"iTunes"];
692 - (void)showPreferences:(id)sender
694 if (!prefsController) {
695 prefsController = [[PreferencesController alloc] initWithMenuTunes:self];
701 - (void)closePreferences
703 if (!((iTunesPSN.highLongOfPSN == kNoProcess) && (iTunesPSN.lowLongOfPSN == 0))) {
706 [prefsController release];
707 prefsController = nil;
712 // Show Current Track Info And Show Upcoming Songs Floaters
716 - (void)showCurrentTrackInfo
718 NSString *trackName = [self runScriptAndReturnResult:@"return name of current track"];
719 if (!statusController && [trackName length]) {
720 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
721 NSString *stringToShow = @"";
724 if ([defaults boolForKey:@"showName"]) {
725 if ([defaults boolForKey:@"showArtist"]) {
726 NSString *trackArtist = [self runScriptAndReturnResult:@"return artist of current track"];
727 trackName = [NSString stringWithFormat:@"%@ - %@", trackArtist, trackName];
729 stringToShow = [stringToShow stringByAppendingString:trackName];
730 stringToShow = [stringToShow stringByAppendingString:@"\n"];
731 if ([trackName length] > 38) {
737 if ([defaults boolForKey:@"showAlbum"]) {
738 NSString *trackAlbum = [self runScriptAndReturnResult:@"return album of current track"];
739 if ([trackAlbum length]) {
740 stringToShow = [stringToShow stringByAppendingString:trackAlbum];
741 stringToShow = [stringToShow stringByAppendingString:@"\n"];
746 if ([defaults boolForKey:@"showTime"]) {
747 NSString *trackTime = [self runScriptAndReturnResult:@"return time of current track"];
748 if ([trackTime length]) {
749 stringToShow = [NSString stringWithFormat:@"%@Total Time: %@\n", stringToShow, trackTime];
755 int trackTimeLeft = [[self runScriptAndReturnResult:@"return (duration of current track) - player position"] intValue];
756 int minutes = trackTimeLeft / 60, seconds = trackTimeLeft % 60;
758 stringToShow = [stringToShow stringByAppendingString:
759 [NSString stringWithFormat:@"Time Remaining: %i:0%i", minutes, seconds]];
761 stringToShow = [stringToShow stringByAppendingString:
762 [NSString stringWithFormat:@"Time Remaining: %i:%i", minutes, seconds]];
766 statusController = [[StatusWindowController alloc] init];
767 [statusController setTrackInfo:stringToShow lines:lines];
768 [NSTimer scheduledTimerWithTimeInterval:3.0
770 selector:@selector(fadeAndCloseStatusWindow)
776 - (void)showUpcomingSongs
778 if (!statusController) {
779 int numSongs = [[self runScriptAndReturnResult:@"return number of tracks in current playlist"] intValue];
782 int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
783 int curTrack = [[self runScriptAndReturnResult:@"return index of current track"] intValue];
785 NSString *songs = @"";
787 statusController = [[StatusWindowController alloc] init];
788 for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) {
790 NSString *curSong = [self runScriptAndReturnResult:
791 [NSString stringWithFormat:@"return name of track %i of current playlist", i]];
792 songs = [songs stringByAppendingString:curSong];
793 songs = [songs stringByAppendingString:@"\n"];
796 [statusController setUpcomingSongs:songs numSongs:numSongsInAdvance];
797 [NSTimer scheduledTimerWithTimeInterval:3.0
799 selector:@selector(fadeAndCloseStatusWindow)
806 - (void)fadeAndCloseStatusWindow
808 [statusController fadeWindowOut];
809 [statusController release];
810 statusController = nil;
813 /*************************************************************************/
815 #pragma mark NSApplication DELEGATE METHODS
816 /*************************************************************************/
818 - (void)applicationWillTerminate:(NSNotification *)note
821 [[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
825 /*************************************************************************/
827 #pragma mark DEALLOCATION METHODS
828 /*************************************************************************/
833 [refreshTimer invalidate];
836 CloseComponent(asComponent);
837 [statusItem release];