Blender V2.61 - r43446
|
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 /* --------------------------------------------------------------------- */