Adding initial work on new plugin API. THIS BREAKS MT. We are working to
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Sat, 6 Sep 2003 17:56:40 +0000 (17:56 +0000)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Sat, 6 Sep 2003 17:56:40 +0000 (17:56 +0000)
finish up the iTunes remote, and Kent should start work on moving the
application to use the new API.

18 files changed:
Deprecated/ITMTRemote.h [new file with mode: 0755]
Deprecated/ITMTRemote.m [new file with mode: 0755]
Deprecated/iTunesRemote.h [new file with mode: 0755]
Deprecated/iTunesRemote.m [new file with mode: 0755]
ITMTEqualizer.h [new file with mode: 0755]
ITMTEqualizer.m [new file with mode: 0755]
ITMTPlayer.h [new file with mode: 0755]
ITMTPlayer.m [new file with mode: 0755]
ITMTPlaylist.h [new file with mode: 0755]
ITMTPlaylist.m [new file with mode: 0755]
ITMTRemote.h
ITMTRemote.m
ITMTTrack.h [new file with mode: 0755]
ITMTTrack.m [new file with mode: 0755]
iTunesPlayer.h [new file with mode: 0755]
iTunesPlayer.m [new file with mode: 0755]
iTunesRemote.h
iTunesRemote.m

diff --git a/Deprecated/ITMTRemote.h b/Deprecated/ITMTRemote.h
new file mode 100755 (executable)
index 0000000..2c27199
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ *  MenuTunes
+ *  ITMTRemote
+ *    Plugin definition for audio player control via MenuTunes
+ *
+ *  Original Author : Matt Judy <mjudy@ithinksw.com>
+ *   Responsibility : Matt Judy <mjudy@ithinksw.com>
+ *
+ *  Copyright (c) 2002 - 2003 iThink Software.
+ *  All Rights Reserved
+ *
+ *     This header defines the Objective-C protocol which all MenuTunes Remote
+ *  plugins must implement.  To build a remote, create a subclass of this
+ *  object, and implement each method in the @protocol below.
+ *
+ */
+
+/*!
+ * @header ITMTRemote
+ * @discussion This header defines the Objective-C protocol which all MenuTunes Remote plugins must implement.  To build a remote, create a subclass of the ITMTRemote object, and implement each method in the ITMTRemote protocol.
+ */
+#import <Cocoa/Cocoa.h>
+
+/*!
+ * @enum ITMTRemotePlayerRunningState
+ * @abstract Possible running states for the remote's player.
+ * @discussion Used in fuctions that report or take the running state of the remote's player application.
+ * @constant ITMTRemotePlayerNotRunning The remote's player isn't running.
+ * @constant ITMTRemotePlayerLaunching The remote's player is starting up, or is running, but not yet accepting remote commands.
+ * @constant ITMTRemotePlayerRunning The remote's player is running, and as such, is accepting remote commands.
+ */
+typedef enum {
+    ITMTRemotePlayerNotRunning = -1,
+    ITMTRemotePlayerLaunching,
+    ITMTRemotePlayerRunning
+} ITMTRemotePlayerRunningState;
+
+/*!
+ * @enum ITMTRemotePlayerPlayingState
+ * @abstract Possible playing states for the remote's player.
+ * @discussion Used in functions that report or take the playing state of the remote's player application.
+ * @constant ITMTRemotePlayerStopped The remote's player is stopped.
+ * @constant ITMTRemotePlayerPaused The remote's player is paused.
+ * @constant ITMTRemotePlayerPlaying The remote's player is playing.
+ * @constant ITMTRemotePlayerRewinding The remote's player is rewinding.
+ * @constant ITMTRemotePlayerForwarding The remote's player is forwarding.
+ */
+typedef enum {
+    ITMTRemotePlayerStopped = -1,
+    ITMTRemotePlayerPaused,
+    ITMTRemotePlayerPlaying,
+    ITMTRemotePlayerRewinding,
+    ITMTRemotePlayerForwarding
+} ITMTRemotePlayerPlayingState;
+
+/*!
+ * @enum ITMTRemotePlayerPlaylistClass
+ * @abstract Possible playlist classes used by a remote's player
+ * @discussion Used in functions that report the class of a playlist to MenuTunes. While we borrow the terms/descriptions from iTunes, these should work fine with any other player. If your player doesn't support a given type of playlist, then just return ITMTRemotePlayerPlaylist.
+ * @constant ITMTRemotePlayerLibraryPlaylist For players that have one playlist that contains all of a user's music, or for players that don't have the concept of multiple playlists, this is the class for that "Master" list.
+ * @constant ITMTRemotePlayerPlaylist The generic playlist. Created and maintained by the user.
+ * @constant ITMTRemotePlayerSmartPlaylist A smart playlist is a playlist who's contents are dynamic, based on a set of criteria or updated by a script. These are usually not edited directly by the user, but instead maintained by the player.
+ * @constant ITMTRemotePlayerRadioPlaylist This is for when playing tracks off of (online) radio stations.
+ */
+typedef enum {
+    ITMTRemotePlayerLibraryPlaylist = -1,
+    ITMTRemotePlayerPlaylist,
+    ITMTRemotePlayerSmartPlaylist,
+    ITMTRemotePlayerRadioPlaylist
+} ITMTRemotePlayerPlaylistClass;
+
+/*!
+ * @enum ITMTRemotePlayerRepeatMode
+ * @abstract Possible repeat modes for the remote's player.
+ * @discussion Used in functions that report or set the remote's player's repeat mode.
+ * @constant ITMTRemotePlayerRepeatOff The player plays all of the songs in a playlist through to the end, and then stops.
+ * @constant ITMTRemotePlayerRepeatAll The player plays all of the songs in a playlist through to the end, and then starts over again from the beginning.
+ * @constant ITMTRemotePlayerRepeatOne The player loops playing the selected song.
+ */
+typedef enum {
+    ITMTRemotePlayerRepeatOff = -1,
+    ITMTRemotePlayerRepeatAll,
+    ITMTRemotePlayerRepeatOne
+} ITMTRemotePlayerRepeatMode;
+
+/*!
+ * @protocol ITMTRemote
+ * @discussion The Objective-C protocol which all MenuTunes remotes must implement.
+ */
+@protocol ITMTRemote
+
+/*!
+ * @method remote
+ * @abstract Returns an autoreleased instance of the remote.
+ * @discussion Should be very quick and compact.
+ *
+ * EXAMPLE:<br>
+ * + (id)remote<br>
+ * {<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [[[MyRemote alloc] init] autorelease];<br>
+ * }
+ *
+ * @result An instance of the remote.
+ */
++ (id)remote;
+
+/*!
+ * @method remoteTitle
+ * @abstract Returns the remote's title/name.
+ * @discussion This title is shown while the user is selecting which remote to use. This is for informational purposes only.
+ * @result An NSString containing the title/name of the remote.
+ */
+- (NSString *)remoteTitle;
+
+/*!
+ * @method remoteInformation
+ * @abstract Returns the remote's information.
+ * @discussion Information on the remote that the user will see when selecting which remote to use. The information returned here has no bearing on how the remote works, it's simply here for informing the user.
+ * @result An NSString containing the information for the remote.
+ */
+- (NSString *)remoteInformation;
+
+/*!
+ * @method remoteIcon
+ * @abstract Returns the remote's icon.
+ * @discussion This icon is shown while the user is selecting which remote to use. Typically, this is the remote's player's application icon, however it can be anything you like.
+ * @result An NSImage containing the icon of the remote.
+ */
+- (NSImage *)remoteIcon;
+
+/*!
+ * @method begin
+ * @abstract Sent when the remote should begin operation.
+ * @result A result code signifying success.
+ */
+- (BOOL)begin;
+
+/*!
+ * @method halt
+ * @abstract Sent when the remote should cease operation.
+ * @result A result code signifying success.
+ */
+- (BOOL)halt;
+
+/*!
+ * @method playerFullName
+ * @abstract Returns the remote's player's application filename.
+ * @discussion This string should be the name typically used by the remote's player's application bundle/file. For example, Panic's Audion audio player is known simply as "Audion", however, the application bundle is called "Audion 3" for version 3 of their application. This should return "Audion 3", not simply "Audion". See playerSimpleName.
+ * @result An NSString containing the remote's player's application filename
+ */
+- (NSString *)playerFullName;
+
+/*!
+ * @method playerSimpleName
+ * @abstract Returns the simplified name of the remote's player.
+ * @discussion This is the name used in the User Interface for when referring to the remote's player. Continuing the example from the playerFullName method, this method would return simply "Audion", as that is how the player is known.
+ * @result An NSString containing the simplified name of the remote's player.
+ */
+- (NSString *)playerSimpleName;
+
+/*!
+ * @method capabilities
+ * @abstract Returns a dictionary defining the capabilities of the remote and it's player.
+ * @discussion Discussion Forthcoming.
+ * @result An NSDictionary defining the capabilities of the remote and it's player.
+ */
+- (NSDictionary *)capabilities;
+
+/*!
+ * @method showPrimaryInterface
+ */
+- (BOOL)showPrimaryInterface;
+
+/*!
+ * @method playerRunningState
+ * @abstract Returns the running state of the remote's player.
+ * @discussion While most remotes will use only ITMTRemotePlayerNotRunning or ITMTRemotePlayerRunning, we have included support for ITMTRemotePlayerLaunching (see ITMTRemotePlayerRunningState) for remotes that want the most precise control over their player's process managment.
+ * @result An ITMTRemotePlayerRunningState defining the running state of the remote's player.
+ */
+- (ITMTRemotePlayerRunningState)playerRunningState;
+
+/*!
+ * @method playerPlayingState
+ */
+- (ITMTRemotePlayerPlayingState)playerPlayingState;
+
+/*!
+ * @method playlists
+ */
+- (NSArray *)playlists;
+
+/*!
+ * @method numberOfSongsInPlaylistAtIndex:
+ */
+- (int)numberOfSongsInPlaylistAtIndex:(int)index;
+
+/*!
+ * @method currentPlaylistClass
+ */
+- (ITMTRemotePlayerPlaylistClass)currentPlaylistClass;
+
+/*!
+ * @method currentPlaylistIndex
+ */
+- (int)currentPlaylistIndex;
+
+/*!
+ * @method songTitleAtIndex:
+ */
+- (NSString *)songTitleAtIndex:(int)index;
+
+/*!
+ * @method currentAlbumTrackCount:
+ */
+- (int)currentAlbumTrackCount;
+
+/*!
+ * @method currentSongTrack:
+ */
+- (int)currentSongTrack;
+
+/*!
+ * @method playerStateUniqueIdentifier:
+ */
+- (NSString *)playerStateUniqueIdentifier;
+
+/*!
+ * @method currentSongIndex
+ */
+- (int)currentSongIndex;
+
+/*!
+ * @method currentSongTitle
+ */
+- (NSString *)currentSongTitle;
+
+/*!
+ * @method currentSongArtist
+ */
+- (NSString *)currentSongArtist;
+
+/*!
+ * @method currentSongAlbum
+ */
+- (NSString *)currentSongAlbum;
+
+/*!
+ * @method currentSongGenre
+ */
+- (NSString *)currentSongGenre;
+
+/*!
+ * @method currentSongLength
+ */
+- (NSString *)currentSongLength;
+
+/*!
+ * @method currentSongRemaining
+ */
+- (NSString *)currentSongRemaining;
+
+/*!
+ * @method currentSongRating
+ */
+- (float)currentSongRating;
+
+/*!
+ * @method setCurrentSongRating:
+ */
+- (BOOL)setCurrentSongRating:(float)rating;
+
+/*!
+ * @method eqPresets
+ */
+- (NSArray *)eqPresets;
+
+/*!
+ * @method currentEQPresetIndex
+ */
+- (int)currentEQPresetIndex;
+
+/*!
+ * @method volume
+ */
+- (float)volume;
+
+/*!
+ * @method setVolume:
+ */
+- (BOOL)setVolume:(float)volume;
+
+/*!
+ * @method shuffleEnabled
+ */
+- (BOOL)shuffleEnabled;
+
+/*!
+ * @method setShuffleEnabled:
+ */
+- (BOOL)setShuffleEnabled:(BOOL)enabled;
+
+/*!
+ * @method repeatMode
+ */
+- (ITMTRemotePlayerRepeatMode)repeatMode;
+
+/*!
+ * @method setRepeatMode:
+ */
+- (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode;
+
+/*!
+ * @method play
+ */
+- (BOOL)play;
+
+/*!
+ * @method pause
+ */
+- (BOOL)pause;
+
+/*!
+ * @method goToNextSong
+ */
+- (BOOL)goToNextSong;
+
+/*!
+ * @method goToPreviousSong
+ */
+- (BOOL)goToPreviousSong;
+
+/*!
+ * @method forward
+ */
+- (BOOL)forward;
+
+/*!
+ * @method rewind
+ */
+- (BOOL)rewind;
+
+/*!
+ * @method switchToPlaylistAtIndex:
+ */
+- (BOOL)switchToPlaylistAtIndex:(int)index;
+
+/*!
+ * @method switchToSongAtIndex:
+ */
+- (BOOL)switchToSongAtIndex:(int)index;
+
+/*!
+ * @method switchToEQAtIndex:
+ */
+- (BOOL)switchToEQAtIndex:(int)index;
+
+@end
+
+/*!
+ * @class ITMTRemote
+ */
+@interface ITMTRemote : NSObject <ITMTRemote>
+
+@end
diff --git a/Deprecated/ITMTRemote.m b/Deprecated/ITMTRemote.m
new file mode 100755 (executable)
index 0000000..3337e55
--- /dev/null
@@ -0,0 +1,257 @@
+#import "ITMTRemote.h"
+
+@implementation ITMTRemote
+
++ (id)remote
+{
+    return nil;
+}
+
+- (NSString *)remoteTitle
+{
+    return nil;
+}
+
+- (NSString *)remoteInformation
+{
+    return nil;
+}
+
+- (NSImage *)remoteIcon
+{
+    return nil;
+}
+
+- (BOOL)begin
+{
+    return NO;
+}
+
+- (BOOL)halt
+{
+    return NO;
+}
+
+- (NSString *)playerFullName
+{
+    return nil;
+}
+
+- (NSString *)playerSimpleName
+{
+    return nil;
+}
+
+- (NSDictionary *)capabilities
+{
+    return [NSDictionary dictionaryWithObjectsAndKeys:
+                [NSNumber numberWithBool: NO], @"Remote", // Set this to YES for a valid remote, otherwise the remote will be unusable.
+                [NSNumber numberWithBool: NO], @"Basic Track Control",
+                [NSNumber numberWithBool: NO], @"Track Information",
+                [NSNumber numberWithBool: NO], @"Track Navigation",
+                [NSNumber numberWithBool: NO], @"Upcoming Songs",
+                [NSNumber numberWithBool: NO], @"Playlists",
+                [NSNumber numberWithBool: NO], @"Volume",
+                [NSNumber numberWithBool: NO], @"Shuffle",
+                [NSNumber numberWithBool: NO], @"Repeat Modes",
+                [NSNumber numberWithBool: NO], @"Equalizer",
+                [NSNumber numberWithBool: NO], @"Track Rating",
+                nil];
+}
+
+- (BOOL)showPrimaryInterface
+{
+    return NO;
+}
+
+- (ITMTRemotePlayerRunningState)playerRunningState
+{
+    return nil;
+}
+
+- (ITMTRemotePlayerPlayingState)playerPlayingState
+{
+    return nil;
+}
+
+- (NSArray *)playlists
+{
+    return nil;
+}
+
+- (int)numberOfSongsInPlaylistAtIndex:(int)index
+{
+    return nil;
+}
+
+- (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
+{
+    return nil;
+}
+
+- (int)currentPlaylistIndex
+{
+    return nil;
+}
+
+- (NSString *)songTitleAtIndex:(int)index
+{
+    return nil;
+}
+
+- (int)currentAlbumTrackCount
+{
+    return nil;
+}
+
+- (int)currentSongTrack
+{
+    return nil;
+}
+
+- (NSString *)playerStateUniqueIdentifier
+{
+    return nil;
+}
+
+- (int)currentSongIndex
+{
+    return nil;
+}
+
+- (NSString *)currentSongTitle
+{
+    return nil;
+}
+
+- (NSString *)currentSongArtist
+{
+    return nil;
+}
+
+- (NSString *)currentSongAlbum
+{
+    return nil;
+}
+
+- (NSString *)currentSongGenre
+{
+    return nil;
+}
+
+- (NSString *)currentSongLength
+{
+    return nil;
+}
+
+- (NSString *)currentSongRemaining
+{
+    return nil;
+}
+
+- (float)currentSongRating
+{
+    return nil;
+}
+
+- (BOOL)setCurrentSongRating:(float)rating
+{
+    return NO;
+}
+
+/* - (BOOL)equalizerEnabled
+{
+    return NO;
+}
+
+- (BOOL)setEqualizerEnabled:(BOOL)enabled
+{
+    return NO;
+} */
+
+- (NSArray *)eqPresets
+{
+    return nil;
+}
+
+- (int)currentEQPresetIndex
+{
+    return nil;
+}
+
+- (float)volume
+{
+    return nil;
+}
+
+- (BOOL)setVolume:(float)volume
+{
+    return NO;
+}
+
+- (BOOL)shuffleEnabled
+{
+    return NO;
+}
+
+- (BOOL)setShuffleEnabled:(BOOL)enabled
+{
+    return NO;
+}
+
+- (ITMTRemotePlayerRepeatMode)repeatMode
+{
+    return ITMTRemotePlayerRepeatOff;
+}
+
+- (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
+{
+    return NO;
+}
+
+- (BOOL)play
+{
+    return NO;
+}
+
+- (BOOL)pause
+{
+    return NO;
+}
+
+- (BOOL)goToNextSong
+{
+    return NO;
+}
+
+- (BOOL)goToPreviousSong
+{
+    return NO;
+}
+
+- (BOOL)forward
+{
+    return NO;
+}
+
+- (BOOL)rewind
+{
+    return NO;
+}
+
+- (BOOL)switchToPlaylistAtIndex:(int)index
+{
+    return NO;
+}
+
+- (BOOL)switchToSongAtIndex:(int)index
+{
+    return NO;
+}
+
+- (BOOL)switchToEQAtIndex:(int)index
+{
+    return NO;
+}
+
+@end
diff --git a/Deprecated/iTunesRemote.h b/Deprecated/iTunesRemote.h
new file mode 100755 (executable)
index 0000000..992eb49
--- /dev/null
@@ -0,0 +1,20 @@
+//
+//  iTunesRemoteControl.h
+//  MenuTunes
+//
+//  Created by Matt L. Judy on Sun Jan 05 2003.
+//  Copyright (c) 2003 NibFile.com. All rights reserved.
+//
+
+
+#import <Cocoa/Cocoa.h>
+#import <Carbon/Carbon.h>
+#import <ITMTRemote/ITMTRemote.h>
+#import <ITFoundation/ITFoundation.h>
+
+@interface iTunesRemote : ITMTRemote <ITMTRemote>
+{
+    ProcessSerialNumber savedPSN;
+}
+- (ProcessSerialNumber)iTunesPSN;
+@end
diff --git a/Deprecated/iTunesRemote.m b/Deprecated/iTunesRemote.m
new file mode 100755 (executable)
index 0000000..5a64303
--- /dev/null
@@ -0,0 +1,426 @@
+#import "iTunesRemote.h"
+
+@implementation iTunesRemote
+
++ (id)remote
+{
+    return [[[iTunesRemote alloc] init] autorelease];
+}
+
+- (NSString *)remoteTitle
+{
+    return @"iTunes Remote";
+}
+
+- (NSString *)remoteInformation
+{
+    return @"Default MenuTunes plugin to control iTunes, by iThink Software.";
+}
+
+- (NSImage *)remoteIcon
+{
+    return nil;
+}
+
+- (BOOL)begin
+{
+    savedPSN = [self iTunesPSN];
+    return YES;
+}
+
+- (BOOL)halt
+{
+    return YES;
+}
+
+- (NSString *)playerFullName
+{
+    return @"iTunes";
+}
+
+- (NSString *)playerSimpleName
+{
+    return @"iTunes";
+}
+
+- (NSDictionary *)capabilities
+{
+    return [NSDictionary dictionaryWithObjectsAndKeys:
+                [NSNumber numberWithBool: YES], @"Remote",
+                [NSNumber numberWithBool: YES], @"Basic Track Control",
+                [NSNumber numberWithBool: YES], @"Track Information",
+                [NSNumber numberWithBool: YES], @"Track Navigation",
+                [NSNumber numberWithBool: YES], @"Upcoming Songs",
+                [NSNumber numberWithBool: YES], @"Playlists",
+                [NSNumber numberWithBool: YES], @"Volume",
+                [NSNumber numberWithBool: YES], @"Shuffle",
+                [NSNumber numberWithBool: YES], @"Repeat Modes",
+                [NSNumber numberWithBool: YES], @"Equalizer",
+                [NSNumber numberWithBool: YES], @"Track Rating",
+                nil];
+}
+
+- (BOOL)showPrimaryInterface
+{
+    // Make this into AppleEvents... shouldn't be too hard, I'm just too tired to do it right now.
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pisf'), from:'null'() }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    // Still have to convert these to AEs:
+    // set visible of browser window 1 to true
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(1), ----:obj { form:'prop', want:'prop', seld:'pvis', from:obj { form:'indx', want:'cBrW', seld:1, from:'null'() } }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    // set minimized of browser window 1 to false
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(0), ----:obj { form:'prop', want:'prop', seld:'pMin', from:obj { form:'indx', want:'cBrW', seld:1, from:'null'() } }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+
+    return NO;
+}
+
+- (ITMTRemotePlayerRunningState)playerRunningState
+{
+    NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
+    int i;
+    int count = [apps count];
+    
+    for (i = 0; i < count; i++) {
+        if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
+            return ITMTRemotePlayerRunning;
+        }
+    }
+    return ITMTRemotePlayerNotRunning;
+}
+
+- (ITMTRemotePlayerPlayingState)playerPlayingState
+{
+    long result = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlS'), from:'null'() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+    
+    switch (result)
+    {
+        default:
+        case 'kPSS':
+            return ITMTRemotePlayerStopped;
+        case 'kPSP':
+            return ITMTRemotePlayerPlaying;
+        case 'kPSp':
+            return ITMTRemotePlayerPaused;
+        case 'kPSR':
+            return ITMTRemotePlayerRewinding;
+        case 'kPSF':
+            return ITMTRemotePlayerForwarding;
+    }
+    
+    return ITMTRemotePlayerStopped;
+}
+
+- (NSArray *)playlists
+{
+    long i = 0;
+    const signed long numPlaylists = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cPly'), '----':()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
+    NSMutableArray *playlists = [[NSMutableArray alloc] initWithCapacity:numPlaylists];
+    
+    for (i = 1; i <= numPlaylists; i++) {
+        const long j = i;
+        NSString *sendStr = [NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cPly'), seld:long(%lu), from:'null'() } }",(unsigned long)j];
+        NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:sendStr eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+        [playlists addObject:theObj];
+    }
+    return [playlists autorelease];
+}
+
+- (int)numberOfSongsInPlaylistAtIndex:(int)index
+{
+    return [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:[NSString stringWithFormat:@"kocl:type('cTrk'), '----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:'null'() }",index] eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
+}
+
+- (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
+{
+    int realResult = [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pcls" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+    
+
+    switch (realResult)
+          {
+          case 'cLiP':
+                 return ITMTRemotePlayerLibraryPlaylist;
+                 break;
+          case 'cRTP':
+                 return ITMTRemotePlayerRadioPlaylist;
+                 break;
+          default:
+                 return ITMTRemotePlayerPlaylist;
+          }
+}
+
+- (int)currentPlaylistIndex
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)songTitleAtIndex:(int)index
+{
+    return [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }",index] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (int)currentAlbumTrackCount
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pTrC" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (int)currentSongTrack
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pTrN" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)playerStateUniqueIdentifier
+{
+    return [NSString stringWithFormat:@"%i-%i", [self currentPlaylistIndex], [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pDID" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN]];
+}
+
+- (int)currentSongIndex
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)currentSongTitle
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)currentSongArtist
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)currentSongAlbum
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)currentSongGenre
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)currentSongLength
+{
+    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pTim" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+}
+
+- (NSString *)currentSongRemaining
+{
+    long duration = [[ITAppleEventCenter sharedCenter]
+                        sendTwoTierAEWithRequestedKeyForNumber:@"pDur" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+    long current = [[ITAppleEventCenter sharedCenter]
+                        sendAEWithRequestedKeyForNumber:@"pPos" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+
+    return [[NSNumber numberWithLong:duration - current] stringValue];
+}
+
+- (float)currentSongRating
+{
+    return (float)[[ITAppleEventCenter sharedCenter]
+                sendTwoTierAEWithRequestedKeyForNumber:@"pRte" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100.0;
+}
+
+- (BOOL)setCurrentSongRating:(float)rating
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pRte'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }",(long)(rating*100),[self currentSongIndex]] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    return YES;
+}
+
+/* - (BOOL)equalizerEnabled
+{
+    int thingy = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:type('prop'), want:type('prop'), seld:type('pEQ '), from:() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+    NSLog(@"Debug equalizerEnabled: %i", thingy);
+    return thingy;
+}
+
+- (BOOL)setEqualizerEnabled:(BOOL)enabled
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }",enabled] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    return YES;
+} */
+
+- (NSArray *)eqPresets
+{
+    int i;
+    long numPresets = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cEQP'), '----':(), &subj:()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
+    NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
+    
+    for (i = 1; i <= numPresets; i++) {
+        NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() } }",i] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+        if (theObj) {
+            [presets addObject:theObj];
+        }
+    }
+    return [presets autorelease];
+}
+
+- (int)currentEQPresetIndex
+{
+    int result;
+    result = [[ITAppleEventCenter sharedCenter]
+                sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pEQP" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+    return result;
+}
+
+- (float)volume
+{
+    return (float)[[ITAppleEventCenter sharedCenter] sendAEWithRequestedKeyForNumber:@"pVol" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100;
+}
+
+- (BOOL)setVolume:(float)volume
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }",(long)(volume*100)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    return NO;
+}
+
+- (BOOL)shuffleEnabled
+{
+    int result = [[ITAppleEventCenter sharedCenter]
+                sendTwoTierAEWithRequestedKeyForNumber:@"pShf" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+    return result;
+}
+
+- (BOOL)setShuffleEnabled:(BOOL)enabled
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu) ----:obj { form:'prop', want:type('prop'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",(unsigned long)enabled] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    return YES;
+}
+
+- (ITMTRemotePlayerRepeatMode)repeatMode
+{
+    FourCharCode m00f = 0;
+    int result = 0;
+    m00f = [[ITAppleEventCenter sharedCenter]
+                sendTwoTierAEWithRequestedKeyForNumber:@"pRpt" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
+
+    switch (m00f)
+          {
+          case 'kRp0':
+                 result = ITMTRemotePlayerRepeatOff;
+                 break;
+          case 'kRp1':
+                 result = ITMTRemotePlayerRepeatOne;
+                 break;
+          case 'kRpA':
+                 result = ITMTRemotePlayerRepeatAll;
+                 break;
+          }
+    
+    return result;
+}
+
+- (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
+{
+    char *m00f = NULL;
+    switch (repeatMode)
+          {
+          case ITMTRemotePlayerRepeatOff:
+                 m00f = "kRp0";
+                 break;
+          case ITMTRemotePlayerRepeatOne:
+                 m00f = "kRp1";
+                 break;
+          case ITMTRemotePlayerRepeatAll:
+                 m00f = "kRpA";
+                 break;
+          }
+
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:type('%s') ----:obj { form:'prop', want:type('pRpt'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",m00f] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)play
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)pause
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)goToNextSong
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)goToPreviousSong
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)forward
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Fast" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)rewind
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Rwnd" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)switchToPlaylistAtIndex:(int)index
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)switchToSongAtIndex:(int)index
+{
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:() } }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
+    return YES;
+}
+
+- (BOOL)switchToEQAtIndex:(int)index
+{
+    // index should count from 0, but itunes counts from 1, so let's add 1.
+    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pEQP'), from:'null'() }, data:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() }",(index+1)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+    return YES;
+}
+
+- (ProcessSerialNumber)iTunesPSN
+{
+    /*NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
+    ProcessSerialNumber number;
+    int i;
+    int count = [apps count];
+    
+    number.highLongOfPSN = kNoProcess;
+    
+    for (i = 0; i < count; i++)
+    {
+        NSDictionary *curApp = [apps objectAtIndex:i];
+        
+        if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
+        {
+            number.highLongOfPSN = [[curApp objectForKey:
+                @"NSApplicationProcessSerialNumberHigh"] intValue];
+            number.lowLongOfPSN = [[curApp objectForKey:
+                @"NSApplicationProcessSerialNumberLow"] intValue];
+        }
+    }
+    return number;*/
+    ProcessSerialNumber number;
+    number.highLongOfPSN = kNoProcess;
+    number.lowLongOfPSN = 0;
+    
+    while ( (GetNextProcess(&number) == noErr) ) 
+    {
+        CFStringRef name;
+        if ( (CopyProcessName(&number, &name) == noErr) )
+        {
+            if ([(NSString *)name isEqualToString:@"iTunes"])
+            {
+                return number;
+            }
+            [(NSString *)name release];
+        }
+    }
+    return number;
+}
+
+@end
diff --git a/ITMTEqualizer.h b/ITMTEqualizer.h
new file mode 100755 (executable)
index 0000000..664576c
--- /dev/null
@@ -0,0 +1,39 @@
+/****************************************
+    ITMTRemote 1.0 (MenuTunes Remotes)
+    ITMTEqualizer.h
+    
+    Responsibility:
+        Joseph Spiros <joseph.spiros@ithinksw.com>
+    
+    Copyright (c) 2002 - 2003 by iThink Software.
+    All Rights Reserved.
+****************************************/
+
+#import <Cocoa/Cocoa.h>
+
+#import <ITMTRemote/ITMTRemote.h>
+
+typedef enum {
+    ITMT32HzEqualizerBandLevel,
+    ITMT64HzEqualizerBandLevel,
+    ITMT125HzEqualizerBandLevel,
+    ITMT250HzEqualizerBandLevel,
+    ITMT500HzEqualizerBandLevel,
+    ITMT1kHzEqualizerBandLevel,
+    ITMT2kHzEqualizerBandLevel,
+    ITMT4kHzEqualizerBandLevel,
+    ITMT8kHzEqualizerBandLevel,
+    ITMT16kHzEqualizerBandLevel,
+    ITMTEqualizerPreampLevel
+} ITMTEqualizerLevel;
+
+@protocol ITMTEqualizer
+- (BOOL)writable;
+
+- (ITMTPlayer *)player;
+
+- (float)dBForLevel:(ITMTEqualizerLevel)level;
+@end
+
+@interface ITMTEqualizer : NSObject 
+@end
diff --git a/ITMTEqualizer.m b/ITMTEqualizer.m
new file mode 100755 (executable)
index 0000000..b08dce2
--- /dev/null
@@ -0,0 +1,6 @@
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
+#import "ITMTEqualizer.h"
+
+@implementation ITMTEqualizer
+@end
diff --git a/ITMTPlayer.h b/ITMTPlayer.h
new file mode 100755 (executable)
index 0000000..3a94ace
--- /dev/null
@@ -0,0 +1,82 @@
+/****************************************
+    ITMTRemote 1.0 (MenuTunes Remotes)
+    ITMTPlayer.h
+    
+    Responsibility:
+        Joseph Spiros <joseph.spiros@ithinksw.com>
+    
+    Copyright (c) 2002 - 2003 by iThink Software.
+    All Rights Reserved.
+****************************************/
+
+#import <Cocoa/Cocoa.h>
+
+#import <ITMTRemote/ITMTRemote.h>
+
+/*!
+    @protocol ITMTPlayer
+    @abstract Object representation for a controlled player.
+    @discussion Object representation for a controlled player. Players can be defined as things that control playlist(s) objects, a pool of track objects, and possibly, equalizer objects.
+*/
+@protocol ITMTPlayer
+/*!
+    @method show
+*/
+- (BOOL)show;
+
+/*!
+    @method setValue:forProperty:
+*/
+- (BOOL)setValue:(id)value forProperty:(ITMTGenericProperty)property;
+/*!
+    @method valueOfProperty:
+*/
+- (id)valueOfProperty:(ITMTGenericProperty)property;
+/*!
+    @method propertiesAndValues
+*/
+- (NSDictionary *)propertiesAndValues;
+
+/*!
+    @method remote
+*/
+- (ITMTRemote *)remote;
+
+/*!
+    @method currentPlaylist
+*/
+- (ITMTPlaylist *)currentPlaylist;
+/*!
+    @method currentTrack
+*/
+- (ITMTTrack *)currentTrack;
+/*!
+    @method currentEqualizer
+*/
+- (ITMTEqualizer *)currentEqualizer;
+
+/*!
+    @method playlists
+*/
+- (NSArray *)playlists;
+
+/*!
+    @method tracks
+*/
+- (NSArray *)tracks;
+/*!
+    @method libraryPlaylist
+*/
+- (ITMTPlaylist *)libraryPlaylist;
+
+/*!
+    @method equalizers
+*/
+- (NSArray *)equalizers;
+@end
+
+/*!
+    @class ITMTPlayer
+*/
+@interface ITMTPlayer : NSObject
+@end
diff --git a/ITMTPlayer.m b/ITMTPlayer.m
new file mode 100755 (executable)
index 0000000..c92715f
--- /dev/null
@@ -0,0 +1,6 @@
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
+#import "ITMTPlayer.h"
+
+@implementation ITMTPlayer
+@end
diff --git a/ITMTPlaylist.h b/ITMTPlaylist.h
new file mode 100755 (executable)
index 0000000..9f2d61d
--- /dev/null
@@ -0,0 +1,44 @@
+/****************************************
+    ITMTRemote 1.0 (MenuTunes Remotes)
+    ITMTPlaylist.h
+    
+    Responsibility:
+        Joseph Spiros <joseph.spiros@ithinksw.com>
+    
+    Copyright (c) 2002 - 2003 by iThink Software.
+    All Rights Reserved.
+****************************************/
+
+#import <Cocoa/Cocoa.h>
+
+#import <ITMTRemote/ITMTRemote.h>
+
+@protocol ITMTPlaylist
+- (BOOL)show; // graphical
+
+- (BOOL)setValue:(id)value forProperty:(ITMTGenericProperty)property;
+- (id)valueOfProperty:(ITMTGenericProperty)property;
+- (NSDictionary *)propertiesAndValues;
+
+- (ITMTPlayer *)player;
+
+- (BOOL)addTrack:(ITMTTrack *)track;
+- (BOOL)insertTrack:(ITMTTrack *)track atIndex:(int)index;
+
+- (BOOL)removeTrack:(ITMTTrack *)item;
+- (BOOL)removeTrackAtIndex:(int)index;
+
+- (ITMTTrack *)trackAtIndex:(int)index;
+
+- (int)indexOfTrack:(ITMTTrack *)track;
+- (ITMTTrack *)trackWithProperty:(ITMTTrackProperty)property ofValue:(id)value allowPartialMatch:(BOOL)partial;
+- (NSArray *)tracksWithProperty:(ITMTTrackProperty)property ofValue:(id)value allowPartialMatches:(BOOL)partial;
+- (int)indexOfTrackWithProperty:(ITMTTrackProperty)property ofValue:(id)value allowPartialMatch:(BOOL)partial;
+- (NSArray *)indexesOfTracksWithProperty:(ITMTTrackProperty)property ofValue:(id)value allowPartialMatches:(BOOL)partial;
+
+- (int)trackCount;
+- (NSArray *)trackArray;
+@end
+
+@interface ITMTPlaylist : NSObject
+@end
diff --git a/ITMTPlaylist.m b/ITMTPlaylist.m
new file mode 100755 (executable)
index 0000000..5665229
--- /dev/null
@@ -0,0 +1,6 @@
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
+#import "ITMTPlaylist.h"
+
+@implementation ITMTPlaylist
+@end
index 2c27199..aedbc4d 100755 (executable)
-/*
- *  MenuTunes
- *  ITMTRemote
- *    Plugin definition for audio player control via MenuTunes
- *
- *  Original Author : Matt Judy <mjudy@ithinksw.com>
- *   Responsibility : Matt Judy <mjudy@ithinksw.com>
- *
- *  Copyright (c) 2002 - 2003 iThink Software.
- *  All Rights Reserved
- *
- *     This header defines the Objective-C protocol which all MenuTunes Remote
- *  plugins must implement.  To build a remote, create a subclass of this
- *  object, and implement each method in the @protocol below.
- *
- */
+/****************************************
+    ITMTRemote 1.0 (MenuTunes Remotes)
+    ITMTRemote.h
+    
+    Responsibility:
+        Joseph Spiros <joseph.spiros@ithinksw.com>
+    
+    Copyright (c) 2002 - 2003 by iThink Software.
+    All Rights Reserved.
+****************************************/
 
-/*!
- * @header ITMTRemote
- * @discussion This header defines the Objective-C protocol which all MenuTunes Remote plugins must implement.  To build a remote, create a subclass of the ITMTRemote object, and implement each method in the ITMTRemote protocol.
- */
 #import <Cocoa/Cocoa.h>
 
-/*!
- * @enum ITMTRemotePlayerRunningState
- * @abstract Possible running states for the remote's player.
- * @discussion Used in fuctions that report or take the running state of the remote's player application.
- * @constant ITMTRemotePlayerNotRunning The remote's player isn't running.
- * @constant ITMTRemotePlayerLaunching The remote's player is starting up, or is running, but not yet accepting remote commands.
- * @constant ITMTRemotePlayerRunning The remote's player is running, and as such, is accepting remote commands.
- */
-typedef enum {
-    ITMTRemotePlayerNotRunning = -1,
-    ITMTRemotePlayerLaunching,
-    ITMTRemotePlayerRunning
-} ITMTRemotePlayerRunningState;
+#import <ITMTRemote/ITMTPlayer.h>
+#import <ITMTRemote/ITMTPlaylist.h>
+#import <ITMTRemote/ITMTTrack.h>
+#import <ITMTRemote/ITMTEqualizer.h>
 
 /*!
- * @enum ITMTRemotePlayerPlayingState
- * @abstract Possible playing states for the remote's player.
- * @discussion Used in functions that report or take the playing state of the remote's player application.
- * @constant ITMTRemotePlayerStopped The remote's player is stopped.
- * @constant ITMTRemotePlayerPaused The remote's player is paused.
- * @constant ITMTRemotePlayerPlaying The remote's player is playing.
- * @constant ITMTRemotePlayerRewinding The remote's player is rewinding.
- * @constant ITMTRemotePlayerForwarding The remote's player is forwarding.
- */
+    @typedef ITMTGenericProperty
+    @constant ITMTNameProperty The object's human readable name.
+    @constant ITMTImageProperty An image that can be associated with the object.
+*/
 typedef enum {
-    ITMTRemotePlayerStopped = -1,
-    ITMTRemotePlayerPaused,
-    ITMTRemotePlayerPlaying,
-    ITMTRemotePlayerRewinding,
-    ITMTRemotePlayerForwarding
-} ITMTRemotePlayerPlayingState;
-
-/*!
- * @enum ITMTRemotePlayerPlaylistClass
- * @abstract Possible playlist classes used by a remote's player
- * @discussion Used in functions that report the class of a playlist to MenuTunes. While we borrow the terms/descriptions from iTunes, these should work fine with any other player. If your player doesn't support a given type of playlist, then just return ITMTRemotePlayerPlaylist.
- * @constant ITMTRemotePlayerLibraryPlaylist For players that have one playlist that contains all of a user's music, or for players that don't have the concept of multiple playlists, this is the class for that "Master" list.
- * @constant ITMTRemotePlayerPlaylist The generic playlist. Created and maintained by the user.
- * @constant ITMTRemotePlayerSmartPlaylist A smart playlist is a playlist who's contents are dynamic, based on a set of criteria or updated by a script. These are usually not edited directly by the user, but instead maintained by the player.
- * @constant ITMTRemotePlayerRadioPlaylist This is for when playing tracks off of (online) radio stations.
- */
+    ITMTNameProperty,
+    ITMTImageProperty
+} ITMTGenericProperty;
+/*!
+    @typedef ITMTRemoteProperty
+    @constant ITMTRemoteNameProperty
+    @constant ITMTRemoteImageProperty
+    @constant ITMTRemoteAuthorProperty
+    @constant ITMTRemoteDescriptionProperty
+    @constant ITMTRemoteURLProperty
+    @constant ITMTRemoteCopyrightProperty
+*/
 typedef enum {
-    ITMTRemotePlayerLibraryPlaylist = -1,
-    ITMTRemotePlayerPlaylist,
-    ITMTRemotePlayerSmartPlaylist,
-    ITMTRemotePlayerRadioPlaylist
-} ITMTRemotePlayerPlaylistClass;
-
-/*!
- * @enum ITMTRemotePlayerRepeatMode
- * @abstract Possible repeat modes for the remote's player.
- * @discussion Used in functions that report or set the remote's player's repeat mode.
- * @constant ITMTRemotePlayerRepeatOff The player plays all of the songs in a playlist through to the end, and then stops.
- * @constant ITMTRemotePlayerRepeatAll The player plays all of the songs in a playlist through to the end, and then starts over again from the beginning.
- * @constant ITMTRemotePlayerRepeatOne The player loops playing the selected song.
- */
+    ITMTRemoteNameProperty,
+    ITMTRemoteImageProperty,
+    ITMTRemoteAuthorProperty,
+    ITMTRemoteDescriptionProperty,
+    ITMTRemoteURLProperty,
+    ITMTRemoteCopyrightProperty,
+    ITMTRemoteActivationStringProperty,
+    ITMTRemoteDeactivationStringProperty
+} ITMTRemoteProperty
+/*!
+    @typedef ITMTPlayerStyle
+    @constant ITMTSinglePlayerStyle Like iTunes, One player controls all available songs.
+    @constant ITMTMultiplePlayerStyle Like Audion, Multiple players control multiple playlists.
+    @constant ITMTSinglePlayerSinglePlaylistStyle Like *Amp, XMMS. Not recommended, but instead, developers are urged to use ITMTSinglePlayerStyle with emulated support for multiple playlists.
+*/
 typedef enum {
-    ITMTRemotePlayerRepeatOff = -1,
-    ITMTRemotePlayerRepeatAll,
-    ITMTRemotePlayerRepeatOne
-} ITMTRemotePlayerRepeatMode;
+    ITMTSinglePlayerStyle,
+    ITMTMultiplePlayerStyle,
+    ITMTSinglePlayerSinglePlaylistStyle
+} ITMTPlayerStyle;
 
 /*!
* @protocol ITMTRemote
* @discussion The Objective-C protocol which all MenuTunes remotes must implement.
- */
   @protocol ITMTRemote
   @abstract The ITMTRemote protocol is the protocol that all MenuTunes remotes' primary class must implement.
+*/
 @protocol ITMTRemote
-
 /*!
- * @method remote
- * @abstract Returns an autoreleased instance of the remote.
- * @discussion Should be very quick and compact.
- *
- * EXAMPLE:<br>
- * + (id)remote<br>
- * {<br>
- * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [[[MyRemote alloc] init] autorelease];<br>
- * }
- *
- * @result An instance of the remote.
- */
+    @method remote
+    @result Returns an autoreleased instance of the remote.
+*/
 + (id)remote;
 
 /*!
- * @method remoteTitle
- * @abstract Returns the remote's title/name.
- * @discussion This title is shown while the user is selecting which remote to use. This is for informational purposes only.
- * @result An NSString containing the title/name of the remote.
- */
-- (NSString *)remoteTitle;
-
-/*!
- * @method remoteInformation
- * @abstract Returns the remote's information.
- * @discussion Information on the remote that the user will see when selecting which remote to use. The information returned here has no bearing on how the remote works, it's simply here for informing the user.
- * @result An NSString containing the information for the remote.
- */
-- (NSString *)remoteInformation;
-
-/*!
- * @method remoteIcon
- * @abstract Returns the remote's icon.
- * @discussion This icon is shown while the user is selecting which remote to use. Typically, this is the remote's player's application icon, however it can be anything you like.
- * @result An NSImage containing the icon of the remote.
- */
-- (NSImage *)remoteIcon;
-
-/*!
- * @method begin
- * @abstract Sent when the remote should begin operation.
- * @result A result code signifying success.
- */
-- (BOOL)begin;
-
-/*!
- * @method halt
- * @abstract Sent when the remote should cease operation.
- * @result A result code signifying success.
- */
-- (BOOL)halt;
-
-/*!
- * @method playerFullName
- * @abstract Returns the remote's player's application filename.
- * @discussion This string should be the name typically used by the remote's player's application bundle/file. For example, Panic's Audion audio player is known simply as "Audion", however, the application bundle is called "Audion 3" for version 3 of their application. This should return "Audion 3", not simply "Audion". See playerSimpleName.
- * @result An NSString containing the remote's player's application filename
- */
-- (NSString *)playerFullName;
-
-/*!
- * @method playerSimpleName
- * @abstract Returns the simplified name of the remote's player.
- * @discussion This is the name used in the User Interface for when referring to the remote's player. Continuing the example from the playerFullName method, this method would return simply "Audion", as that is how the player is known.
- * @result An NSString containing the simplified name of the remote's player.
- */
-- (NSString *)playerSimpleName;
-
-/*!
- * @method capabilities
- * @abstract Returns a dictionary defining the capabilities of the remote and it's player.
- * @discussion Discussion Forthcoming.
- * @result An NSDictionary defining the capabilities of the remote and it's player.
- */
-- (NSDictionary *)capabilities;
-
-/*!
- * @method showPrimaryInterface
- */
-- (BOOL)showPrimaryInterface;
-
-/*!
- * @method playerRunningState
- * @abstract Returns the running state of the remote's player.
- * @discussion While most remotes will use only ITMTRemotePlayerNotRunning or ITMTRemotePlayerRunning, we have included support for ITMTRemotePlayerLaunching (see ITMTRemotePlayerRunningState) for remotes that want the most precise control over their player's process managment.
- * @result An ITMTRemotePlayerRunningState defining the running state of the remote's player.
- */
-- (ITMTRemotePlayerRunningState)playerRunningState;
-
-/*!
- * @method playerPlayingState
- */
-- (ITMTRemotePlayerPlayingState)playerPlayingState;
-
-/*!
- * @method playlists
- */
-- (NSArray *)playlists;
-
-/*!
- * @method numberOfSongsInPlaylistAtIndex:
- */
-- (int)numberOfSongsInPlaylistAtIndex:(int)index;
-
-/*!
- * @method currentPlaylistClass
- */
-- (ITMTRemotePlayerPlaylistClass)currentPlaylistClass;
-
-/*!
- * @method currentPlaylistIndex
- */
-- (int)currentPlaylistIndex;
-
-/*!
- * @method songTitleAtIndex:
- */
-- (NSString *)songTitleAtIndex:(int)index;
-
-/*!
- * @method currentAlbumTrackCount:
- */
-- (int)currentAlbumTrackCount;
-
-/*!
- * @method currentSongTrack:
- */
-- (int)currentSongTrack;
-
-/*!
- * @method playerStateUniqueIdentifier:
- */
-- (NSString *)playerStateUniqueIdentifier;
+    @method valueOfProperty:
+*/
+- (id)valueOfProperty:(ITMTRemoteProperty)property;
 
 /*!
- * @method currentSongIndex
- */
-- (int)currentSongIndex;
+    @method propertiesAndValues
+*/
+- (NSDictionary *)propertiesAndValues;
 
 /*!
- * @method currentSongTitle
- */
-- (NSString *)currentSongTitle;
+    @method playerStyle
+    @result An ITMTPlayerStyle defining how the remote works with players and playlists.
+*/
+- (ITMTPlayerStyle)playerStyle;
 
 /*!
- * @method currentSongArtist
- */
-- (NSString *)currentSongArtist;
-
-/*!
- * @method currentSongAlbum
- */
-- (NSString *)currentSongAlbum;
-
-/*!
- * @method currentSongGenre
- */
-- (NSString *)currentSongGenre;
-
-/*!
- * @method currentSongLength
- */
-- (NSString *)currentSongLength;
-
-/*!
- * @method currentSongRemaining
- */
-- (NSString *)currentSongRemaining;
-
-/*!
- * @method currentSongRating
- */
-- (float)currentSongRating;
-
-/*!
- * @method setCurrentSongRating:
- */
-- (BOOL)setCurrentSongRating:(float)rating;
-
-/*!
- * @method eqPresets
- */
-- (NSArray *)eqPresets;
-
-/*!
- * @method currentEQPresetIndex
- */
-- (int)currentEQPresetIndex;
-
-/*!
- * @method volume
- */
-- (float)volume;
-
-/*!
- * @method setVolume:
- */
-- (BOOL)setVolume:(float)volume;
-
-/*!
- * @method shuffleEnabled
- */
-- (BOOL)shuffleEnabled;
-
-/*!
- * @method setShuffleEnabled:
- */
-- (BOOL)setShuffleEnabled:(BOOL)enabled;
-
-/*!
- * @method repeatMode
- */
-- (ITMTRemotePlayerRepeatMode)repeatMode;
-
-/*!
- * @method setRepeatMode:
- */
-- (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode;
-
-/*!
- * @method play
- */
-- (BOOL)play;
-
-/*!
- * @method pause
- */
-- (BOOL)pause;
-
+    @method activate
+    @result A BOOL indicating success or failure.
+*/
+- (BOOL)activate;
 /*!
- * @method goToNextSong
- */
-- (BOOL)goToNextSong;
+    @method deactivate
+    @result A BOOL indicating success or failure.
+*/
+- (BOOL)deactivate;
 
 /*!
- * @method goToPreviousSong
- */
-- (BOOL)goToPreviousSong;
-
-/*!
- * @method forward
- */
-- (BOOL)forward;
-
+    @method currentPlayer
+    @result An ITMTPlayer object representing the currently active player that the remote is controlling.
+*/
+- (ITMTPlayer *)currentPlayer
 /*!
- * @method rewind
- */
-- (BOOL)rewind;
-
-/*!
- * @method switchToPlaylistAtIndex:
- */
-- (BOOL)switchToPlaylistAtIndex:(int)index;
-
-/*!
- * @method switchToSongAtIndex:
- */
-- (BOOL)switchToSongAtIndex:(int)index;
-
-/*!
- * @method switchToEQAtIndex:
- */
-- (BOOL)switchToEQAtIndex:(int)index;
-
+    @method players
+    @result An NSArray filled with ITMTPlayer objects.
+*/
+- (NSArray *)players;
 @end
 
 /*!
* @class ITMTRemote
- */
   @class ITMTRemote
+*/
 @interface ITMTRemote : NSObject <ITMTRemote>
-
 @end
index 3337e55..8284318 100755 (executable)
@@ -1,257 +1,6 @@
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
 #import "ITMTRemote.h"
 
 @implementation ITMTRemote
-
-+ (id)remote
-{
-    return nil;
-}
-
-- (NSString *)remoteTitle
-{
-    return nil;
-}
-
-- (NSString *)remoteInformation
-{
-    return nil;
-}
-
-- (NSImage *)remoteIcon
-{
-    return nil;
-}
-
-- (BOOL)begin
-{
-    return NO;
-}
-
-- (BOOL)halt
-{
-    return NO;
-}
-
-- (NSString *)playerFullName
-{
-    return nil;
-}
-
-- (NSString *)playerSimpleName
-{
-    return nil;
-}
-
-- (NSDictionary *)capabilities
-{
-    return [NSDictionary dictionaryWithObjectsAndKeys:
-                [NSNumber numberWithBool: NO], @"Remote", // Set this to YES for a valid remote, otherwise the remote will be unusable.
-                [NSNumber numberWithBool: NO], @"Basic Track Control",
-                [NSNumber numberWithBool: NO], @"Track Information",
-                [NSNumber numberWithBool: NO], @"Track Navigation",
-                [NSNumber numberWithBool: NO], @"Upcoming Songs",
-                [NSNumber numberWithBool: NO], @"Playlists",
-                [NSNumber numberWithBool: NO], @"Volume",
-                [NSNumber numberWithBool: NO], @"Shuffle",
-                [NSNumber numberWithBool: NO], @"Repeat Modes",
-                [NSNumber numberWithBool: NO], @"Equalizer",
-                [NSNumber numberWithBool: NO], @"Track Rating",
-                nil];
-}
-
-- (BOOL)showPrimaryInterface
-{
-    return NO;
-}
-
-- (ITMTRemotePlayerRunningState)playerRunningState
-{
-    return nil;
-}
-
-- (ITMTRemotePlayerPlayingState)playerPlayingState
-{
-    return nil;
-}
-
-- (NSArray *)playlists
-{
-    return nil;
-}
-
-- (int)numberOfSongsInPlaylistAtIndex:(int)index
-{
-    return nil;
-}
-
-- (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
-{
-    return nil;
-}
-
-- (int)currentPlaylistIndex
-{
-    return nil;
-}
-
-- (NSString *)songTitleAtIndex:(int)index
-{
-    return nil;
-}
-
-- (int)currentAlbumTrackCount
-{
-    return nil;
-}
-
-- (int)currentSongTrack
-{
-    return nil;
-}
-
-- (NSString *)playerStateUniqueIdentifier
-{
-    return nil;
-}
-
-- (int)currentSongIndex
-{
-    return nil;
-}
-
-- (NSString *)currentSongTitle
-{
-    return nil;
-}
-
-- (NSString *)currentSongArtist
-{
-    return nil;
-}
-
-- (NSString *)currentSongAlbum
-{
-    return nil;
-}
-
-- (NSString *)currentSongGenre
-{
-    return nil;
-}
-
-- (NSString *)currentSongLength
-{
-    return nil;
-}
-
-- (NSString *)currentSongRemaining
-{
-    return nil;
-}
-
-- (float)currentSongRating
-{
-    return nil;
-}
-
-- (BOOL)setCurrentSongRating:(float)rating
-{
-    return NO;
-}
-
-/* - (BOOL)equalizerEnabled
-{
-    return NO;
-}
-
-- (BOOL)setEqualizerEnabled:(BOOL)enabled
-{
-    return NO;
-} */
-
-- (NSArray *)eqPresets
-{
-    return nil;
-}
-
-- (int)currentEQPresetIndex
-{
-    return nil;
-}
-
-- (float)volume
-{
-    return nil;
-}
-
-- (BOOL)setVolume:(float)volume
-{
-    return NO;
-}
-
-- (BOOL)shuffleEnabled
-{
-    return NO;
-}
-
-- (BOOL)setShuffleEnabled:(BOOL)enabled
-{
-    return NO;
-}
-
-- (ITMTRemotePlayerRepeatMode)repeatMode
-{
-    return ITMTRemotePlayerRepeatOff;
-}
-
-- (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
-{
-    return NO;
-}
-
-- (BOOL)play
-{
-    return NO;
-}
-
-- (BOOL)pause
-{
-    return NO;
-}
-
-- (BOOL)goToNextSong
-{
-    return NO;
-}
-
-- (BOOL)goToPreviousSong
-{
-    return NO;
-}
-
-- (BOOL)forward
-{
-    return NO;
-}
-
-- (BOOL)rewind
-{
-    return NO;
-}
-
-- (BOOL)switchToPlaylistAtIndex:(int)index
-{
-    return NO;
-}
-
-- (BOOL)switchToSongAtIndex:(int)index
-{
-    return NO;
-}
-
-- (BOOL)switchToEQAtIndex:(int)index
-{
-    return NO;
-}
-
 @end
diff --git a/ITMTTrack.h b/ITMTTrack.h
new file mode 100755 (executable)
index 0000000..2ddda6d
--- /dev/null
@@ -0,0 +1,29 @@
+/****************************************
+    ITMTRemote 1.0 (MenuTunes Remotes)
+    ITMTTrack.h
+    
+    Responsibility:
+        Joseph Spiros <joseph.spiros@ithinksw.com>
+    
+    Copyright (c) 2002 - 2003 by iThink Software.
+    All Rights Reserved.
+****************************************/
+
+#import <Cocoa/Cocoa.h>
+
+#import <ITMTRemote/ITMTRemote.h>
+
+@protocol ITMTTrack
+- (BOOL)addToPlaylist:(ITMTPlaylist *)playlist;
+- (BOOL)addToPlaylist:(ITMTPlaylist *)playlist atIndex:(int)index;
+
+- (ITMTPlayer *)player;
+- (NSArray *)playlists;
+
+- (BOOL)setValue:(id)value forProperty:(ITMTTrackProperty)property; // setting nil as value removes value completely
+- (id)valueOfProperty:(ITMTTrackProperty)property;
+- (NSDictionary *)propertiesAndValues;
+@end
+
+@interface ITMTTrack : NSObject
+@end
\ No newline at end of file
diff --git a/ITMTTrack.m b/ITMTTrack.m
new file mode 100755 (executable)
index 0000000..b8063fb
--- /dev/null
@@ -0,0 +1,6 @@
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
+#import "ITMTTrack.h"
+
+@implementation ITMTTrack
+@end
diff --git a/iTunesPlayer.h b/iTunesPlayer.h
new file mode 100755 (executable)
index 0000000..44f6e5e
--- /dev/null
@@ -0,0 +1,14 @@
+//
+//  iTunesPlayer.h
+//  MenuTunes
+//
+//  Created by Joseph Spiros on Sat Sep 06 2003.
+//  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+#import <ITMTRemote/ITMTRemote.h>
+
+@interface iTunesPlayer : ITMTPlayer <ITMTPlayer>
+@end
diff --git a/iTunesPlayer.m b/iTunesPlayer.m
new file mode 100755 (executable)
index 0000000..6a7b08b
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
+#import "iTunesPlayer.h"
+
+@implementation iTunesPlayer
+
+static iTunesPlayer *_sharediTunesPlayer = nil;
+
++ (id)sharedPlayer {
+    if ( _sharediTunesPlayer ) {
+        return _sharediTunesPlayer;
+    } else {
+        return _sharediTunesPlayer = [[iTunesPlayer alloc] init];
+    }
+}
+
+@end
index 992eb49..9408c63 100755 (executable)
@@ -1,20 +1,20 @@
 //
-//  iTunesRemoteControl.h
+//  iTunesRemote.h
 //  MenuTunes
 //
-//  Created by Matt L. Judy on Sun Jan 05 2003.
-//  Copyright (c) 2003 NibFile.com. All rights reserved.
+//  Created by Joseph Spiros on Sat Sep 06 2003.
+//  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
 //
 
-
 #import <Cocoa/Cocoa.h>
 #import <Carbon/Carbon.h>
+
 #import <ITMTRemote/ITMTRemote.h>
-#import <ITFoundation/ITFoundation.h>
 
-@interface iTunesRemote : ITMTRemote <ITMTRemote>
-{
-    ProcessSerialNumber savedPSN;
+@interface iTunesRemote : ITMTRemote <ITMTRemote> {
+    ProcessSerialNumber        _currentPSN;
+    iTunesPlayer _player;
+    BOOL _activated;
 }
 - (ProcessSerialNumber)iTunesPSN;
 @end
index 5a64303..bb9e464 100755 (executable)
+/* Copyright (c) 2002 - 2003 by iThink Software. All Rights Reserved. */
+
 #import "iTunesRemote.h"
 
+
 @implementation iTunesRemote
 
-+ (id)remote
-{
++ (id)remote {
     return [[[iTunesRemote alloc] init] autorelease];
 }
 
-- (NSString *)remoteTitle
-{
-    return @"iTunes Remote";
-}
-
-- (NSString *)remoteInformation
-{
-    return @"Default MenuTunes plugin to control iTunes, by iThink Software.";
-}
-
-- (NSImage *)remoteIcon
-{
+- (id)valueOfProperty:(ITMTRemoteProperty)property {
+    // Get from Info.plist
     return nil;
 }
 
-- (BOOL)begin
-{
-    savedPSN = [self iTunesPSN];
-    return YES;
-}
-
-- (BOOL)halt
-{
-    return YES;
-}
-
-- (NSString *)playerFullName
-{
-    return @"iTunes";
-}
-
-- (NSString *)playerSimpleName
-{
-    return @"iTunes";
-}
-
-- (NSDictionary *)capabilities
-{
-    return [NSDictionary dictionaryWithObjectsAndKeys:
-                [NSNumber numberWithBool: YES], @"Remote",
-                [NSNumber numberWithBool: YES], @"Basic Track Control",
-                [NSNumber numberWithBool: YES], @"Track Information",
-                [NSNumber numberWithBool: YES], @"Track Navigation",
-                [NSNumber numberWithBool: YES], @"Upcoming Songs",
-                [NSNumber numberWithBool: YES], @"Playlists",
-                [NSNumber numberWithBool: YES], @"Volume",
-                [NSNumber numberWithBool: YES], @"Shuffle",
-                [NSNumber numberWithBool: YES], @"Repeat Modes",
-                [NSNumber numberWithBool: YES], @"Equalizer",
-                [NSNumber numberWithBool: YES], @"Track Rating",
-                nil];
+- (NSDictionary *)propertiesAndValues {
+    // Get from Info.plist
+    return nil;
 }
 
-- (BOOL)showPrimaryInterface
-{
-    // Make this into AppleEvents... shouldn't be too hard, I'm just too tired to do it right now.
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pisf'), from:'null'() }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    // Still have to convert these to AEs:
-    // set visible of browser window 1 to true
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(1), ----:obj { form:'prop', want:'prop', seld:'pvis', from:obj { form:'indx', want:'cBrW', seld:1, from:'null'() } }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    // set minimized of browser window 1 to false
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(0), ----:obj { form:'prop', want:'prop', seld:'pMin', from:obj { form:'indx', want:'cBrW', seld:1, from:'null'() } }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-
-    return NO;
+- (ITMTPlayerStyle)playerStyle {
+    return ITMTSinglePlayerStyle;
 }
 
-- (ITMTRemotePlayerRunningState)playerRunningState
-{
-    NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
-    int i;
-    int count = [apps count];
-    
-    for (i = 0; i < count; i++) {
-        if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
-            return ITMTRemotePlayerRunning;
+- (BOOL)activate {
+    if ( !_activated ) {
+        if ( [self iTunesIsRunning] ) {
+            _currentPSN = [self iTunesPSN];
+        } else {
+            if ( [self launchiTunes] ) {
+                _currentPSN = [self iTunesPSN];
+            } else {
+                return NO;
+            }
+        }
+        if ( ( _player = [iTunesPlayer sharedPlayer] ) ) {
+            _activated = YES;
+            return YES;
         }
+    } else {
+        return NO;
     }
-    return ITMTRemotePlayerNotRunning;
 }
 
-- (ITMTRemotePlayerPlayingState)playerPlayingState
-{
-    long result = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlS'), from:'null'() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-    
-    switch (result)
-    {
-        default:
-        case 'kPSS':
-            return ITMTRemotePlayerStopped;
-        case 'kPSP':
-            return ITMTRemotePlayerPlaying;
-        case 'kPSp':
-            return ITMTRemotePlayerPaused;
-        case 'kPSR':
-            return ITMTRemotePlayerRewinding;
-        case 'kPSF':
-            return ITMTRemotePlayerForwarding;
+- (BOOL)deactivate {
+    if ( _activated ) {
+        _currentPSN = kNoProcess;
+        _player = nil;
+        _activated = NO;
+        return YES;
+    } else {
+        return NO;
     }
-    
-    return ITMTRemotePlayerStopped;
 }
 
-- (NSArray *)playlists
-{
-    long i = 0;
-    const signed long numPlaylists = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cPly'), '----':()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
-    NSMutableArray *playlists = [[NSMutableArray alloc] initWithCapacity:numPlaylists];
-    
-    for (i = 1; i <= numPlaylists; i++) {
-        const long j = i;
-        NSString *sendStr = [NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cPly'), seld:long(%lu), from:'null'() } }",(unsigned long)j];
-        NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:sendStr eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-        [playlists addObject:theObj];
+- (ITMTPlayer *)currentPlayer {
+    if (_activated) {
+        return _player;
+    } else {
+        return nil;
     }
-    return [playlists autorelease];
-}
-
-- (int)numberOfSongsInPlaylistAtIndex:(int)index
-{
-    return [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:[NSString stringWithFormat:@"kocl:type('cTrk'), '----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:'null'() }",index] eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
-}
-
-- (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
-{
-    int realResult = [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pcls" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-    
-
-    switch (realResult)
-          {
-          case 'cLiP':
-                 return ITMTRemotePlayerLibraryPlaylist;
-                 break;
-          case 'cRTP':
-                 return ITMTRemotePlayerRadioPlaylist;
-                 break;
-          default:
-                 return ITMTRemotePlayerPlaylist;
-          }
-}
-
-- (int)currentPlaylistIndex
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)songTitleAtIndex:(int)index
-{
-    return [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }",index] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (int)currentAlbumTrackCount
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pTrC" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (int)currentSongTrack
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pTrN" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
 }
 
-- (NSString *)playerStateUniqueIdentifier
-{
-    return [NSString stringWithFormat:@"%i-%i", [self currentPlaylistIndex], [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pDID" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN]];
-}
-
-- (int)currentSongIndex
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)currentSongTitle
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)currentSongArtist
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)currentSongAlbum
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)currentSongGenre
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)currentSongLength
-{
-    return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pTim" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-}
-
-- (NSString *)currentSongRemaining
-{
-    long duration = [[ITAppleEventCenter sharedCenter]
-                        sendTwoTierAEWithRequestedKeyForNumber:@"pDur" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-    long current = [[ITAppleEventCenter sharedCenter]
-                        sendAEWithRequestedKeyForNumber:@"pPos" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-
-    return [[NSNumber numberWithLong:duration - current] stringValue];
-}
-
-- (float)currentSongRating
-{
-    return (float)[[ITAppleEventCenter sharedCenter]
-                sendTwoTierAEWithRequestedKeyForNumber:@"pRte" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100.0;
-}
-
-- (BOOL)setCurrentSongRating:(float)rating
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pRte'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }",(long)(rating*100),[self currentSongIndex]] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    return YES;
-}
-
-/* - (BOOL)equalizerEnabled
-{
-    int thingy = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:type('prop'), want:type('prop'), seld:type('pEQ '), from:() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-    NSLog(@"Debug equalizerEnabled: %i", thingy);
-    return thingy;
-}
-
-- (BOOL)setEqualizerEnabled:(BOOL)enabled
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }",enabled] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    return YES;
-} */
-
-- (NSArray *)eqPresets
-{
-    int i;
-    long numPresets = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cEQP'), '----':(), &subj:()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
-    NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
-    
-    for (i = 1; i <= numPresets; i++) {
-        NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() } }",i] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-        if (theObj) {
-            [presets addObject:theObj];
-        }
+- (NSArray *)players {
+    if (_activated) {
+        return [NSArray arrayWithObject:_player];
+    } else {
+        return nil;
     }
-    return [presets autorelease];
 }
 
-- (int)currentEQPresetIndex
-{
-    int result;
-    result = [[ITAppleEventCenter sharedCenter]
-                sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pEQP" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-    return result;
-}
-
-- (float)volume
-{
-    return (float)[[ITAppleEventCenter sharedCenter] sendAEWithRequestedKeyForNumber:@"pVol" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100;
-}
+#pragma mark -
+#pragma mark INTERNAL METHODS
+#pragma mark -
 
-- (BOOL)setVolume:(float)volume
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }",(long)(volume*100)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
+- (BOOL)launchiTunes {
     return NO;
 }
 
-- (BOOL)shuffleEnabled
-{
-    int result = [[ITAppleEventCenter sharedCenter]
-                sendTwoTierAEWithRequestedKeyForNumber:@"pShf" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-    return result;
-}
-
-- (BOOL)setShuffleEnabled:(BOOL)enabled
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu) ----:obj { form:'prop', want:type('prop'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",(unsigned long)enabled] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    return YES;
-}
-
-- (ITMTRemotePlayerRepeatMode)repeatMode
-{
-    FourCharCode m00f = 0;
-    int result = 0;
-    m00f = [[ITAppleEventCenter sharedCenter]
-                sendTwoTierAEWithRequestedKeyForNumber:@"pRpt" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
-
-    switch (m00f)
-          {
-          case 'kRp0':
-                 result = ITMTRemotePlayerRepeatOff;
-                 break;
-          case 'kRp1':
-                 result = ITMTRemotePlayerRepeatOne;
-                 break;
-          case 'kRpA':
-                 result = ITMTRemotePlayerRepeatAll;
-                 break;
-          }
-    
-    return result;
-}
-
-- (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
-{
-    char *m00f = NULL;
-    switch (repeatMode)
-          {
-          case ITMTRemotePlayerRepeatOff:
-                 m00f = "kRp0";
-                 break;
-          case ITMTRemotePlayerRepeatOne:
-                 m00f = "kRp1";
-                 break;
-          case ITMTRemotePlayerRepeatAll:
-                 m00f = "kRpA";
-                 break;
-          }
-
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:type('%s') ----:obj { form:'prop', want:type('pRpt'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",m00f] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)play
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)pause
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)goToNextSong
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)goToPreviousSong
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)forward
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Fast" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)rewind
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Rwnd" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)switchToPlaylistAtIndex:(int)index
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)switchToSongAtIndex:(int)index
-{
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:() } }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
-    return YES;
-}
-
-- (BOOL)switchToEQAtIndex:(int)index
-{
-    // index should count from 0, but itunes counts from 1, so let's add 1.
-    [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pEQP'), from:'null'() }, data:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() }",(index+1)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
-    return YES;
+- (BOOL)iTunesIsRunning {
+    return NO;
 }
 
 - (ProcessSerialNumber)iTunesPSN
 {
-    /*NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
-    ProcessSerialNumber number;
-    int i;
-    int count = [apps count];
-    
-    number.highLongOfPSN = kNoProcess;
-    
-    for (i = 0; i < count; i++)
-    {
-        NSDictionary *curApp = [apps objectAtIndex:i];
-        
-        if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
-        {
-            number.highLongOfPSN = [[curApp objectForKey:
-                @"NSApplicationProcessSerialNumberHigh"] intValue];
-            number.lowLongOfPSN = [[curApp objectForKey:
-                @"NSApplicationProcessSerialNumberLow"] intValue];
-        }
-    }
-    return number;*/
     ProcessSerialNumber number;
     number.highLongOfPSN = kNoProcess;
     number.lowLongOfPSN = 0;