2 IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in
3 consideration of your agreement to the following terms, and your use, installation,
4 modification or redistribution of this Apple software constitutes acceptance of these
5 terms. If you do not agree with these terms, please do not use, install, modify or
6 redistribute this Apple software.
8 In consideration of your agreement to abide by the following terms, and subject to these
9 terms, Apple grants you a personal, non-exclusive license, under Appleās copyrights in
10 this original Apple software (the "Apple Software"), to use, reproduce, modify and
11 redistribute the Apple Software, with or without modifications, in source and/or binary
12 forms; provided that if you redistribute the Apple Software in its entirety and without
13 modifications, you must retain this notice and the following text and disclaimers in all
14 such redistributions of the Apple Software. Neither the name, trademarks, service marks
15 or logos of Apple Inc. may be used to endorse or promote products derived from
16 the Apple Software without specific prior written permission from Apple. Except as expressly
17 stated in this notice, no other rights or licenses, express or implied, are granted by Apple
18 herein, including but not limited to any patent rights that may be infringed by your
19 derivative works or by other works in which the Apple Software may be incorporated.
21 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES,
22 EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
23 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
24 USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
26 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
27 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
29 REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
30 WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
31 OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #import "AudioPlayer.h"
35 #import "MenuHandler.h"
36 #import <Cocoa/Cocoa.h>
37 #import <WebKit/npapi.h>
38 #import <WebKit/npfunctions.h>
39 #import <WebKit/npruntime.h>
41 // Browser function table
42 static NPNetscapeFuncs* browser;
44 // Structure for per-instance storage
45 @interface PluginObject : NSObject <AudioPlayerDelegate> {
46 AudioPlayer *_audioPlayer;
47 MenuHandler *_menuHandler;
50 @property (nonatomic, readonly) NPP npp;
51 @property (nonatomic) NPWindow window;
52 @property (nonatomic, strong, readonly) NSURL *audioURL;
53 @property (nonatomic, copy, readonly) NSString *displayString;
54 @property (nonatomic, strong, readonly) MenuHandler *menuHandler;
55 @property (nonatomic) BOOL hasFocus;
56 @property (nonatomic, readonly, getter=isPlayingAudio) BOOL playingAudio;
57 @property (nonatomic, getter=isMuted) BOOL muted;
59 - (instancetype)initWithNPP:(NPP)npp audioURL:(NSURL *)audioURL;
63 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData*);
64 NPError NPP_Destroy(NPP instance, NPSavedData**);
65 NPError NPP_SetWindow(NPP instance, NPWindow*);
66 NPError NPP_NewStream(NPP instance, NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype);
67 NPError NPP_DestroyStream(NPP instance, NPStream*, NPReason);
68 int32_t NPP_WriteReady(NPP instance, NPStream*);
69 int32_t NPP_Write(NPP instance, NPStream*, int32_t offset, int32_t len, void* buffer);
70 void NPP_StreamAsFile(NPP instance, NPStream*, const char* fname);
71 void NPP_Print(NPP instance, NPPrint* platformPrint);
72 int16_t NPP_HandleEvent(NPP instance, void* event);
73 void NPP_URLNotify(NPP instance, const char* URL, NPReason, void* notifyData);
74 NPError NPP_GetValue(NPP instance, NPPVariable, void *value);
75 NPError NPP_SetValue(NPP instance, NPNVariable, void *value);
78 // Mach-o entry points
79 NPError NP_Initialize(NPNetscapeFuncs *browserFuncs);
80 NPError NP_GetEntryPoints(NPPluginFuncs *);
81 void NP_Shutdown(void);
84 static void invalidatePlugin(PluginObject *);
86 @implementation PluginObject
88 - (instancetype)initWithNPP:(NPP)npp audioURL:(NSURL *)audioURL
90 if (!(self = [super init]))
94 _audioURL = [audioURL retain];
95 _audioPlayer = [[AudioPlayer alloc] initWithURL:audioURL];
96 _audioPlayer.audioPlayerDelegate = self;
99 if (browser->getvalue(npp, NPNVmuteAudioBool, &isMuted) != NPERR_NO_ERROR)
101 self.muted = isMuted;
103 [self _invalidateDisplayString];
111 [_menuHandler release];
112 [_audioPlayer release];
113 [_displayString release];
118 - (MenuHandler *)menuHandler
121 _menuHandler = [[MenuHandler alloc] initWithAudioPlayer:_audioPlayer];
126 - (BOOL)isPlayingAudio
128 return _audioPlayer.isPlaying;
133 return _audioPlayer.isMuted;
136 - (void)setMuted:(BOOL)muted
138 _audioPlayer.muted = muted;
141 - (void)readyStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer
143 [self _invalidateDisplayString];
144 invalidatePlugin(self);
147 - (void)mutedStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer
151 - (void)playStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer
153 [self _invalidateDisplayString];
154 invalidatePlugin(self);
155 browser->setvalue(_npp, NPPVpluginIsPlayingAudio, _audioPlayer.isPlaying);
158 - (void)_invalidateDisplayString
160 [_displayString release];
163 if (!_audioPlayer.isReadyToPlay)
164 prefix = @"Loading: ";
165 else if (_audioPlayer.isPlaying)
166 prefix = @"Playing: ";
168 prefix = @"Ready to play: ";
170 _displayString = [[NSString stringWithFormat:@"%@ %@", prefix, _audioURL.absoluteString] retain];
176 NPError NP_Initialize(NPNetscapeFuncs* browserFuncs)
178 browser = browserFuncs;
179 return NPERR_NO_ERROR;
182 NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
184 pluginFuncs->version = 11;
185 pluginFuncs->size = sizeof(pluginFuncs);
186 pluginFuncs->newp = NPP_New;
187 pluginFuncs->destroy = NPP_Destroy;
188 pluginFuncs->setwindow = NPP_SetWindow;
189 pluginFuncs->newstream = NPP_NewStream;
190 pluginFuncs->destroystream = NPP_DestroyStream;
191 pluginFuncs->asfile = NPP_StreamAsFile;
192 pluginFuncs->writeready = NPP_WriteReady;
193 pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
194 pluginFuncs->print = NPP_Print;
195 pluginFuncs->event = NPP_HandleEvent;
196 pluginFuncs->urlnotify = NPP_URLNotify;
197 pluginFuncs->getvalue = NPP_GetValue;
198 pluginFuncs->setvalue = NPP_SetValue;
200 return NPERR_NO_ERROR;
203 void NP_Shutdown(void)
208 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
210 // Create per-instance storage
211 // Ask the browser if it supports the CoreGraphics drawing model
212 NPBool supportsCoreGraphics;
213 if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR)
214 supportsCoreGraphics = FALSE;
216 if (!supportsCoreGraphics)
217 return NPERR_INCOMPATIBLE_VERSION_ERROR;
219 // If the browser supports the CoreGraphics drawing model, enable it.
220 browser->setvalue(instance, NPPVpluginDrawingModel, (void *)NPDrawingModelCoreGraphics);
222 // If the browser supports the Cocoa event model, enable it.
223 NPBool supportsCocoa;
224 if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR)
225 supportsCocoa = FALSE;
228 return NPERR_INCOMPATIBLE_VERSION_ERROR;
230 browser->setvalue(instance, NPPVpluginEventModel, (void *)NPEventModelCocoa);
232 NSURL *audioURL = nil;
233 for (int16_t i = 0; i < argc; i++) {
234 if (!strcasecmp(argn[i], "audiourl")) {
235 NSString *urlString = [NSString stringWithUTF8String:argv[i]];
237 audioURL = [NSURL URLWithString:urlString];
242 PluginObject *obj = [[PluginObject alloc] initWithNPP:instance audioURL:audioURL];
243 instance->pdata = obj;
245 return NPERR_NO_ERROR;
248 NPError NPP_Destroy(NPP instance, NPSavedData** save)
250 // Free per-instance storage
251 PluginObject *obj = instance->pdata;
254 return NPERR_NO_ERROR;
257 NPError NPP_SetWindow(NPP instance, NPWindow* window)
259 PluginObject *obj = instance->pdata;
260 obj.window = *window;
262 return NPERR_NO_ERROR;
265 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
267 *stype = NP_ASFILEONLY;
268 return NPERR_NO_ERROR;
271 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
273 return NPERR_NO_ERROR;
276 int32_t NPP_WriteReady(NPP instance, NPStream* stream)
281 int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
286 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
290 void NPP_Print(NPP instance, NPPrint* platformPrint)
294 static void handleDraw(PluginObject *obj, NPCocoaEvent *event)
296 NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain];
298 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:event->data.draw.context flipped:YES];
300 [NSGraphicsContext setCurrentContext:context];
302 NSRect rect = NSMakeRect(0, 0, obj.window.width, obj.window.height);
304 [[NSColor lightGrayColor] set];
305 [NSBezierPath fillRect:rect];
307 // If the plugin has focus, draw a focus indicator
309 [[NSColor blackColor] set];
310 NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect];
311 [path setLineWidth:5];
315 [obj.displayString drawAtPoint:NSMakePoint(10, 10) withAttributes:nil];
317 [NSGraphicsContext setCurrentContext:oldContext];
318 [oldContext release];
321 static void invalidatePlugin(PluginObject *obj)
326 rect.right = obj.window.width;
327 rect.bottom = obj.window.height;
329 browser->invalidaterect(obj.npp, &rect);
333 static void handleMouseEvent(PluginObject *obj, NPCocoaEvent *event)
335 if (event->data.mouse.buttonNumber == 1)
336 browser->popupcontextmenu(obj.npp, (NPNSMenu *)[obj.menuHandler menu]);
339 int16_t NPP_HandleEvent(NPP instance, void* event)
341 PluginObject *obj = instance->pdata;
343 NPCocoaEvent *cocoaEvent = event;
345 switch (cocoaEvent->type) {
346 case NPCocoaEventFocusChanged:
347 obj.hasFocus = cocoaEvent->data.focus.hasFocus;
348 invalidatePlugin(obj);
351 case NPCocoaEventDrawRect:
352 handleDraw(obj, cocoaEvent);
355 case NPCocoaEventMouseDown:
356 case NPCocoaEventMouseUp:
358 // FIXME: NPCocoaEventMouseMoved is currently disabled in order to see other events more clearly
359 // without "drowning" in mouse moved events.
360 // case NPCocoaEventMouseMoved:
361 case NPCocoaEventMouseEntered:
362 case NPCocoaEventMouseExited:
363 case NPCocoaEventMouseDragged:
364 case NPCocoaEventScrollWheel:
365 handleMouseEvent(obj, cocoaEvent);
375 void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
380 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
382 PluginObject *obj = instance->pdata;
385 case NPPVpluginIsPlayingAudio:
387 *((NPBool **)value) = obj.isPlayingAudio;
388 return NPERR_NO_ERROR;
391 return NPERR_GENERIC_ERROR;
395 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
397 PluginObject *obj = instance->pdata;
400 case NPNVmuteAudioBool:
402 obj.muted = *((NPBool *)value);
403 return NPERR_NO_ERROR;
406 return NPERR_GENERIC_ERROR;