/* -*- Mode: C; tab-width: 4; -*- */ /******************************************************************************* * Simple LiveConnect Sample Plugin * Copyright (c) 1996 Netscape Communications. All rights reserved. ******************************************************************************/ /* * npshell.c * * Netscape Client Plugin API * - Function that need to be implemented by plugin developers * * This file defines a "shell" plugin that plugin developers can use * as the basis for a real plugin. This shell just provides empty * implementations of all functions that the plugin can implement * that will be called by Netscape (the NPP_xxx methods defined in * npapi.h). * ******************************************************************************* * PLUGIN DEVELOPERS: * Implement your plugins here. * A sample text plugin is implemented here. * All the sample plugin does is displays any file with a * ".txt" extension in a scrolled text window. It uses Motif. ******************************************************************************/ #include #include #include "npapi.h" /* ** Define IMPLEMENT_Simple before including Simple.h to state that we're ** implementing the native methods of this plug-in here, and consequently ** need to access it's protected and private memebers. */ #define IMPLEMENT_Simple #include "Simple.h" /* Windows Includes */ #ifdef _WINDOWS #include #endif /* _WINDOWS */ /* ** Stuff for the NPP_SetWindow method: */ #ifdef XP_UNIX #include #include #include #endif /* XP_UNIX */ /******************************************************************************* * Instance state information about the plugin. * * PLUGIN DEVELOPERS: * Use this struct to hold per-instance information that you'll * need in the various functions in this file. ******************************************************************************/ typedef struct _PluginInstance { NPWindow* fWindow; uint16 fMode; /* Windows data members */ #ifdef _WINDOWS HWND fhWnd; WNDPROC fDefaultWindowProc; #endif /* _WINDOWS */ /* UNIX data members */ #ifdef XP_UNIX Window window; Display *display; uint32 x, y; uint32 width, height; #endif /* XP_UNIX */ } PluginInstance; void DisplayJavaMessage(NPP instance, char* msg, int len); /******************************************************************************* * Windows-only declarations ******************************************************************************/ #ifdef _WINDOWS LRESULT CALLBACK PluginWindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); const char* gInstanceLookupString = "instance->pdata"; #endif /******************************************************************************* * Mac-only declarations ******************************************************************************/ #ifdef macintosh NPBool StartDraw(NPWindow* window); void EndDraw(NPWindow* window); void DoDraw(PluginInstance* This); CGrafPort gSavePort; CGrafPtr gOldPort; #endif /******************************************************************************* * Unix-only declarations ******************************************************************************/ #ifdef XP_UNIX void Redraw(Widget w, XtPointer closure, XEvent *event); #endif /* XP_UNIX */ /******************************************************************************* * UNIX-only API calls ******************************************************************************/ #ifdef XP_UNIX char* NPP_GetMIMEDescription(void) { return("application/x-simple-plugin:smp:Simple LiveConnect Sample Plug-in"); } #define PLUGIN_NAME "Simple LiveConnect Sample Plug-in" #define PLUGIN_DESCRIPTION "Demonstrates a simple LiveConnected plug-in." NPError NPP_GetValue(void *future, NPPVariable variable, void *value) { NPError err = NPERR_NO_ERROR; if (variable == NPPVpluginNameString) *((char **)value) = PLUGIN_NAME; else if (variable == NPPVpluginDescriptionString) *((char **)value) = PLUGIN_DESCRIPTION; else err = NPERR_GENERIC_ERROR; return err; } #endif /* XP_UNIX */ /******************************************************************************* * General Plug-in Calls ******************************************************************************/ /* ** NPP_Initialize is called when your DLL is being loaded to do any ** DLL-specific initialization. */ NPError NPP_Initialize(void) { return NPERR_NO_ERROR; } /* ** We'll keep a global execution environment around to make our life ** simpler. */ JRIEnv* env; /* ** NPP_GetJavaClass is called during initialization to ask your plugin ** what its associated Java class is. If you don't have one, just return ** NULL. Otherwise, use the javah-generated "use_" function to both ** initialize your class and return it. If you can't find your class, an ** error will be signalled by "use_" and will cause the Navigator to ** complain to the user. */ jref NPP_GetJavaClass(void) { struct java_lang_Class* myClass; env = NPN_GetJavaEnv(); if (env == NULL) return NULL; /* Java disabled */ myClass = use_Simple(env); if (myClass == NULL) { /* ** If our class doesn't exist (the user hasn't installed it) then ** don't allow any of the Java stuff to happen. */ env = NULL; } return myClass; } /* ** NPP_Shutdown is called when your DLL is being unloaded to do any ** DLL-specific shut-down. You should be a good citizen and declare that ** you're not using your java class any more. This allows java to unload ** it, freeing up memory. */ void NPP_Shutdown(void) { if (env) unuse_Simple(env); } /* ** This function is a utility routine that calls back into Java to print ** messages to the Java Console and to stdout (via the native method, ** native_Simple_printToStdout, defined below). Sure, it's not a very ** interesting use of Java, but it gets the point across. */ void DisplayJavaMessage(NPP instance, char* msg, int len) { jref str, javaPeer; if (!env) { /* Java failed to initialize, so do nothing. */ return; } if (len == -1) len = strlen(msg); /* ** Use the JRI (see jri.h) to create a Java string from the input ** message: */ str = JRI_NewStringUTF(env, msg, len); /* ** Use the NPN_GetJavaPeer operation to get the Java instance that ** corresponds to our plug-in (an instance of the Simple class): */ javaPeer = NPN_GetJavaPeer(instance); /* ** Finally, call our plug-in's big "feature" -- the 'doit' method, ** passing the execution environment, the object, and the java ** string: */ Simple_doit(env, javaPeer, str); } /* ** NPP_New is called when your plugin is instantiated (i.e. when an EMBED ** tag appears on a page). */ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) { NPError result = NPERR_NO_ERROR; PluginInstance* This; char factString[60]; if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; instance->pdata = NPN_MemAlloc(sizeof(PluginInstance)); This = (PluginInstance*) instance->pdata; if (This == NULL) return NPERR_OUT_OF_MEMORY_ERROR; { /* mode is NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) */ This->fWindow = NULL; This->fMode = mode; #ifdef XP_UNIX This->window = 0; #endif /* XP_UNIX */ #ifdef _WINDOWS This->fhWnd = NULL; This->fDefaultWindowProc = NULL; #endif /* _WIDOWS */ /* PLUGIN DEVELOPERS: * Initialize fields of your plugin * instance data here. If the NPSavedData is non- * NULL, you can use that data (returned by you from * NPP_Destroy to set up the new plugin instance). */ } /* Show off some of that Java functionality: */ if (env) { jint v; /* ** Call the DisplayJavaMessage utility function to cause Java to ** write to the console and to stdout: */ DisplayJavaMessage(instance, "Hello world from npsimple!", -1); /* ** Also test out that fancy factorial method. It's a static ** method, so we'll need to use the class object in order to call ** it: */ v = Simple_fact(env, class_Simple(env), 10); sprintf(factString, "my favorite function returned %d\n", v); DisplayJavaMessage( instance, factString, -1 ); } return result; } NPError NPP_Destroy(NPP instance, NPSavedData** save) { PluginInstance* This; if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; This = (PluginInstance*) instance->pdata; /* PLUGIN DEVELOPERS: * If desired, call NP_MemAlloc to create a * NPSavedDate structure containing any state information * that you want restored if this plugin instance is later * recreated. */ if (This != NULL) { NPN_MemFree(instance->pdata); instance->pdata = NULL; } DisplayJavaMessage(instance, "Calling NPP_Destroy.", -1); return NPERR_NO_ERROR; } NPError NPP_SetWindow(NPP instance, NPWindow* window) { NPError result = NPERR_NO_ERROR; PluginInstance* This; DisplayJavaMessage(instance, "Calling NPP_SetWindow.", -1); if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; This = (PluginInstance*) instance->pdata; /* * PLUGIN DEVELOPERS: * Before setting window to point to the * new window, you may wish to compare the new window * info to the previous window (if any) to note window * size changes, etc. */ #ifdef XP_UNIX { Widget netscape_widget; This->window = (Window) window->window; This->x = window->x; This->y = window->y; This->width = window->width; This->height = window->height; This->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display; netscape_widget = XtWindowToWidget(This->display, This->window); XtAddEventHandler(netscape_widget, ExposureMask, FALSE, (XtEventHandler)Redraw, This); Redraw(netscape_widget, (XtPointer)This, NULL); } #endif /* XP_UNIX */ #ifdef _WINDOWS { if( This->fWindow != NULL ) // If we already have a window, clean // it up before trying to subclass // the new window. { if( (window == NULL) || ( window->window == NULL ) ) { // There is now no window to use. get rid of the old // one and exit. SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc); This->fDefaultWindowProc = NULL; This->fhWnd = NULL; return NPERR_NO_ERROR; } else if ( This->fWindow->window == window->window ) { // The new window is the same as the old one. Exit now. return NPERR_NO_ERROR; } else { // Clean up the old window, so that we can subclass the new // one later. SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc); This->fDefaultWindowProc = NULL; This->fhWnd = NULL; } } else if( (window == NULL) || ( window->window == NULL ) ) { // We can just get out of here if there is no current // window and there is no new window to use. return NPERR_NO_ERROR; } // At this point, we will subclass // window->window so that we can begin drawing and // receiving window messages. This->fDefaultWindowProc = (WNDPROC)SetWindowLong( (HWND)window->window, GWL_WNDPROC, (LONG)PluginWindowProc); This->fhWnd = (HWND) window->window; SetProp( This->fhWnd, gInstanceLookupString, (HANDLE)This); InvalidateRect( This->fhWnd, NULL, TRUE ); UpdateWindow( This->fhWnd ); } #endif /* _WINDOWS */ #ifdef macintosh This->fWindow = window; if( StartDraw( window ) ) { DoDraw(This); EndDraw( window ); } #endif /* macintosh */ This->fWindow = window; return result; } NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype) { PluginInstance* This; if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; This = (PluginInstance*) instance->pdata; DisplayJavaMessage(instance, "Calling NPP_NewStream.", -1); return NPERR_NO_ERROR; } /* PLUGIN DEVELOPERS: * These next 2 functions are directly relevant in a plug-in which * handles the data in a streaming manner. If you want zero bytes * because no buffer space is YET available, return 0. As long as * the stream has not been written to the plugin, Navigator will * continue trying to send bytes. If the plugin doesn't want them, * just return some large number from NPP_WriteReady(), and * ignore them in NPP_Write(). For a NP_ASFILE stream, they are * still called but can safely be ignored using this strategy. */ int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile * mode so we can take any size stream in our * write call (since we ignore it) */ int32 NPP_WriteReady(NPP instance, NPStream *stream) { PluginInstance* This; if (instance != NULL) This = (PluginInstance*) instance->pdata; DisplayJavaMessage(instance, "Calling NPP_WriteReady.", -1); /* Number of bytes ready to accept in NPP_Write() */ return STREAMBUFSIZE; } int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) { if (instance != NULL) { PluginInstance* This = (PluginInstance*) instance->pdata; } DisplayJavaMessage(instance, (char*)buffer, len); return len; /* The number of bytes accepted */ } NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) { PluginInstance* This; if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; This = (PluginInstance*) instance->pdata; DisplayJavaMessage(instance, "Calling NPP_DestroyStream.", -1); return NPERR_NO_ERROR; } void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) { PluginInstance* This; if (instance != NULL) This = (PluginInstance*) instance->pdata; DisplayJavaMessage(instance, "Calling NPP_StreamAsFile.", -1); } void NPP_Print(NPP instance, NPPrint* printInfo) { DisplayJavaMessage(instance, "Calling NPP_Print.", -1); if(printInfo == NULL) return; if (instance != NULL) { PluginInstance* This = (PluginInstance*) instance->pdata; if (printInfo->mode == NP_FULL) { /* * PLUGIN DEVELOPERS: * If your plugin would like to take over * printing completely when it is in full-screen mode, * set printInfo->pluginPrinted to TRUE and print your * plugin as you see fit. If your plugin wants Netscape * to handle printing in this case, set * printInfo->pluginPrinted to FALSE (the default) and * do nothing. If you do want to handle printing * yourself, printOne is true if the print button * (as opposed to the print menu) was clicked. * On the Macintosh, platformPrint is a THPrint; on * Windows, platformPrint is a structure * (defined in npapi.h) containing the printer name, port, * etc. */ void* platformPrint = printInfo->print.fullPrint.platformPrint; NPBool printOne = printInfo->print.fullPrint.printOne; /* Do the default*/ printInfo->print.fullPrint.pluginPrinted = FALSE; } else { /* If not fullscreen, we must be embedded */ /* * PLUGIN DEVELOPERS: * If your plugin is embedded, or is full-screen * but you returned false in pluginPrinted above, NPP_Print * will be called with mode == NP_EMBED. The NPWindow * in the printInfo gives the location and dimensions of * the embedded plugin on the printed page. On the * Macintosh, platformPrint is the printer port; on * Windows, platformPrint is the handle to the printing * device context. */ NPWindow* printWindow = &(printInfo->print.embedPrint.window); void* platformPrint = printInfo->print.embedPrint.platformPrint; } } } /******************************************************************************* * Define the Java native methods ******************************************************************************/ /* public native printToStdout(Ljava/lang/String;)V */ JRI_PUBLIC_API(void) native_Simple_printToStdout(JRIEnv* env, struct Simple* self, struct java_lang_String * s) { const char* chars = JRI_GetStringUTFChars(env, s); printf(chars); /* cross-platform UI! */ } /******************************************************************************* // NPP_URLNotify: // Notifies the instance of the completion of a URL request. // // NPP_URLNotify is called when Netscape completes a NPN_GetURLNotify or // NPN_PostURLNotify request, to inform the plug-in that the request, // identified by url, has completed for the reason specified by reason. The most // common reason code is NPRES_DONE, indicating simply that the request // completed normally. Other possible reason codes are NPRES_USER_BREAK, // indicating that the request was halted due to a user action (for example, // clicking the "Stop" button), and NPRES_NETWORK_ERR, indicating that the // request could not be completed (for example, because the URL could not be // found). The complete list of reason codes is found in npapi.h. // // The parameter notifyData is the same plug-in-private value passed as an // argument to the corresponding NPN_GetURLNotify or NPN_PostURLNotify // call, and can be used by your plug-in to uniquely identify the request. ******************************************************************************/ void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) { } /******************************************************************************* // NPP_HandleEvent: // Mac-only, but stub must be present for Windows // Delivers a platform-specific event to the instance. // // On the Macintosh, event is a pointer to a standard Macintosh EventRecord. // All standard event types are passed to the instance as appropriate. In general, // return TRUE if you handle the event and FALSE if you ignore the event. ******************************************************************************/ #ifndef XP_UNIX int16 NPP_HandleEvent(NPP instance, void* event) { int16 eventHandled = FALSE; #ifdef macintosh PluginInstance* This = (PluginInstance*) instance->pdata; EventRecord* ev = (EventRecord*) event; if (instance == NULL) return eventHandled; if (This != NULL && event != NULL) { switch (ev->what) { // // Draw ourselves on update events // case updateEvt: if( StartDraw( This->fWindow ) ) { DoDraw(This); EndDraw( This->fWindow ); } eventHandled = true; break; default: break; } } #endif /* macintosh */ return eventHandled; } #endif /* ndef XP_UNIX */ /******************************************************************************* * UNIX-only methods ******************************************************************************/ #ifdef XP_UNIX void Redraw(Widget w, XtPointer closure, XEvent *event) { PluginInstance* This = (PluginInstance*)closure; GC gc; XGCValues gcv; const char* text = "Hello World"; XtVaGetValues(w, XtNbackground, &gcv.background, XtNforeground, &gcv.foreground, 0); gc = XCreateGC(This->display, This->window, GCForeground|GCBackground, &gcv); XDrawRectangle(This->display, This->window, gc, 0, 0, This->width-1, This->height-1); XDrawString(This->display, This->window, gc, This->width/2 - 100, This->height/2, text, strlen(text)); } #endif /* XP_UNIX */ /******************************************************************************* * Windows-only methods ******************************************************************************/ #ifdef _WINDOWS LRESULT CALLBACK PluginWindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { PluginInstance* This = (PluginInstance*) GetProp(hWnd, gInstanceLookupString); switch( Msg ) { case WM_PAINT: { PAINTSTRUCT paintStruct; HDC hdc; hdc = BeginPaint( hWnd, &paintStruct ); TextOut(hdc, 0, 0, "Hello, World!", 15); EndPaint( hWnd, &paintStruct ); break; } default: { This->fDefaultWindowProc( hWnd, Msg, wParam, lParam); } } return 0; } #endif /* _WINDOWS */ /******************************************************************************* * Mac-only methods ******************************************************************************/ #ifdef macintosh NPBool StartDraw(NPWindow* window) { NP_Port* port; Rect clipRect; RGBColor col; if (window == NULL) return FALSE; port = (NP_Port*) window->window; if (window->clipRect.left < window->clipRect.right) { // Preserve the old port GetPort((GrafPtr*)&gOldPort); SetPort((GrafPtr)port->port); // Preserve the old drawing environment gSavePort.portRect = port->port->portRect; gSavePort.txFont = port->port->txFont; gSavePort.txFace = port->port->txFace; gSavePort.txMode = port->port->txMode; gSavePort.rgbFgColor = port->port->rgbFgColor; gSavePort.rgbBkColor = port->port->rgbBkColor; GetClip(gSavePort.clipRgn); // Setup our drawing environment clipRect.top = window->clipRect.top + port->porty; clipRect.left = window->clipRect.left + port->portx; clipRect.bottom = window->clipRect.bottom + port->porty; clipRect.right = window->clipRect.right + port->portx; SetOrigin(port->portx,port->porty); ClipRect(&clipRect); clipRect.top = clipRect.left = 0; TextSize(12); TextFont(geneva); TextMode(srcCopy); col.red = col.green = col.blue = 0; RGBForeColor(&col); col.red = col.green = col.blue = 65000; RGBBackColor(&col); return TRUE; } else return FALSE; } void EndDraw(NPWindow* window) { CGrafPtr myPort; NP_Port* port = (NP_Port*) window->window; SetOrigin(gSavePort.portRect.left, gSavePort.portRect.top); SetClip(gSavePort.clipRgn); GetPort((GrafPtr*)&myPort); myPort->txFont = gSavePort.txFont; myPort->txFace = gSavePort.txFace; myPort->txMode = gSavePort.txMode; RGBForeColor(&gSavePort.rgbFgColor); RGBBackColor(&gSavePort.rgbBkColor); SetPort((GrafPtr)gOldPort); } void DoDraw(PluginInstance* This) { Rect drawRect; drawRect.top = 0; drawRect.left = 0; drawRect.bottom = drawRect.top + This->fWindow->height; drawRect.right = drawRect.left + This->fWindow->width; EraseRect( &drawRect ); MoveTo( 2, 12 ); DrawString("\pHello, World!"); } #endif /* macintosh */ /******************************************************************************/