#define DISPLAY_COLOR_LOGO /* -*- Mode: C; tab-width: 4; -*- */ /****************************************************************************** * Copyright (c) 1996 Netscape Communications. All rights reserved. * Copyright (c) 1997 Lawrence T. Hoff (hoff@bnl.gov). All rights reserved. ******************************************************************************/ /* * UnixShell.c * * Netscape Client Plugin API * - Function that need to be implemented by plugin developers * * This file defines a "Template" 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). * */ #include /* sprintf(), fprintf(), etc. */ #include /* pid_t */ #include /* fork(), system(), unlink(), etc. */ #include /* SIGHUP */ #include /* O_RDWR */ #include /* wait() */ #include "npapi.h" #include /* maximum # of file descriptors */ /* ** Stuff for the NPP_SetWindow method: */ #ifdef XP_UNIX #include #include #include static void Redraw(Widget w, XtPointer closure, XEvent *event); #ifdef DISPLAY_COLOR_LOGO #include "xpm.h" /* xpm library functions */ #include "ump.xpm" /* UMP in XPM format */ #endif /* DISPLAY_COLOR_LOGO */ /* We aim to please all sorts, color, bw, etc. */ typedef enum { DISPLAY_UNKNOWN = 0, DISPLAY_BW = 1, DISPLAY_COLOR = 2 } displayType ; #endif /* XP_UNIX */ /* default library, compatible with TIMIDITY */ static const char *timdir = "/usr/local/lib/timidity"; /* resort to slow sampling rate for busy/slow processors */ static int eightKFlag = 0; /*********************************************************************** * * * * * Stop playing music, kill the subordinate task * * * * * * * * * ***********************************************************************/ static void stopMidiPlayer(pid_t pid){ if(pid != (pid_t) -1) { kill(pid, SIGHUP); while(waitpid(pid, 0, WNOHANG)>0); /* clean up after dead child */ } } /*********************************************************************** * * * * * Function to actually play the music * * * * * * * * * ***********************************************************************/ static pid_t startMidiPlayer(const char *filename){ /* if we're the parent, return the child ID */ pid_t pid = fork(); if(pid != (pid_t)0) return pid; /* OK, now let's get ourselves somewhat removed from our parent */ { int fd, sig; struct rlimit rlp; /* start by closing all file descriptors (except stderr) */ (void) getrlimit(RLIMIT_NOFILE, &rlp); for(fd = 3; fd < rlp.rlim_max; fd++) (void) close(fd); /* now attach stdin and adtout to /dev/null */ (void) freopen("/dev/null", "r", stdin); (void) freopen("/dev/null", "w", stdout); /* then remove an netscape-installed signal handlers */ for(sig=0; sig < 64; sig++)signal(sig, SIG_DFL); } /* Now play the sound file */ { static const char *argv[4]; argv[0] = "timidity"; argv[1] = "-Od"; argv[2] = eightKFlag ? "-s8000": "-s22050"; /* check if the user specified 8K rate */ argv[3] = filename; /* change to the configuration directory */ chdir(timdir); /* jump to timidity */ timiditymain(4, argv); } /* bye now */ _exit(0); } /*********************************************************************** * 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. ***********************************************************************/ /* we'll read in all the file before processing. Typical MIDI files are smallish, so it should be OK */ static const char *filestub = "/tmp/midi"; typedef struct _PluginInstance { int fd; /* file descriptor for temp file */ const char *filename; /* name of same */ pid_t pid; /* process ID of sound player */ NPWindow* fWindow; uint16 fMode; /* UNIX data members */ #ifdef XP_UNIX Window window; Display *display; uint32 x, y; uint32 width, height; Pixmap pixmap; /* logo pixmap ID */ #ifdef DISPLAY_COLOR_LOGO XpmAttributes attr; /* height, width, and pixels of color logo */ #endif /* DISPLAY_COLOR_LOGO */ displayType dt; /* what kind of display it is */ #endif /* XP_UNIX */ } 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) { static char *desc = "audio/midi:mid,midi:Larry Hoff's " "UMP plugin version 1.01;" "audio/x-midi:mid,midi:Larry Hoff's " "UMP plugin version 1.01;"; return(desc); } NPError NPP_GetValue(void *future, NPPVariable variable, void *value) { NPError err = NPERR_NO_ERROR; static char *desc = "This plugins plays MIDI, using the timidity " "toolkit, via the standard audio device.

" "By default, timidity configuration files are in the directory " "/usr/local/bin/timidity

" "Use the TIMID_DIR environment variable to change " "the configuration directory.

" "You may set the environment variable TIMID_8K to " "reduce the sampling rate (to 8000 Hz) for busy or slow " "processors, or for machines which only support 8KHz.

"; switch (variable) { case NPPVpluginNameString: *((char **)value) = "UNIX MIDI plugin"; break; case NPPVpluginDescriptionString: *((char **)value) = desc; break; default: err = NPERR_GENERIC_ERROR; } return err; } NPError NPP_Initialize(void) { /* see if the user has specified an alternate directory for timidity */ if(getenv("TIMID_DIR") != NULL) timdir = getenv("TIMID_DIR"); /* see if the user has specified an alternate directory for timidity */ if(getenv("TIMID_8K") != NULL) eightKFlag = 1; return NPERR_NO_ERROR; } jref NPP_GetJavaClass() { return NULL; } void NPP_Shutdown(void) { } NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) { 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; { /* construct a filename unique to this instance to store the data in */ static char buf[256]; sprintf(buf, "%s%x.mid", filestub, This); This->filename = buf; This->pid = -1; This->dt = DISPLAY_UNKNOWN; This->pixmap = NULL; } return NPERR_NO_ERROR; } 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) { /* get rid of the temporary file */ (void) unlink(This->filename); /* stop player */ stopMidiPlayer(This->pid); #ifdef XP_UNIX /* free pixmaps and colors */ if(This->pixmap != NULL)XFreePixmap(This->display, This->pixmap); #ifdef DISPLAY_COLOR_LOGO #if(0) /* it seems that the colormap is destroyed before the plugins, so we don't need to do this */ if(This->dt == DISPLAY_COLOR)XFreeColors(This->display, This->attr.colormap, This->attr.alloc_pixels, This->attr.nalloc_pixels, 0); #endif if(This->dt == DISPLAY_COLOR)XpmFreeAttributes(&This->attr); #endif /* DISPLAY_COLOR_LOGO */ #endif /*XP_UNIX */ NPN_MemFree(instance->pdata); instance->pdata = NULL; } return NPERR_NO_ERROR; } NPError NPP_SetWindow(NPP instance, NPWindow* window) { PluginInstance* This; if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; if (window == NULL) return NPERR_NO_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 */ This->fWindow = window; return NPERR_NO_ERROR; } NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype) { NPByteRange range; PluginInstance* This; if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; This = (PluginInstance*) instance->pdata; /* open the file to store data in */ This->fd = open(This->filename, O_RDWR|O_CREAT, 0666); if(This->fd == -1) return NPERR_GENERIC_ERROR; 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; return STREAMBUFSIZE; } int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) { if (instance != NULL) { PluginInstance* This = (PluginInstance*) instance->pdata; len = write(This->fd, buffer, len); if(len <0) close(This->fd); } 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; close(This->fd); /* stop another player in progress ???*/ stopMidiPlayer(This->pid); /* yahoo, now we have the data, run timidity */ This->pid = startMidiPlayer(This->filename); return NPERR_NO_ERROR; } void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) { PluginInstance* This; if (instance != NULL) This = (PluginInstance*) instance->pdata; /* just spwan timidity */ This->pid = startMidiPlayer(fname); } 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; } } } #ifdef XP_UNIX #define umpbw_width 140 #define umpbw_height 50 static char umpbw_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x21,0x92,0x24,0x49,0xf2,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x24,0x12,0x04,0x00,0x00,0x00,0xf0,0x00,0x00,0x24,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x44,0x00,0x40,0x10,0x49,0x92,0xa4,0xf4,0x00,0x00,0x66, 0x00,0x00,0x00,0x00,0x00,0x10,0x44,0x00,0x40,0x00,0x80,0xaa,0x00,0x00,0xf0, 0x00,0x00,0x56,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,0x02,0xfd,0xea, 0xaa,0x4a,0xf2,0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x22,0x00, 0xd0,0x06,0xe4,0x00,0x00,0xf0,0x00,0x00,0xd2,0x00,0x00,0x00,0x00,0x04,0x00, 0x00,0x80,0x90,0x30,0xf9,0x9f,0x42,0x24,0xf5,0x00,0x00,0xba,0x00,0x00,0x00, 0x10,0x00,0x00,0x44,0x00,0x02,0xde,0xff,0x8f,0x08,0x01,0xf0,0x00,0x00,0xb3, 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x04,0x00,0xf5,0x03,0x84,0x20,0x28,0xf1, 0x00,0x00,0x9a,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x10,0xc0,0x3f,0x00,0x84, 0xff,0xff,0xf5,0x00,0x00,0xbb,0x60,0xc0,0x71,0x3e,0x3e,0x70,0x3f,0x80,0xe8, 0x03,0x00,0xc0,0xef,0xdd,0xf3,0xf8,0xff,0x9b,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x64,0xc0,0xf5,0xf0,0x3c,0x00,0xdd,0xe1,0xc2,0xe5, 0xff,0xff,0xf1,0xff,0x4a,0x7a,0x00,0x90,0x9c,0x2a,0x76,0xf2,0x3c,0x00,0x99, 0xe0,0xc0,0xf1,0xfb,0xf7,0xf0,0xfd,0x00,0x18,0x00,0xfe,0xf9,0xff,0x3f,0xf0, 0x3c,0x80,0xcd,0xe0,0xc0,0xe1,0xe1,0xe9,0xf1,0xe1,0x01,0x0c,0xc0,0xff,0xdd, 0xff,0x97,0xf4,0x3c,0x80,0x5d,0x60,0x82,0xe3,0xea,0xc3,0xf5,0xe4,0x12,0x0e, 0xf0,0xff,0x81,0x00,0x00,0xf0,0xbc,0x2a,0x65,0xe9,0xd4,0xf5,0xe4,0xe9,0x79, 0xea,0xa9,0x07,0xf8,0xfa,0x84,0x00,0x48,0xf2,0xf8,0xff,0xf1,0xff,0xff,0xfd, 0xff,0xfe,0xff,0xfd,0xff,0x03,0xae,0xaf,0x85,0x22,0x01,0xf0,0x3c,0x80,0x39, 0x60,0xc0,0x61,0xe0,0xc0,0xb1,0xc0,0x01,0x03,0xfb,0xea,0x84,0x08,0x24,0xf5, 0x3c,0xe0,0x08,0xe0,0xc0,0x63,0xe1,0xc1,0x72,0xc0,0x82,0x81,0x57,0xbf,0x81, 0x80,0x00,0xf0,0x3c,0x70,0x0a,0x60,0x81,0xe5,0xc0,0xc2,0xb1,0xc2,0x85,0x81, 0xaa,0x55,0x85,0x24,0x28,0xf1,0x3c,0x18,0x9b,0xe4,0xc4,0x71,0xe5,0xd4,0x7d, 0xc9,0xab,0x81,0xd5,0xaa,0x85,0x81,0x02,0xf4,0xfc,0xdf,0xfb,0xff,0xff,0xff, 0xfe,0xff,0xfb,0xff,0xfd,0xc1,0xb7,0xee,0x80,0x10,0x90,0xf0,0x3c,0xc6,0x3a, 0x60,0xc0,0xe1,0xe0,0xc0,0x74,0xc0,0x83,0x41,0xf5,0x2b,0x85,0x44,0x04,0xf2, 0x38,0xf2,0xe3,0xe1,0xc1,0x65,0xe1,0xc0,0x71,0x80,0x85,0x81,0x5d,0x6d,0x81, 0x01,0x41,0xf0,0x3c,0xf3,0x08,0x63,0xc0,0x61,0xc0,0xc1,0xb5,0xc0,0x81,0x81, 0xd5,0x2a,0x85,0x24,0x10,0xf4,0x3c,0x3b,0xf4,0xe6,0xc2,0x75,0xe1,0xc2,0x71, 0xd2,0x95,0x01,0x65,0x2b,0x81,0x80,0x44,0xf1,0xfc,0x9d,0xf7,0xfe,0xfd,0xfd, 0xff,0xfe,0xff,0xff,0xfd,0x03,0x9b,0x6a,0x89,0xb6,0xaa,0xf2,0x38,0xdb,0x97, 0xe5,0xc2,0x63,0xe0,0xc2,0xf1,0xe0,0x02,0x03,0xd4,0x2a,0xc1,0xff,0xff,0xf3, 0x3c,0xcb,0xb4,0xe4,0xe0,0x71,0xe1,0xc0,0xf5,0xe1,0x09,0x06,0x78,0x25,0x45, 0x6b,0xd9,0xf1,0x3c,0x9a,0xe7,0xe4,0xf3,0xe3,0xe0,0xc2,0xf1,0x79,0x44,0x0e, 0xa0,0x2a,0xb0,0x90,0x76,0xf4,0x1c,0x33,0x74,0xc6,0xbf,0x65,0xc1,0xc0,0xf2, 0x7f,0x01,0x0c,0x80,0x25,0xb9,0xee,0x7b,0xf0,0x7c,0xee,0x6f,0xee,0xff,0xfb, 0xfe,0xfe,0xbd,0x7f,0xfd,0x1f,0x00,0x98,0xf9,0xff,0x1f,0xf2,0xa8,0x9f,0x86, 0xb7,0xdf,0xed,0xea,0xd5,0x7b,0xff,0xaf,0x7a,0x00,0x00,0x84,0x04,0x84,0xf0, 0x00,0x70,0xc0,0x01,0x0a,0x00,0x00,0x00,0xb0,0x0c,0x00,0xe0,0x00,0x00,0x80, 0x21,0x21,0xf4,0x00,0xc0,0x77,0x00,0x20,0x00,0x00,0x01,0x74,0x21,0x00,0xc1, 0x03,0x00,0x84,0x08,0x88,0xf0,0x00,0x00,0x26,0x00,0x00,0x80,0x00,0x00,0x70, 0x44,0x10,0x08,0x1f,0x00,0x80,0x42,0x01,0xf2,0x00,0x00,0x1a,0x00,0x00,0x00, 0x00,0x00,0xb0,0x00,0x41,0x00,0xfc,0x00,0xc4,0x10,0x48,0xf0,0x00,0x00,0x32, 0x00,0x10,0x00,0x00,0x51,0x79,0x00,0x01,0x82,0xe4,0x2f,0x60,0x02,0x02,0xf4, 0x00,0x00,0x13,0x00,0x40,0x00,0x00,0x40,0x70,0x09,0x01,0x08,0x02,0xff,0xbf, 0xa0,0x20,0xf1,0x00,0x00,0x16,0x51,0x93,0x84,0x1b,0x79,0x71,0x3c,0x4d,0x3e, 0xdc,0xd0,0x0f,0x08,0x08,0xf0,0x00,0x00,0x1e,0xd1,0x94,0x84,0xac,0xc5,0xb1, 0x64,0x65,0x11,0x74,0x01,0x00,0x42,0xa2,0xf4,0x00,0x00,0x00,0x51,0x14,0x8b, 0x24,0x45,0x71,0x45,0x45,0xd1,0x15,0x25,0xa0,0x10,0x00,0xf0,0x00,0x00,0x00, 0x51,0x14,0x83,0x24,0x45,0x09,0x44,0x45,0x93,0x14,0x81,0x0a,0x84,0x4a,0xf2, 0x00,0x00,0x00,0x59,0x94,0x84,0x24,0x45,0x01,0x44,0x65,0x11,0x56,0x13,0x80, 0x10,0x00,0xf0,0x00,0x00,0x00,0x56,0x94,0x84,0x24,0x79,0x81,0xbc,0x5d,0x3e, 0x1c,0x41,0x24,0x42,0x24,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, 0x06,0x40,0x11,0x40,0x08,0x01,0x00,0x01,0xf0,0x00,0x00,0x00,0x00,0x00,0x10, 0x00,0x40,0x04,0x14,0x00,0x8f,0x00,0x01,0x24,0x29,0x50,0xf1,0x00,0x00,0x00, 0x00,0x00,0x80,0x08,0x00,0x10,0x00,0x04,0x04,0x12,0x50,0x00,0x80,0x04,0xf4 }; static void Redraw(Widget w, XtPointer closure, XEvent *event) { XGCValues gcv; /* GC values for bitmap */ GC gc; /* graphics context for drawing */ PluginInstance* This = (PluginInstance*)closure; XtVaGetValues(w, XtNbackground, &gcv.background, XtNforeground, &gcv.foreground, 0); gc = XCreateGC(This->display, This->window, GCForeground|GCBackground, &gcv); #ifdef DISPLAY_COLOR_LOGO if( This->dt == DISPLAY_UNKNOWN ){ /* let's figger out what kind of display it is */ XWindowAttributes wattr; /* discover the colormap */ XGetWindowAttributes(This->display, This->window, &wattr); /* tell XPM to allocate fairly close (not exact) colors from the window's colormap */ This->attr.valuemask = XpmSize|XpmCloseness|XpmAllocCloseColors|XpmExactColors|XpmColormap; This->attr.closeness = 30000; This->attr.alloc_close_colors = True; This->attr.exactColors = False; This->attr.colormap = wattr.colormap; /* while it's at it, tell us what size the logo is */ if(XpmCreatePixmapFromData(This->display, This->window, ump, &This->pixmap, NULL, &This->attr) == XpmSuccess) This->dt = DISPLAY_COLOR; } if(This->dt == DISPLAY_COLOR) XCopyArea(This->display, This->pixmap, This->window, gc, 0, 0, This->attr.width, This->attr.height, 0, 0); #endif /* ! DISPLAY_COLOR_LOGO */ if( This->dt == DISPLAY_UNKNOWN ){ /* let's figger out what kind of display it is */ This->pixmap = XCreatePixmapFromBitmapData(This->display, This->window, umpbw_bits, umpbw_width, umpbw_height, WhitePixel(This->display, DefaultScreen(This->display)), BlackPixel(This->display, DefaultScreen(This->display)), 1); if(This->pixmap != NULL) This->dt = DISPLAY_BW; /* we have a bitmap to work with! */ } if(This->dt == DISPLAY_BW) { XCopyPlane(This->display, This->pixmap, This->window, gc, 0, 0, umpbw_width, umpbw_height, 0, 0, 1); } /* free resources */ XFreeGC(This->display, gc); } #endif /* XP_UNIX */