X-Git-Url: http://git.ithinksw.org/MenuTunes.git/blobdiff_plain/b4741ddf87f7a63256d44526313dab7a6b743362..32c6934d7afdef0ee3f165436e7c1c560b72e79f:/MenuTunes.m diff --git a/MenuTunes.m b/MenuTunes.m index b3f858a..c09358a 100755 --- a/MenuTunes.m +++ b/MenuTunes.m @@ -1,24 +1,17 @@ /* Things to do: -¥ Radio mode makes things act oddly ¥ Make preferences window pretty -¥ Hot Keys - - hot keys can't be set when NSBGOnly is on. The window is not key, - so the KeyBroadcaster does not pick up key combos - - going to need a different way of defining key combos ¥ Optimize ¥ Apple Events! Apple Events! Apple Events! -¥ Upcoming songs menu items are disabled after launching iTunes and playing +¥ Manual and webpage */ #import "MenuTunes.h" -// #import "MenuTunesView.h" #import "PreferencesController.h" #import "HotKeyCenter.h" #import "StatusWindowController.h" @interface MenuTunes(Private) -- (void)registerDefaultsIfNeeded; - (void)updateMenu; - (void)rebuildUpcomingSongsMenu; - (void)rebuildPlaylistMenu; @@ -50,10 +43,10 @@ Things to do: { [self rebuildMenu]; refreshTimer = [NSTimer scheduledTimerWithTimeInterval:3.5 - target:self - selector:@selector(timerUpdate) - userInfo:nil - repeats:YES]; + target:self + selector:@selector(timerUpdate) + userInfo:nil + repeats:YES]; } else { @@ -64,16 +57,15 @@ Things to do: [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(iTunesLaunched:) name:NSWorkspaceDidLaunchApplicationNotification object:nil]; refreshTimer = nil; } + + statusItem = [[ITStatusItem alloc] initWithStatusBar:[NSStatusBar systemStatusBar] + withLength:NSSquareStatusItemLength]; - statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; - [[[statusItem _button] cell] setType:NSNullCellType]; [statusItem setImage:[NSImage imageNamed:@"menu"]]; - [[statusItem _button] setAlternateImage:[NSImage imageNamed:@"selected_image"]]; - [statusItem setHighlightMode:YES]; + [statusItem setAlternateImage:[NSImage imageNamed:@"selected_image"]]; [statusItem setMenu:menu]; - [statusItem retain]; -// view = [[MenuTunesView alloc] initWithFrame:[[statusItem view] frame]]; -// [statusItem setView:view]; + // Below line of code is for creating builds for Beta Testers + // [statusItem setToolTip:@[NSString stringWithFormat:@"This Nontransferable Beta (Built on %s) of iThink Software's MenuTunes is Registered to: Beta Tester (betatester@somedomain.com).",__DATE__]]; } @@ -84,8 +76,14 @@ Things to do: - (void)registerDefaultsIfNeeded { - if (![[NSUserDefaults standardUserDefaults] objectForKey:@"menu"]) { - [[NSUserDefaults standardUserDefaults] setObject: + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if (![defaults objectForKey:@"menu"]) { + bool found = NO; + NSMutableDictionary *loginwindow; + NSMutableArray *loginarray; + int i; + + [defaults setObject: [NSArray arrayWithObjects: @"Play/Pause", @"Next Track", @@ -101,6 +99,53 @@ Things to do: @"", @"Current Track Info", nil] forKey:@"menu"]; + + [defaults synchronize]; + loginwindow = [[defaults persistentDomainForName:@"loginwindow"] mutableCopy]; + loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"]; + + for (i = 0; i < [loginarray count]; i++) { + NSDictionary *tempDict = [loginarray objectAtIndex:i]; + if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) { + found = YES; + } + } + + if (!found) { + if (NSRunInformationalAlertPanel(@"Auto-launch MenuTunes", @"Would you like MenuTunes to automatically launch at login?", @"Yes", @"No", nil) == NSOKButton) { + AEDesc scriptDesc, resultDesc; + NSString *script = [NSString stringWithFormat:@"tell application \"System Events\"\nmake new login item at end of login items with properties {path:\"%@\", kind:\"APPLICATION\"}\nend tell", [[NSBundle mainBundle] bundlePath]]; + + AECreateDesc(typeChar, [script cString], [script cStringLength], + &scriptDesc); + + OSADoScript(asComponent, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc); + + AEDisposeDesc(&scriptDesc); + AEDisposeDesc(&resultDesc); + } + } + } + + if (![defaults integerForKey:@"SongsInAdvance"]) + { + [defaults setInteger:5 forKey:@"SongsInAdvance"]; + } + + if (![defaults objectForKey:@"showName"]) { + [defaults setBool:YES forKey:@"showName"]; + } + + if (![defaults objectForKey:@"showArtist"]) { + [defaults setBool:YES forKey:@"showArtist"]; + } + + if (![defaults objectForKey:@"showAlbum"]) { + [defaults setBool:NO forKey:@"showAlbum"]; + } + + if (![defaults objectForKey:@"showTime"]) { + [defaults setBool:NO forKey:@"showTime"]; } } @@ -112,7 +157,9 @@ Things to do: trackInfoIndex = -1; didHaveAlbumName = ([[self runScriptAndReturnResult:@"return album of current track"] length] > 0); - + didHaveArtistName = ([[self runScriptAndReturnResult:@"return artist of current track"] length] > 0); + + while ([menu numberOfItems] > 0) { [menu removeItemAtIndex:0]; } @@ -189,8 +236,9 @@ Things to do: //Updates the menu with current player state, song, and upcoming songs - (void)updateMenu { - NSString *curAlbumName = [self runScriptAndReturnResult:@"return album of current track"]; NSMenuItem *menuItem; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ((iTunesPSN.highLongOfPSN == kNoProcess) && (iTunesPSN.lowLongOfPSN == 0)) { return; } @@ -198,30 +246,61 @@ Things to do: if (upcomingSongsItem) { [self rebuildUpcomingSongsMenu]; } + if (playlistItem) { [self rebuildPlaylistMenu]; } + if (eqItem) { [self rebuildEQPresetsMenu]; } if (trackInfoIndex > -1) { - NSString *curSongName; + NSString *curSongName, *curAlbumName = @"", *curArtistName = @""; curSongName = [self runScriptAndReturnResult:@"return name of current track"]; + + if ([defaults boolForKey:@"showAlbum"]) { + curAlbumName = [self runScriptAndReturnResult:@"return album of current track"]; + } + + if ([defaults boolForKey:@"showArtist"]) { + curArtistName = [self runScriptAndReturnResult:@"return artist of current track"]; + } + if ([curSongName length] > 0) { int index = [menu indexOfItemWithTitle:@"Now Playing"]; - if (index > -1) { - [menu removeItemAtIndex:index + 1]; - - if (!isPlayingRadio) { - if (didHaveAlbumName) { - [menu removeItemAtIndex:index + 1]; - } + if ([defaults boolForKey:@"showName"]) { + [menu removeItemAtIndex:index + 1]; + } + if (didHaveAlbumName) { + [menu removeItemAtIndex:index + 1]; + } + if (didHaveArtistName) { + [menu removeItemAtIndex:index + 1]; + } + if ([defaults boolForKey:@"showTime"]) { + [menu removeItemAtIndex:index + 1]; } } if (!isPlayingRadio) { + if ([defaults boolForKey:@"showTime"]) { + menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", [self runScriptAndReturnResult:@"return time of current track"]] + action:nil + keyEquivalent:@""]; + [menu insertItem:menuItem atIndex:trackInfoIndex + 1]; + [menuItem release]; + } + + if ([curArtistName length] > 0) { + menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curArtistName] + action:nil + keyEquivalent:@""]; + [menu insertItem:menuItem atIndex:trackInfoIndex + 1]; + [menuItem release]; + } + if ([curAlbumName length] > 0) { menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curAlbumName] action:nil @@ -230,11 +309,14 @@ Things to do: [menuItem release]; } } - menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curSongName] - action:nil - keyEquivalent:@""]; - [menu insertItem:menuItem atIndex:trackInfoIndex + 1]; - [menuItem release]; + + if ([defaults boolForKey:@"showName"]) { + menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", curSongName] + action:nil + keyEquivalent:@""]; + [menu insertItem:menuItem atIndex:trackInfoIndex + 1]; + [menuItem release]; + } if (index == -1) { menuItem = [[NSMenuItem alloc] initWithTitle:@"Now Playing" action:nil keyEquivalent:@""]; @@ -242,12 +324,22 @@ Things to do: [menu insertItem:menuItem atIndex:trackInfoIndex]; [menuItem release]; } - } else if ([menu indexOfItemWithTitle:@"No Song"] == -1) { [menu removeItemAtIndex:trackInfoIndex]; - [menu removeItemAtIndex:trackInfoIndex]; - if (didHaveAlbumName) { + if ([defaults boolForKey:@"showName"] == YES) { + [menu removeItemAtIndex:trackInfoIndex]; + } + + if ([defaults boolForKey:@"showTime"] == YES) { + [menu removeItemAtIndex:trackInfoIndex]; + } + + if (didHaveArtistName && [defaults boolForKey:@"showArtist"]) { + [menu removeItemAtIndex:trackInfoIndex]; + } + + if (didHaveAlbumName && [defaults boolForKey:@"showAlbum"]) { [menu removeItemAtIndex:trackInfoIndex]; } @@ -255,8 +347,15 @@ Things to do: [menu insertItem:menuItem atIndex:trackInfoIndex]; [menuItem release]; } + + if ([defaults boolForKey:@"showArtist"]) { + didHaveAlbumName = (([curArtistName length] > 0) ? YES : NO); + } + + if ([defaults boolForKey:@"showAlbum"]) { + didHaveArtistName = (([curAlbumName length] > 0) ? YES : NO); + } } - didHaveAlbumName = (([curAlbumName length] > 0) ? YES : NO); } //Rebuild the upcoming songs submenu. Can be improved a lot. @@ -271,6 +370,8 @@ Things to do: [upcomingSongsMenu release]; upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""]; + [upcomingSongsItem setSubmenu:upcomingSongsMenu]; + [upcomingSongsItem setEnabled:YES]; for (i = curTrack + 1; i <= curTrack + numSongsInAdvance; i++) { if (i <= numSongs) { @@ -282,12 +383,9 @@ Things to do: [upcomingSongsMenu addItem:songItem]; [songItem release]; } else { - [upcomingSongsMenu addItemWithTitle:@"End of playlist." action:nil keyEquivalent:@""]; break; } } - [upcomingSongsItem setSubmenu:upcomingSongsMenu]; - [upcomingSongsItem setEnabled:YES]; } } else { [upcomingSongsItem setSubmenu:nil]; @@ -433,16 +531,50 @@ Things to do: - (void)timerUpdate { int pid; - if (GetProcessPID(&iTunesPSN, &pid) == noErr) { int trackPlayingIndex = [[self runScriptAndReturnResult:@"return index of current track"] intValue]; if (trackPlayingIndex != curTrackIndex) { + bool wasPlayingRadio = isPlayingRadio; isPlayingRadio = [[self runScriptAndReturnResult:@"return class of current playlist"] isEqualToString:@"radio tuner playlist"]; + if (isPlayingRadio && !wasPlayingRadio) { + int i; + for (i = 0; i < [playlistMenu numberOfItems]; i++) + { + [[playlistMenu itemAtIndex:i] setState:NSOffState]; + } + } + if (wasPlayingRadio) { + NSMenuItem *temp = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; + [menu insertItem:temp atIndex:trackInfoIndex + 1]; + [temp release]; + } [self updateMenu]; curTrackIndex = trackPlayingIndex; } - + else + { + int playlist = [[self runScriptAndReturnResult:@"return index of current playlist"] intValue]; + if (playlist != curPlaylistIndex) { + bool wasPlayingRadio = isPlayingRadio; + isPlayingRadio = [[self runScriptAndReturnResult:@"return class of current playlist"] isEqualToString:@"radio tuner playlist"]; + if (isPlayingRadio && !wasPlayingRadio) { + int i; + for (i = 0; i < [playlistMenu numberOfItems]; i++) + { + [[playlistMenu itemAtIndex:i] setState:NSOffState]; + } + } + if (wasPlayingRadio) { + NSMenuItem *temp = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; + [menu insertItem:temp atIndex:trackInfoIndex + 1]; + [temp release]; + } + [self updateMenu]; + curTrackIndex = trackPlayingIndex; + curPlaylistIndex = playlist; + } + } //Update Play/Pause menu item if (playPauseMenuItem){ if ([[self runScriptAndReturnResult:@"return player state"] isEqualToString:@"playing"]) { @@ -494,7 +626,7 @@ Things to do: if ([(NSString *)procName isEqualToString:@"iTunes"]) { return procNum; } - [(NSString *)procName release]; + CFRelease(procName); } } return procNum; @@ -527,11 +659,12 @@ andEventID:(AEEventID)eventID - (void)selectPlaylist:(id)sender { int playlist = [[sender representedObject] intValue]; - int curPlaylist = [[self runScriptAndReturnResult:@"return index of current playlist"] intValue]; - [[playlistMenu itemAtIndex:curPlaylist - 1] setState:NSOffState]; + if (!isPlayingRadio) { + int curPlaylist = [[self runScriptAndReturnResult:@"return index of current playlist"] intValue]; + [[playlistMenu itemAtIndex:curPlaylist - 1] setState:NSOffState]; + } [self runScriptAndReturnResult:[NSString stringWithFormat:@"play playlist %i", playlist]]; [[playlistMenu itemAtIndex:playlist - 1] setState:NSOnState]; - [self updateMenu]; } - (void)selectEQPreset:(id)sender @@ -667,10 +800,10 @@ isEqualToString:@"rewinding"]) { statusController = [[StatusWindowController alloc] init]; [statusController setTrackInfo:stringToShow lines:lines]; [NSTimer scheduledTimerWithTimeInterval:3.0 - target:self - selector:@selector(fadeAndCloseStatusWindow) - userInfo:nil - repeats:NO]; + target:self + selector:@selector(fadeAndCloseStatusWindow) + userInfo:nil + repeats:NO]; } }