AppleEvented it all and lost all my sleep. AEPrintDescToHandle is reporting completel...
[MenuTunes.git] / iTunesRemote.m
1 #import "iTunesRemote.h"
2
3 @implementation iTunesRemote
4
5 + (id)remote
6 {
7     return [[[iTunesRemote alloc] init] autorelease];
8 }
9
10 - (NSString *)title
11 {
12     return @"iTunes Plug-in";
13 }
14
15 - (NSString *)information;
16 {
17     return @"Default MenuTunes plugin to control iTunes. Written by iThink Software.";
18 }
19
20 - (NSImage *)icon
21 {
22     return nil;
23 }
24
25 - (BOOL)begin
26 {
27     iTunesPSN = [self iTunesPSN];
28
29     //Register for application termination in NSWorkspace
30     [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationLaunched:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
31     [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationTerminated:) name:NSWorkspaceDidTerminateApplicationNotification object:nil];
32
33     return YES;
34 }
35
36 - (BOOL)halt
37 {
38     iTunesPSN.highLongOfPSN = kNoProcess;
39
40     //Unregister for application termination in NSWorkspace
41     [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
42
43     return YES;
44 }
45
46 - (BOOL)isAppRunning
47 {
48     NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
49     int i,count = [apps count];
50
51     for (i = 0; i < count; i++) {
52         if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"]
53                 isEqualToString:@"iTunes"]) {
54             return YES;
55         }
56     }
57     return NO;
58 }
59
60 - (PlayerState)playerState
61 {
62     long result = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlS'), from:'null'() }" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
63
64     switch (result)
65            {
66            default:
67            case 'kPSS':
68                   return stopped;
69            case 'kPSP':
70                   return paused;
71            case 'kPSp':
72                   return playing;
73            case 'kPSR':
74                   return rewinding;
75            case 'kPSF':
76                   return forwarding;
77            }
78
79     return stopped;
80 }
81
82 - (NSArray *)playlists
83 {
84     long i = 0;
85     const signed long numPlaylists = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cPly'), '----':(), &subj:()" eventClass:@"core" eventID:@"cnte" appPSN:[self iTunesPSN]];
86     NSMutableArray *playlists = [[NSMutableArray alloc] initWithCapacity:numPlaylists];
87     NSLog(@"entered playlist");
88
89            for (i = 1; i <= numPlaylists; i++) {
90                   const long j = i;
91                   NSString *sendStr = [NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cPly'), seld:%lu, from:'null'() } }",(unsigned long)j];
92                   NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:sendStr eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
93                   NSLog(@"sent event cur %d max %d",i,numPlaylists);
94                   [playlists addObject:theObj];
95            }
96            NSLog(@"playlists end");
97            return [playlists autorelease];
98 }
99
100 - (int)numberOfSongsInPlaylistAtIndex:(int)index
101 {
102     return [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:[NSString stringWithFormat:@"kocl:'cTrk', '----':obj { form:'indx', want:type('cPly'), seld:%i, from:'null'() }",index] eventClass:@"core" eventID:@"cnte" appPSN:[self iTunesPSN]];
103 }
104
105 - (NSString *)classOfPlaylistAtIndex:(int)index
106 {
107     int realResult = [[ITAppleEventCenter sharedCenter]
108                 sendTwoTierAEWithRequestedKeyForNumber:@"pcls" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
109
110     if (realResult == 'cRTP') return @"radio tuner playlist";
111     else return @"playlist";
112 }
113
114 - (int)currentPlaylistIndex
115 {
116     int result;
117     result = [[ITAppleEventCenter sharedCenter]
118                 sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
119     return result;
120 }
121
122 - (NSString *)songTitleAtIndex:(int)index
123 {
124     return [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cTrk'), seld:%i, from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }",index] eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
125 }
126
127 - (int)currentSongIndex
128 {
129     int result;
130     result = [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
131     return result;
132 }
133
134 - (NSString *)currentSongTitle
135 {
136     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
137 }
138
139 - (NSString *)currentSongArtist
140 {
141     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
142 }
143
144 - (NSString *)currentSongAlbum
145 {
146     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
147 }
148
149 - (NSString *)currentSongGenre
150 {
151     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
152 }
153
154 - (NSString *)currentSongLength
155 {
156     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pTim" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
157 }
158
159 - (NSString *)currentSongRemaining
160 {
161     long duration = [[ITAppleEventCenter sharedCenter]
162                         sendTwoTierAEWithRequestedKeyForNumber:@"pDur" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
163     long current = [[ITAppleEventCenter sharedCenter]
164                         sendAEWithRequestedKeyForNumber:@"pPos" eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
165
166     return [[NSNumber numberWithLong:duration - current] stringValue];
167 }
168
169 - (NSArray *)eqPresets;
170 {
171     int i;
172     long numPresets = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cEQP'), '----':(), &subj:()" eventClass:@"core" eventID:@"cnte" appPSN:[self iTunesPSN]];
173     NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
174
175
176            for (i = 0; i < numPresets; i++) {
177                   NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cEQP'), seld:%d, from:'null'() } }",i] eventClass:@"core" eventID:@"getd" appPSN:[self iTunesPSN]];
178                   [presets addObject:theObj];
179            }
180            return [presets autorelease];
181 }
182
183 - (int)currentEQPresetIndex
184 {
185     int result;
186     result = [[ITAppleEventCenter sharedCenter]
187                 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
188                                                                                                           fromObjectByKey:@"pEQP" eventClass:@"core" eventID:@"getd"
189                                                                                                                                     appPSN:[self iTunesPSN]];
190     return result;
191 }
192
193 - (BOOL)play
194 {
195     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play"
196                                                                                                                                                    appPSN:[self iTunesPSN]];
197     return YES;
198 }
199
200 - (BOOL)pause
201 {
202     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus"
203                                                                                                                                                    appPSN:[self iTunesPSN]];
204     return YES;
205 }
206
207 - (BOOL)goToNextSong
208 {
209     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next"
210                                                                                                                                                    appPSN:[self iTunesPSN]];
211     return YES;
212 }
213
214 - (BOOL)goToPreviousSong
215 {
216     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev"
217                                                                                                                                                    appPSN:[self iTunesPSN]];
218     return YES;
219 }
220
221 - (BOOL)fastForward
222 {
223     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Fast"
224                                                                                                                                                    appPSN:[self iTunesPSN]];
225     return YES;
226 }
227
228 - (BOOL)rewind
229 {
230     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Rwnd"
231                                                                                                                                                    appPSN:[self iTunesPSN]];
232     return YES;
233 }
234
235
236 - (BOOL)switchToPlaylistAtIndex:(int)index
237 {
238     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'name', want:type('cPly'), seld:%i, from:'null'() }",index] eventClass:@"hook" eventID:@"Play" appPSN:[self iTunesPSN]];
239     return NO;
240 }
241
242 - (BOOL)switchToSongAtIndex:(int)index
243 {
244     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cTrk'), seld:%i, from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",index] eventClass:@"hook" eventID:@"Play" appPSN:[self iTunesPSN]];
245     return NO;
246 }
247
248 - (BOOL)switchToEQAtIndex:(int)index
249 {
250     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:obj { form:'name', want:type('cEQP'), seld:%i, from:'null'() }, '----':obj { form:'prop', want:type('prop'), seld:type('pEQP'), from:'null'() }",index] eventClass:@"core" eventID:@"setd" appPSN:[self iTunesPSN]];
251     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:1, '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }" eventClass:@"core" eventID:@"setd" appPSN:[self iTunesPSN]];
252     return NO;
253 }
254
255 - (ProcessSerialNumber)iTunesPSN
256 {
257     NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
258     ProcessSerialNumber number;
259     int i, count = [apps count];
260
261                number.highLongOfPSN = kNoProcess;
262
263                for (i = 0; i < count; i++)
264                       {
265                           NSDictionary *curApp = [apps objectAtIndex:i];
266                          
267                                  if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
268                                      {
269                                                 number.highLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberHigh"] intValue];
270                                                 number.lowLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberLow"] intValue];
271                                             }
272                              }
273     return number;}
274
275 - (void)applicationLaunched:(NSNotification *)note
276 {
277     NSDictionary *info = [note userInfo];
278
279     if ([[info objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
280         iTunesPSN.highLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberHigh"] longValue];
281         iTunesPSN.lowLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberLow"] longValue];
282
283         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTRemoteAppDidLaunchNotification" object:nil];
284     }
285 }
286
287 - (void)applicationTerminated:(NSNotification *)note
288 {
289     NSDictionary *info = [note userInfo];
290
291     if ([[info objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
292         iTunesPSN.highLongOfPSN = kNoProcess;
293         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTRemoteAppDidTerminateNotification" object:nil];
294     }
295 }
296
297 @end