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