Reviewed by Jon, Tim and Mark.
[WebKit-https.git] / WebKitExamplePlugins / NetscapeCocoaPlugin / main.m
1 /*
2  IMPORTANT:  This Apple software is supplied to you by Apple Computer, 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.
7  
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 Computer, 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.
20  
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.
25  
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.
32  */
33
34 #import <WebKit/npapi.h>
35 #import <WebKit/npfunctions.h>
36 #import <WebKit/npruntime.h>
37
38 #import <Cocoa/Cocoa.h>
39
40 // Browser function table
41 static NPNetscapeFuncs* browser;
42
43 // Structure for per-instance storage
44 typedef struct PluginObject
45 {
46     NPP npp;
47     
48     NPWindow window;
49     
50     NSString *string;
51     bool hasFocus;
52     bool mouseIsInsidePlugin;
53 } PluginObject;
54
55 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved);
56 NPError NPP_Destroy(NPP instance, NPSavedData** save);
57 NPError NPP_SetWindow(NPP instance, NPWindow* window);
58 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype);
59 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
60 int32 NPP_WriteReady(NPP instance, NPStream* stream);
61 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer);
62 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
63 void NPP_Print(NPP instance, NPPrint* platformPrint);
64 int16 NPP_HandleEvent(NPP instance, void* event);
65 void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData);
66 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
67 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
68
69 #pragma export on
70 // Mach-o entry points
71 NPError NP_Initialize(NPNetscapeFuncs *browserFuncs);
72 NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
73 void NP_Shutdown(void);
74 #pragma export off
75
76 NPError NP_Initialize(NPNetscapeFuncs* browserFuncs)
77 {
78     browser = browserFuncs;
79     return NPERR_NO_ERROR;
80 }
81
82 NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
83 {
84     pluginFuncs->version = 11;
85     pluginFuncs->size = sizeof(pluginFuncs);
86     pluginFuncs->newp = NPP_New;
87     pluginFuncs->destroy = NPP_Destroy;
88     pluginFuncs->setwindow = NPP_SetWindow;
89     pluginFuncs->newstream = NPP_NewStream;
90     pluginFuncs->destroystream = NPP_DestroyStream;
91     pluginFuncs->asfile = NPP_StreamAsFile;
92     pluginFuncs->writeready = NPP_WriteReady;
93     pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
94     pluginFuncs->print = NPP_Print;
95     pluginFuncs->event = NPP_HandleEvent;
96     pluginFuncs->urlnotify = NPP_URLNotify;
97     pluginFuncs->getvalue = NPP_GetValue;
98     pluginFuncs->setvalue = NPP_SetValue;
99     
100     return NPERR_NO_ERROR;
101 }
102
103 void NP_Shutdown(void)
104 {
105
106 }
107
108 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved)
109 {
110     // Create per-instance storage
111     PluginObject *obj = (PluginObject *)malloc(sizeof(PluginObject));
112     bzero(obj, sizeof(PluginObject));
113     
114     obj->npp = instance;
115     instance->pdata = obj;
116     
117     // Ask the browser if it supports the CoreGraphics drawing model
118     NPBool supportsCoreGraphics;
119     if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR)
120         supportsCoreGraphics = FALSE;
121     
122     if (!supportsCoreGraphics)
123         return NPERR_INCOMPATIBLE_VERSION_ERROR;
124     
125     // If the browser supports the CoreGraphics drawing model, enable it.
126     browser->setvalue(instance, NPNVpluginDrawingModel, (void *)NPDrawingModelCoreGraphics);
127
128     // If the browser supports the Cocoa event model, enable it.
129     NPBool supportsCocoa;
130     if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR)
131         supportsCocoa = FALSE;
132     
133     if (!supportsCocoa)
134         return NPERR_INCOMPATIBLE_VERSION_ERROR;
135     
136     browser->setvalue(instance, NPNVpluginEventModel, (void *)NPEventModelCocoa);
137     
138    
139     return NPERR_NO_ERROR;
140 }
141
142 NPError NPP_Destroy(NPP instance, NPSavedData** save)
143 {
144     // Free per-instance storage
145     PluginObject *obj = instance->pdata;
146     
147     [obj->string release];
148     free(obj);
149     
150     return NPERR_NO_ERROR;
151 }
152
153 NPError NPP_SetWindow(NPP instance, NPWindow* window)
154 {
155     PluginObject *obj = instance->pdata;
156     obj->window = *window;
157
158     return NPERR_NO_ERROR;
159 }
160  
161
162 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
163 {
164     *stype = NP_ASFILEONLY;
165     return NPERR_NO_ERROR;
166 }
167
168 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
169 {
170     return NPERR_NO_ERROR;
171 }
172
173 int32 NPP_WriteReady(NPP instance, NPStream* stream)
174 {
175     return 0;
176 }
177
178 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
179 {
180     return 0;
181 }
182
183 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
184 {
185 }
186
187 void NPP_Print(NPP instance, NPPrint* platformPrint)
188 {
189
190 }
191
192 static void handleDraw(PluginObject *obj)
193 {
194     NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain];
195     
196     NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:((NP_CGContext *)obj->window.window)->context
197                                                                             flipped:YES];
198
199
200     [NSGraphicsContext setCurrentContext:context];
201     
202     NSRect rect = NSMakeRect(0, 0, obj->window.width, obj->window.height);
203     
204     [[NSColor lightGrayColor] set];
205     [NSBezierPath fillRect:rect];
206
207     // If the plugin has focus, draw a focus indicator
208     if (obj->hasFocus) {
209         [[NSColor blackColor] set];
210         NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect];
211         [path setLineWidth:5];
212         [path stroke];
213     }
214     
215     [obj->string drawAtPoint:NSMakePoint(10, 10) withAttributes:nil];
216     
217     [NSGraphicsContext setCurrentContext:oldContext];
218 }
219
220 static NSString *eventType(NPCocoaEventType type)
221 {
222     switch (type) {
223         case NPCocoaEventMouseDown:
224             return @"NPCocoaEventMouseDown";
225         case NPCocoaEventMouseUp:
226             return @"NPCocoaEventMouseUp";            
227         case NPCocoaEventMouseMoved:
228             return @"NPCocoaEventMouseMoved";            
229         case NPCocoaEventMouseDragged:
230             return @"NPCocoaEventMouseDragged";            
231         case NPCocoaEventMouseEntered:
232             return @"NPCocoaEventMouseEntered";            
233         case NPCocoaEventMouseExited:
234             return @"NPCocoaEventMouseExited";
235         case NPCocoaEventKeyDown:
236             return @"NPCocoaEventKeyDown";
237         case NPCocoaEventKeyUp:
238             return @"NPCocoaEventKeyUp";
239         case NPCocoaEventFlagsChanged:
240             return @"NPCocoaEventFlagsChanged";
241         default:
242             return @"unknown";
243     }    
244 }
245
246 static void invalidatePlugin(PluginObject *obj)
247 {
248     NPRect rect;
249     rect.left = 0;
250     rect.top = 0;
251     rect.right = obj->window.width;
252     rect.bottom = obj->window.height;
253     
254     browser->invalidaterect(obj->npp, &rect);    
255 }
256
257
258 static void handleMouseEvent(PluginObject *obj, NPCocoaEvent *event)
259 {
260     NSString *string = [NSString stringWithFormat:@"Type: %@\n"
261                                                    "Modifier flags: 0x%x\n"
262                                                    "Coordinates: (%g, %g)\n"
263                                                    "Button number: %d\n"
264                                                    "Click count: %d\n"
265                                                    "Delta: (%g, %g, %g)",
266                                                    eventType(event->type), 
267                                                    event->event.mouse.modifierFlags,
268                                                    event->event.mouse.pluginX,
269                                                    event->event.mouse.pluginY,
270                                                    event->event.mouse.buttonNumber,
271                                                    event->event.mouse.clickCount,
272                                                    event->event.mouse.deltaX, event->event.mouse.deltaY, event->event.mouse.deltaZ];
273     
274     
275     [obj->string release];
276     obj->string = [string retain];
277  
278     invalidatePlugin(obj);
279 }
280
281 static void handleKeyboardEvent(PluginObject *obj, NPCocoaEvent *event)
282 {
283     NSString *string = [NSString stringWithFormat:@"Type: %@\n"
284                         "Modifier flags: 0x%x\n"
285                         "Characters: %@\n"
286                         "Characters ignoring modifiers: %@\n"
287                         "Is a repeat: %@\n"
288                         "Key code: %d",
289                         eventType(event->type), 
290                         event->event.key.modifierFlags,
291                         event->event.key.characters,
292                         event->event.key.charactersIgnoringModifiers,
293                         event->event.key.isARepeat ? @"YES" : @"NO",
294                         event->event.key.keyCode];
295     
296     
297     [obj->string release];
298     obj->string = [string retain];
299     
300     invalidatePlugin(obj);
301 }
302
303 int16 NPP_HandleEvent(NPP instance, void* event)
304 {
305     PluginObject *obj = instance->pdata;
306
307     NPCocoaEvent *cocoaEvent = event;
308     
309     switch(cocoaEvent->type) {
310         case NPCocoaEventFocusChanged:
311             obj->hasFocus = cocoaEvent->event.focus.hasFocus;
312             invalidatePlugin(obj);
313             return 1;
314             
315         case NPCocoaEventDrawRect:
316             handleDraw(obj);
317             return 1;
318         
319         case NPCocoaEventKeyDown:
320         case NPCocoaEventKeyUp:
321         case NPCocoaEventFlagsChanged:
322             handleKeyboardEvent(obj, cocoaEvent);
323             return 1;
324             
325         case NPCocoaEventMouseDown:
326         case NPCocoaEventMouseUp:
327             
328         // FIXME: NPCocoaEventMouseMoved is currently disabled in order to see other events more clearly
329         // without "drowning" in mouse moved events.
330 //        case NPCocoaEventMouseMoved:
331         case NPCocoaEventMouseEntered:
332         case NPCocoaEventMouseExited:
333         case NPCocoaEventMouseDragged:
334         case NPCocoaEventScrollWheel:
335             handleMouseEvent(obj, cocoaEvent);
336             return 1;
337     }
338     
339     return 0;
340 }
341
342 void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
343 {
344
345 }
346
347 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
348 {
349     return NPERR_GENERIC_ERROR;
350 }
351
352 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
353 {
354     return NPERR_GENERIC_ERROR;
355 }