/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* * 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). * * dp Suresh * Modified by Warren Harris to test Java stuff. * *---------------------------------------------------------------------- * 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 "prosdep.h" /* include first to get the right #defines */ #include "npapi.h" #include "JavaTestPlugin.h" #include "java_lang_Class.h" #include "java_lang_String.h" #ifdef EMBEDDED_FRAMES #include "java_awt_EmbeddedFrame.h" #include "java_awt_Component.h" #include "java_awt_Color.h" #include "java_awt_Window.h" #endif /* EMBEDDED_FRAMES */ #define TEXT_PLUGIN #ifdef TEXT_PLUGIN #include #include #include #endif /* TEXT_PLUGIN */ /*********************************************************************** * 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 { uint16 mode; Window window; Display *display; uint32 x, y; uint32 width, height; #ifdef TEXT_PLUGIN Widget text; /* Text widget */ #endif /* TEXT_PLUGIN */ } PluginInstance; /*********************************************************************** * * Empty implementations of plugin API functions * * PLUGIN DEVELOPERS: * You will need to implement these functions as required by your * plugin. * ***********************************************************************/ char* NPP_GetMIMEDescription(void) { #ifdef TEXT_PLUGIN return("text/plain:.txt"); #else return("application/x-data:.sample"); #endif } #define PLUGIN_NAME "Java Test Plugin" #define PLUGIN_DESCRIPTION "Tests java natives and reflection stuff." NPError NPP_GetValue(NPP 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; } JRIEnv* env; JRIGlobalRef classString; JRIGlobalRef classColor; JRIGlobalRef classFrame; JRIGlobalRef classJavaTestPlugin; NPError NPP_Initialize(void) { return NPERR_NO_ERROR; } jref NPP_GetJavaClass(void) { jref myClass; env = NPN_GetJavaEnv(); myClass = init_JavaTestPlugin(env); /* other classes I'll need: */ classString = JRI_NewGlobalRef(env, init_java_lang_String(env)); #ifdef EMBEDDED_FRAMES classColor = JRI_NewGlobalRef(env, init_java_awt_Color(env)); classFrame = JRI_NewGlobalRef(env, java_awt_EmbeddedFrame__init(env)); #endif classJavaTestPlugin = JRI_NewGlobalRef(env, myClass); return myClass; } void NPP_Shutdown(void) { } NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) { NPError result = NPERR_NO_ERROR; PluginInstance* This; 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->mode = mode; This->window = (Window) 0; /* 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). */ } /* Java Test */ { jref plugin; jref fact; int val; plugin = JRI_GetGlobalRef(env, classJavaTestPlugin); val = JavaTestPlugin_fact(env, plugin, 10); /* static method */ if (JRI_ExceptionOccurred(env)) { fprintf(stderr, "fact failed\n"); result = NPERR_INVALID_INSTANCE_ERROR; goto done; } printf("Plugin: Java sez: fact(10) = %d\n", val); fact = NPN_GetJavaPeer(instance); if (JRI_ExceptionOccurred(env)) { fprintf(stderr, "couldn't create a JavaTestPlugin object\n"); result = NPERR_INVALID_INSTANCE_ERROR; goto done; } printf("Plugin: setting foo field to %d\n", 11111); set_JavaTestPlugin_foo(env, fact, 11111); printf("Plugin: reading foo field as %ld\n", get_JavaTestPlugin_foo(env, fact)); printf("Plugin: calling into java to test plugin native methods\n"); JavaTestPlugin_testPluginCalls(env, fact); printf("Plugin: reading foo field as %ld\n", get_JavaTestPlugin_foo(env, fact)); if (JRI_ExceptionOccurred(env)) { fprintf(stderr, "test returned an error\n"); result = NPERR_INVALID_INSTANCE_ERROR; goto done; } done: if (JRI_ExceptionOccurred(env)) { JRI_ExceptionDescribe(env); JRI_ExceptionClear(env); } } 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; } return NPERR_NO_ERROR; } NPError NPP_SetWindow(NPP instance, NPWindow* window) { NPError result = NPERR_NO_ERROR; PluginInstance* This; 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. */ 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; #ifdef TEXT_PLUGIN { Widget netscape_widget; Widget form; Arg av[20]; int ac; netscape_widget = XtWindowToWidget(This->display, This->window); ac = 0; XtSetArg(av[ac], XmNx, 0); ac++; XtSetArg(av[ac], XmNy, 0); ac++; XtSetArg(av[ac], XmNwidth, This->width); ac++; XtSetArg(av[ac], XmNheight, This->height); ac++; XtSetArg(av[ac], XmNborderWidth, 0); ac++; XtSetArg(av[ac], XmNnoResize, True); ac++; form = XmCreateForm(netscape_widget, "pluginForm", av, ac); ac = 0; XtSetArg(av[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(av[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(av[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(av[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++; This->text = XmCreateScrolledText (form, "pluginText", av, ac); XtManageChild(This->text); XtManageChild(form); #ifdef EMBEDDED_FRAMES { JavaStatus err; jref frame; /* Create a window! */ frame = java_awt_EmbeddedFrame_make_1(env, JRI_GetGlobalRef(env, classFrame), form); if ((err = JRI_GetError(env)) != JavaStatusOk) { fprintf(stderr, "couldn't create an EmbeddedFrame (%d)\n", err); result = NPERR_INVALID_INSTANCE_ERROR; goto done; } fprintf(stderr, "frame = %p\n", frame); java_awt_Component_resize(env, frame, 30, 30); java_awt_Component_setBackground(env, frame, java_awt_Color_red_get(env, JRI_GetGlobalRef(env, classColor))); java_awt_Window_show(env, frame); if ((err = JRI_GetError(env)) != JavaStatusOk) { fprintf(stderr, "couldn't show EmbeddedFrame (%d)\n", err); result = NPERR_INVALID_INSTANCE_ERROR; goto done; } fprintf(stderr, "frame shown\n"); done: } #endif } #endif /* TEXT_PLUGIN */ 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; 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; /* 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; #ifdef TEXT_PLUGIN char *cbuf; XmTextPosition pos = 0; cbuf = (char *) NPN_MemAlloc(len + 1); if (!cbuf) return 0; memcpy(cbuf, ((char *)buffer)+offset, len); cbuf[len] = '\0'; XtVaGetValues(This->text, XmNcursorPosition, &pos, 0); XmTextInsert(This->text, pos, cbuf); NPN_MemFree(cbuf); #endif /* TEXT_PLUGIN */ } 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; return NPERR_NO_ERROR; } void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) { PluginInstance* This; if (instance != NULL) This = (PluginInstance*) instance->pdata; } void NPP_Print(NPP instance, NPPrint* printInfo) { 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; } } } /******************************************************************************/ /* public native doPluginStuff(Ljava/lang/String;I)C */ jchar JavaTestPlugin_doPluginStuff(JRIEnv* env, struct JavaTestPlugin* self, struct java_lang_String * s, jint i) { const jchar* chars = JRI_GetStringChars(env, s); return chars[0]; } /* public native native1()V */ void JavaTestPlugin_native1(JRIEnv* env,struct JavaTestPlugin* self) { fprintf(stderr, "Plugin: native1 called!\n"); } /* public native native2(B)B */ jbyte JavaTestPlugin_native2(JRIEnv* env,struct JavaTestPlugin* self,jbyte b) { return b + 4; } /* public native native3(C)C */ jchar JavaTestPlugin_native3(JRIEnv* env,struct JavaTestPlugin* self,jchar c) { return c + 1; } /* public native native4(S)S */ jshort JavaTestPlugin_native4(JRIEnv* env,struct JavaTestPlugin* self,jshort s) { return s + 1; } /* public native native5(I)I */ jint JavaTestPlugin_native5(JRIEnv* env,struct JavaTestPlugin* self,jint i) { return i + 1; } /* public native native6(J)J */ jlong JavaTestPlugin_native6(JRIEnv* env,struct JavaTestPlugin* self,jlong l) { jlong result, tmp; jlong_I2L(tmp, 65536); jlong_ADD(result, l, tmp); return result; } /* public native native7(F)F */ jfloat JavaTestPlugin_native7(JRIEnv* env,struct JavaTestPlugin* self,jfloat f) { return f + 1.0; } /* public native native8(D)D */ jdouble JavaTestPlugin_native8(JRIEnv* env,struct JavaTestPlugin* self,jdouble d) { return d + 1e10; } /* public native native9(Ljava/lang/String;ISCB)Ljava/lang/String; */ struct java_lang_String * JavaTestPlugin_native9(JRIEnv* env, struct JavaTestPlugin* self, struct java_lang_String * s, jint j, jlong x, jfloatArray floats, jbooleanArray bools) { jref clazz, ba; jbool* b; char* c; jsize len = JRI_GetFloatArrayLength(env, floats); jfloat* f = JRI_GetFloatArrayData(env, floats); jsize i; for (i = 0; i < len; i++) { fprintf(stderr, "float %d: %f", i, f[i]); f[i] *= 2.2; fprintf(stderr, " => %f\n", f[i]); } len = JRI_GetBooleanArrayLength(env, bools); b = JRI_GetBooleanArrayData(env, bools); for (i = 0; i < len; i++) { fprintf(stderr, "boolean %d: %d\n", i, b[i]); } ba = JRI_FindClass(env, JRISigArray(JRISigBoolean)); c = JRI_CopyStringUTF(env, java_lang_Class_getName(ba, env)); fprintf(stderr, "class [b => %p (%s)\n", enamed NPN_GetJavaInstance & Plugin.getNativeInstance -> NPN_GetJavaPeer & Plugin.getPeer. free(c); clazz = JRI_GetObjectClass(env, shorts); c = JRI_CopyStringUTF(env, java_lang_Class_getName(env, clazz)); fprintf(stderr, "class of shorts => %p (%s)\n", clazz, c); free(c); na = JRI_NewShortArray(env, 2, ss); clazz = JRI_GetObjectClass(env, na); c = JRI_CopyStringUTF(env, java_lang_Class_getName(env, clazz)); fprintf(stderr, "class of the new short array => %p (%s)\n", clazz, c); /* can we call methods with double results properly */ d = JavaTestPlugin_native8(env, self, 2e10); fprintf(stderr, "calling native8(2e10) => %lf %s\n", d, (d == 3e10 ? "ok" : "error")); /* can we call a system function */ return java_lang_String_substring(env, s, j); }