Blender V2.61 - r43446

UnixShell.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Enrico Fracasso
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  * NS api template, adapted to link to our own internals.
00027  */
00028 
00029 #define MOZ_X11 1
00030 
00031 /* -*- Mode: C; tab-width: 8; c-set-style: bsd -*- */
00032 
00033 /* UnixShell.c was adapted from the template in the Netscape API. */
00034 
00035 /* System: */     
00036 #include <string.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 
00040 /* All nsapi stuff. nsapi now needs FILE, so include stdio as well. */
00041 #include <stdio.h>
00042 #include "npapi.h"
00043 
00044 /* Native hooks: */
00045 #include "npapi.h"
00046 
00047 /* Threading the NSPR way: */
00048 #include "prthread.h"
00049 #include "prlock.h"
00050 
00051 #include "blender_plugin_types.h"
00052 
00053 #include <signal.h>
00054 
00055 /* --------------------------------------------------------------------- */
00056 
00058 #if defined(DEBUG)
00059 #define NZC_GENERATE_LOG
00060 #endif
00061 
00062 int32 STREAMBUFSIZE;
00063 
00065 static void
00066 log_entry(char* msg);
00067 
00068 
00069 void
00070 execute_blenderplayer(BlenderPluginInstance*);
00071 
00072 /* --------------------------------------------------------------------- */
00073 /* Implementations:                                                      */
00074 /* --------------------------------------------------------------------- */
00075 
00076 /* NPP_GetMIMEDescription() and NPP_GetValue() are called to determine
00077  * the mime types supported by this plugin. */
00078 char*
00079 NPP_GetMIMEDescription( void )
00080 {
00081     log_entry("NPP_GetMIMEDescription");
00082     return("application/x-blender-plugin:blend:Blender 3D web plugin");
00083 }
00084 
00085 NPError
00086 NPP_GetValue(
00087     NPP instance,
00088     NPPVariable variable,
00089     void *value
00090     )
00091 {
00092     NPError err = NPERR_NO_ERROR;
00093     
00094     log_entry("NPP_GetValue");
00095 
00096     switch (variable) {
00097     case NPPVpluginNeedsXEmbed:
00098         log_entry("NPP_GetValue::NPPVpluginNeedsXEmbed");
00099         *((PRBool *)value) = PR_TRUE;
00100         break;
00101     case NPPVpluginNameString:
00102         log_entry("NPP_GetValue::NPPVpluginNameString");
00103         *((char **)value) = "Blender";
00104         break;
00105     case NPPVpluginDescriptionString:
00106         log_entry("NPP_GetValue::NPPVpluginDescriptionString");
00107         *((char **)value) = "Player for interactive 3D content";
00108         break;
00109     case NPPVpluginWindowBool:
00110         log_entry("NPP_GetValue::NPPVpluginWindowBool");
00111         *((PRBool *)value) = PR_FALSE; //not windowless
00112         break;
00113     case NPPVpluginTransparentBool:
00114         log_entry("NPP_GetValue::NPPVpluginTransparentBool");
00115         *((PRBool *)value) = PR_FALSE; // not trasparent
00116         break;
00117     default:
00118         err = NPERR_GENERIC_ERROR;
00119     }
00120     return err;
00121 }
00122 
00123 /* --------------------------------------------------------------------- */
00124 /* Mozilla: NPP_Initialize() is called when
00125  * starting the browser, and then every time the plugin is started*/
00126 NPError
00127 NPP_Initialize(void)
00128 {
00129     log_entry("NPP_Initialize");
00130     return NPERR_NO_ERROR;
00131 }
00132 
00133 /* --------------------------------------------------------------------- */
00134 
00135 void
00136 NPP_Shutdown(void)
00137 {
00138     log_entry("NPP_Shutdown");
00139 }
00140 
00141 
00142 NPError 
00143 NPP_New(
00144     NPMIMEType pluginType,
00145     NPP instance,
00146     uint16 mode,
00147     int16 argc,
00148     char* argn[],
00149     char* argv[],
00150     NPSavedData* saved
00151     )
00152 {
00153     BlenderPluginInstance* This  = NULL;
00154     int i = 0;
00155     int retval = 0;
00156 
00157     log_entry("NPP_New");
00158     
00159     if (instance == NULL)
00160         return NPERR_INVALID_INSTANCE_ERROR;
00161     
00162     instance->pdata = NPN_MemAlloc(sizeof(BlenderPluginInstance));
00163     if (instance->pdata == 0)
00164         return NPERR_OUT_OF_MEMORY_ERROR;
00165     
00166     This = (BlenderPluginInstance*) instance->pdata;
00167     This->browser_instance = instance;
00168     This->pID = 0;
00169     This->blend_file = 0;
00170     This->temp_mail_file_name = 0;
00171     This->main_file_store = 0;
00172     This->display = NULL;
00173     This->window = 0;
00174 
00175     /* Parse the options from the file. Should I do this in the
00176      * implementation file maybe? Now we do a lot with
00177      * instance-specific data. */
00178     /*
00179     while (i <argc ) {
00180         if (!strcmp(argn[i],"src")) {
00181             The blend file to load. 
00182             int url_len = strlen(argv[i]);
00183             if ((url_len > 0) && (url_len < 4096) ) {
00184                 This->blend_file = NPN_MemAlloc(url_len + 1);
00185                 if (This->blend_file == 0)
00186                     return NPERR_OUT_OF_MEMORY_ERROR;
00187                 strcpy(This->blend_file, argv[i]);
00188                 
00189                 retval = NPN_GetURL(This->browser_instance,
00190                             This->blend_file,
00191                             NULL);
00192                 if (retval != NPERR_NO_ERROR) {
00193                     log_entry("Cannot read animation");
00194                     NPN_Status(instance, "Cannot read animation file");
00195                     This->blend_file = NULL;
00196                     return NPERR_NO_ERROR;
00197                 } else
00198                     log_entry("Animation loaded"); 
00199             }
00200         }       
00201         i++;
00202     }*/
00203         
00204     if (This != NULL) {
00205         return NPERR_NO_ERROR;
00206     } else
00207         return NPERR_OUT_OF_MEMORY_ERROR;
00208 }
00209 
00210 
00211 NPError 
00212 NPP_Destroy( NPP instance, NPSavedData** save )
00213 {
00214     BlenderPluginInstance* This;
00215 
00216     log_entry("NPP_Destroy");
00217 
00218     if (instance == NULL)
00219         return NPERR_INVALID_INSTANCE_ERROR;
00220 
00221     This = (BlenderPluginInstance*) instance->pdata;
00222     printf("NPP_Destroy ID:  0x%x %d\n", This->window, This->window);
00223 
00224     if (This != NULL) {
00225 
00226         if (This->pID != 0) {
00227 #ifdef WITH_PRIVSEP
00228             kill(This->pID, SIGTERM);
00229 #else 
00230             kill(This->pID, SIGKILL); //if I have to kill blenderplayer directly I need to send SIGKILL
00231 #endif
00232             wait(This->pID);
00233             unlink(This->temp_mail_file_name);
00234         }
00235 
00236         // sometimes FF doesn't delete it's own window...
00237         //printf("%s \n", NPN_UserAgent(instance));
00238         /*if (This->display != NULL && This->window != 0)
00239             XDestroyWindow(This->display, This->window);
00240         */
00241         if (This->blend_file) NPN_MemFree(This->blend_file);
00242         if (This->temp_mail_file_name) NPN_MemFree(This->temp_mail_file_name);
00243         if (This->main_file_store) NPN_MemFree(This->main_file_store);
00244         NPN_MemFree(instance->pdata);
00245         instance->pdata = NULL;
00246     }   
00247 
00248     return NPERR_NO_ERROR;
00249 }
00250 
00251 
00252 
00253 NPError 
00254 NPP_SetWindow( NPP instance,NPWindow* window ) 
00255 {
00256     BlenderPluginInstance* This;
00257 
00258     log_entry("NPP_SetWindow");
00259 
00260     if (instance == NULL)
00261         return NPERR_INVALID_INSTANCE_ERROR;
00262 
00263     /* window handle */ 
00264     if ((window == NULL) || (window->window == NULL)) {
00265         return NPERR_NO_ERROR; /* mmmmmm  */
00266     }
00267     
00268     if (window->ws_info == NULL)
00269         return NPERR_NO_ERROR; /* mmmmmm  */
00270 
00271     This = (BlenderPluginInstance*) instance->pdata;
00272 
00273     if (This) {
00274         This->window = (Window) window->window;
00275 
00276         NPSetWindowCallbackStruct* window_info = window->ws_info;
00277         This->display = window_info->display;
00278 
00279         printf("ID window 0x%x %d\n", window->window, window->window);
00280         return NPERR_NO_ERROR;
00281     } else {
00282         return NPERR_INVALID_INSTANCE_ERROR;
00283     }
00284 }
00285 
00286 
00287 NPError 
00288 NPP_NewStream(
00289     NPP instance,
00290     NPMIMEType type,
00291     NPStream *stream, 
00292     NPBool seekable,
00293     uint16 *stype
00294     )
00295 {
00296     //NPByteRange range;
00297     BlenderPluginInstance* This;
00298 
00299     log_entry("NPP_NewStream");
00300     
00301     if (instance == NULL)
00302         return NPERR_INVALID_INSTANCE_ERROR;
00303 
00304     This = (BlenderPluginInstance*) instance->pdata;
00305 
00306     if (!This) 
00307         return NPERR_INVALID_INSTANCE_ERROR;
00308 
00309     printf("Loading main file %s (%s)\n", stream->url, type);
00310     if ( strcmp(type,"text/html") == 0 ) // original HTML file 
00311         return NPERR_NO_ERROR;
00312     
00313     This->stream_total = stream->end;
00314     This->stream_retrieved = 0;
00315     This->main_file_store = NPN_MemAlloc(stream->end*sizeof(unsigned char));
00316     if (!This->main_file_store) {
00317         fprintf(stderr, "Blender plugin: Out of memory! "
00318             "Cannot get chunk for loading animation.\n");
00319         return NPERR_OUT_OF_MEMORY_ERROR;
00320     }
00321 
00322     This->main_file_stream = stream;
00323 
00324     return NPERR_NO_ERROR;
00325         
00326 }
00327 
00328 
00329 /* PLUGIN DEVELOPERS:
00330  *  These next 2 functions are directly relevant in a plug-in which
00331  *  handles the data in a streaming manner. If you want zero bytes
00332  *  because no buffer space is YET available, return 0. As long as
00333  *  the stream has not been written to the plugin, Navigator will
00334  *  continue trying to send bytes.  If the plugin doesn't want them,
00335  *  just return some large number from NPP_WriteReady(), and
00336  *  ignore them in NPP_Write().  For a NP_ASFILE stream, they are
00337  *  still called but can safely be ignored using this strategy.
00338  */
00339 
00340 int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
00341                    * mode so we can take any size stream in our
00342                    * write call (since we ignore it) */
00343 
00344 int32 
00345 NPP_WriteReady(
00346     NPP instance,
00347     NPStream *stream
00348     )
00349 {
00350     BlenderPluginInstance* This = NULL;
00351     int acceptable = 0;
00352     
00353     log_entry("NPP_WriteReady");
00354 
00355     if (instance == NULL)   
00356         return NPERR_INVALID_INSTANCE_ERROR;
00357 
00358     This = (BlenderPluginInstance*) instance->pdata;
00359 
00360     if (This == NULL)   
00361         return NPERR_INVALID_INSTANCE_ERROR;
00362 
00363     /* Check whether buffers already exist: */
00364 
00365     if ((This->main_file_stream && This->main_file_store)) {
00366         acceptable = STREAMBUFSIZE;
00367     }
00368     
00369     
00370     return acceptable;
00371 }
00372 
00373 
00374 int32 
00375 NPP_Write(
00376     NPP instance,
00377     NPStream *stream,
00378     int32 offset,
00379     int32 len,
00380     void *buffer
00381     )
00382 {
00383     BlenderPluginInstance* This = NULL;
00384     int accepted = 0;
00385     
00386     log_entry("NPP_Write");
00387 
00388     if (instance == NULL)   
00389         return NPERR_INVALID_INSTANCE_ERROR;
00390     
00391     This = (BlenderPluginInstance*) instance->pdata;
00392 
00393     if (This == NULL)   
00394         return NPERR_INVALID_INSTANCE_ERROR;
00395 
00396     
00397     if (stream == This->main_file_stream) {
00398         log_entry("NPP_Write: loading main_file_stream"); 
00399         memcpy(((unsigned char*)This->main_file_store) + This->stream_retrieved, buffer, len);
00400         accepted = len;
00401         This->stream_retrieved += len;
00402         if (This->stream_retrieved >= This->stream_total) {
00403             log_entry("NPP_Write: main_file_stream loaded"); 
00404             execute_blenderplayer(This);
00405         }
00406     } else {
00407         /* the stream ref wasn't set yet..*/
00408         log_entry("NPP_Write: not main stream"); 
00409         log_entry(stream->url);
00410 
00411         accepted = len;
00412     }
00413 
00414     return accepted;
00415 }
00416 
00417 
00418 
00419 NPError 
00420 NPP_DestroyStream(
00421     NPP instance,
00422     NPStream *stream,
00423     NPError reason
00424     )
00425 {
00426     BlenderPluginInstance* This = NULL;
00427 
00428     log_entry("NPP_DestroyStream");
00429 
00430     if (instance == NULL)
00431         return NPERR_INVALID_INSTANCE_ERROR;
00432     This = (BlenderPluginInstance*) instance->pdata;
00433 
00434     if (This) {
00435         if (reason != NPRES_DONE) {
00436             if (stream == This->main_file_stream) {             
00437                 // stream destroyed by NPP_Destroy
00438                 NPN_Status(instance, "Cannot read animation file");
00439                 //main_file_failed(This->application);
00440             }
00441         }
00442         return NPERR_NO_ERROR;
00443     } else {
00444         return NPERR_INVALID_INSTANCE_ERROR;
00445     }
00446 
00447 }
00448 
00449 
00450 /* Not supposed to be called anymore... Anyway, we don't need the
00451  * results. Some Moz implementations will call this one regardless the
00452  * desired transfer mode! */
00453 void 
00454 NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname )
00455 {
00456 /*  log_entry("NPP_StreamAsFile"); */
00457 }
00458 
00459 
00460 void 
00461 NPP_Print(NPP instance, NPPrint* printInfo ) 
00462 {
00463     
00464     log_entry("NPP_Print");
00465     if(printInfo == NULL)
00466         return;
00467     if (instance != NULL) {
00468         if (printInfo->mode == NP_FULL) {
00469             printInfo->print.fullPrint.pluginPrinted = FALSE;
00470         }
00471         else {  /* If not fullscreen, we must be embedded */
00472         }
00473     }
00474 }
00475 
00476 
00477 void
00478 execute_blenderplayer(BlenderPluginInstance* instance){
00479 
00480     char file_name[] = "/tmp/blender.XXXXXX";
00481     int fd = mkstemp(file_name);
00482 
00483     ssize_t real_size = write(fd, instance->main_file_store, instance->stream_retrieved);
00484     close(fd);
00485 
00486     instance->temp_mail_file_name = NPN_MemAlloc(strlen(file_name) + 1);
00487     strcpy(instance->temp_mail_file_name, file_name);
00488 
00489     instance->pID = fork();
00490     //XSelectInput(This->display , This->window, SubstructureNotifyMask);
00491     //XSync(This->display, FALSE);
00492     
00493 
00494 #if defined(WITH_APPARMOR)
00495     const char* executable = "blenderplayer-web"; 
00496 #elif defined(WITH_PRIVSEP)
00497     const char* executable = "blenderplayer-wrapper";
00498 #else   
00499     const char* executable = "blenderplayer";
00500 #endif
00501 
00502     if (instance->pID == 0) {              // child
00503         char window_id[50];
00504         sprintf(window_id, "%d", instance->window);
00505         //exit(0);
00506 #ifdef WITH_PRIVSEP
00507         execlp(executable, executable, file_name, window_id, (char*)NULL);
00508 #else 
00509         execlp(executable, executable, "-i", window_id, file_name, (char*)NULL);
00510 #endif
00511     
00512     } else if (instance->pID < 0) {           // failed to fork
00513         printf("Failed to fork!!!\n");                  
00514     }
00515 
00516     /*XEvent e;
00517     int started = 0;
00518     while(!started) {
00519         XNextEvent(This->display, &e);
00520         printf("Event type %d\n", e.type);                  
00521         if (e.type == MapNotify) {
00522             started = 1;
00523             XCreateWindowEvent event =  e.xcreatewindow;
00524             printf("Created window x:%d, y: %d, h: %d, w: %d\n", event.x, event.y, event.height, event.width);
00525         }
00526     }*/
00527 
00528 }
00529 
00530 
00531 /* --------------------------------------------------------------------- */
00532 
00533 static void
00534 log_entry(char* msg)
00535 {
00536 #ifdef NZC_GENERATE_LOG 
00537     FILE* fp = fopen("/tmp/plugin_log","a");
00538     if (!fp) return;
00539     fprintf(fp, "--> Unixshell:: %s\n",
00540         msg); 
00541     fflush(fp);
00542     fclose (fp);
00543 #endif
00544 }
00545 
00546 /* --------------------------------------------------------------------- */