PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/blender-2.63a/source/gameengine/GamePlayer/xembed/UnixShell.c

#
C | 555 lines | 325 code | 112 blank | 118 comment | 67 complexity | e52c20549af690f34448de0bc0b9c969 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, BSD-3-Clause, LGPL-3.0, BSD-2-Clause, Apache-2.0, AGPL-1.0
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  19. * All rights reserved.
  20. *
  21. * The Original Code is: all of this file.
  22. *
  23. * Contributor(s): Enrico Fracasso
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. * NS api template, adapted to link to our own internals.
  27. */
  28. #define MOZ_X11 1
  29. /* -*- Mode: C; tab-width: 8; c-set-style: bsd -*- */
  30. /* UnixShell.c was adapted from the template in the Netscape API. */
  31. /* System: */
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. /* All nsapi stuff. nsapi now needs FILE, so include stdio as well. */
  36. #include <stdio.h>
  37. #include "npapi.h"
  38. /* Native hooks: */
  39. #include "npapi.h"
  40. /* Threading the NSPR way: */
  41. #include "prthread.h"
  42. #include "prlock.h"
  43. #include "blender_plugin_types.h"
  44. #include <signal.h>
  45. /* --------------------------------------------------------------------- */
  46. /** If defined: write to the plugin log file */
  47. #if defined(DEBUG)
  48. #define NZC_GENERATE_LOG
  49. #endif
  50. int32 STREAMBUFSIZE;
  51. /** Generate a log file. */
  52. static void
  53. log_entry(char* msg);
  54. void
  55. execute_blenderplayer(BlenderPluginInstance*);
  56. /* --------------------------------------------------------------------- */
  57. /* Implementations: */
  58. /* --------------------------------------------------------------------- */
  59. /* NPP_GetMIMEDescription() and NPP_GetValue() are called to determine
  60. * the mime types supported by this plugin. */
  61. char*
  62. NPP_GetMIMEDescription(void)
  63. {
  64. log_entry("NPP_GetMIMEDescription");
  65. return("application/x-blender-plugin:blend:Blender 3D web plugin");
  66. }
  67. NPError
  68. NPP_GetValue(
  69. NPP instance,
  70. NPPVariable variable,
  71. void *value
  72. )
  73. {
  74. NPError err = NPERR_NO_ERROR;
  75. log_entry("NPP_GetValue");
  76. switch (variable) {
  77. case NPPVpluginNeedsXEmbed:
  78. log_entry("NPP_GetValue::NPPVpluginNeedsXEmbed");
  79. *((PRBool *)value) = PR_TRUE;
  80. break;
  81. case NPPVpluginNameString:
  82. log_entry("NPP_GetValue::NPPVpluginNameString");
  83. *((char **)value) = "Blender";
  84. break;
  85. case NPPVpluginDescriptionString:
  86. log_entry("NPP_GetValue::NPPVpluginDescriptionString");
  87. *((char **)value) = "Player for interactive 3D content";
  88. break;
  89. case NPPVpluginWindowBool:
  90. log_entry("NPP_GetValue::NPPVpluginWindowBool");
  91. *((PRBool *)value) = PR_FALSE; //not windowless
  92. break;
  93. case NPPVpluginTransparentBool:
  94. log_entry("NPP_GetValue::NPPVpluginTransparentBool");
  95. *((PRBool *)value) = PR_FALSE; // not trasparent
  96. break;
  97. default:
  98. err = NPERR_GENERIC_ERROR;
  99. }
  100. return err;
  101. }
  102. /* --------------------------------------------------------------------- */
  103. /* Mozilla: NPP_Initialize() is called when
  104. * starting the browser, and then every time the plugin is started*/
  105. NPError
  106. NPP_Initialize(void)
  107. {
  108. log_entry("NPP_Initialize");
  109. return NPERR_NO_ERROR;
  110. }
  111. /* --------------------------------------------------------------------- */
  112. void
  113. NPP_Shutdown(void)
  114. {
  115. log_entry("NPP_Shutdown");
  116. }
  117. NPError
  118. NPP_New(
  119. NPMIMEType pluginType,
  120. NPP instance,
  121. uint16 mode,
  122. int16 argc,
  123. char* argn[],
  124. char* argv[],
  125. NPSavedData* saved
  126. )
  127. {
  128. BlenderPluginInstance* This = NULL;
  129. int i = 0;
  130. int retval = 0;
  131. log_entry("NPP_New");
  132. if (instance == NULL)
  133. return NPERR_INVALID_INSTANCE_ERROR;
  134. instance->pdata = NPN_MemAlloc(sizeof(BlenderPluginInstance));
  135. if (instance->pdata == 0)
  136. return NPERR_OUT_OF_MEMORY_ERROR;
  137. This = (BlenderPluginInstance*) instance->pdata;
  138. This->browser_instance = instance;
  139. This->pID = 0;
  140. This->blend_file = 0;
  141. This->temp_mail_file_name = 0;
  142. This->main_file_store = 0;
  143. This->display = NULL;
  144. This->window = 0;
  145. /* Parse the options from the file. Should I do this in the
  146. * implementation file maybe? Now we do a lot with
  147. * instance-specific data. */
  148. /*
  149. while (i <argc ) {
  150. if (!strcmp(argn[i],"src")) {
  151. The blend file to load.
  152. int url_len = strlen(argv[i]);
  153. if ((url_len > 0) && (url_len < 4096) ) {
  154. This->blend_file = NPN_MemAlloc(url_len + 1);
  155. if (This->blend_file == 0)
  156. return NPERR_OUT_OF_MEMORY_ERROR;
  157. strcpy(This->blend_file, argv[i]);
  158. retval = NPN_GetURL(This->browser_instance,
  159. This->blend_file,
  160. NULL);
  161. if (retval != NPERR_NO_ERROR) {
  162. log_entry("Cannot read animation");
  163. NPN_Status(instance, "Cannot read animation file");
  164. This->blend_file = NULL;
  165. return NPERR_NO_ERROR;
  166. }
  167. else {
  168. log_entry("Animation loaded");
  169. }
  170. }
  171. }
  172. i++;
  173. }*/
  174. if (This != NULL) {
  175. return NPERR_NO_ERROR;
  176. }
  177. else {
  178. return NPERR_OUT_OF_MEMORY_ERROR;
  179. }
  180. }
  181. NPError
  182. NPP_Destroy( NPP instance, NPSavedData** save )
  183. {
  184. BlenderPluginInstance* This;
  185. log_entry("NPP_Destroy");
  186. if (instance == NULL)
  187. return NPERR_INVALID_INSTANCE_ERROR;
  188. This = (BlenderPluginInstance*) instance->pdata;
  189. printf("NPP_Destroy ID: 0x%x %d\n", This->window, This->window);
  190. if (This != NULL) {
  191. if (This->pID != 0) {
  192. #ifdef WITH_PRIVSEP
  193. kill(This->pID, SIGTERM);
  194. #else
  195. kill(This->pID, SIGKILL); //if I have to kill blenderplayer directly I need to send SIGKILL
  196. #endif
  197. wait(This->pID);
  198. unlink(This->temp_mail_file_name);
  199. }
  200. // sometimes FF doesn't delete it's own window...
  201. //printf("%s\n", NPN_UserAgent(instance));
  202. /*if (This->display != NULL && This->window != 0)
  203. XDestroyWindow(This->display, This->window);
  204. */
  205. if (This->blend_file) NPN_MemFree(This->blend_file);
  206. if (This->temp_mail_file_name) NPN_MemFree(This->temp_mail_file_name);
  207. if (This->main_file_store) NPN_MemFree(This->main_file_store);
  208. NPN_MemFree(instance->pdata);
  209. instance->pdata = NULL;
  210. }
  211. return NPERR_NO_ERROR;
  212. }
  213. NPError
  214. NPP_SetWindow( NPP instance,NPWindow* window )
  215. {
  216. BlenderPluginInstance* This;
  217. log_entry("NPP_SetWindow");
  218. if (instance == NULL)
  219. return NPERR_INVALID_INSTANCE_ERROR;
  220. /* window handle */
  221. if ((window == NULL) || (window->window == NULL)) {
  222. return NPERR_NO_ERROR; /* mmmmmm */
  223. }
  224. if (window->ws_info == NULL)
  225. return NPERR_NO_ERROR; /* mmmmmm */
  226. This = (BlenderPluginInstance*) instance->pdata;
  227. if (This) {
  228. This->window = (Window) window->window;
  229. NPSetWindowCallbackStruct* window_info = window->ws_info;
  230. This->display = window_info->display;
  231. printf("ID window 0x%x %d\n", window->window, window->window);
  232. return NPERR_NO_ERROR;
  233. }
  234. else {
  235. return NPERR_INVALID_INSTANCE_ERROR;
  236. }
  237. }
  238. NPError
  239. NPP_NewStream(
  240. NPP instance,
  241. NPMIMEType type,
  242. NPStream *stream,
  243. NPBool seekable,
  244. uint16 *stype
  245. )
  246. {
  247. //NPByteRange range;
  248. BlenderPluginInstance* This;
  249. log_entry("NPP_NewStream");
  250. if (instance == NULL)
  251. return NPERR_INVALID_INSTANCE_ERROR;
  252. This = (BlenderPluginInstance*) instance->pdata;
  253. if (!This)
  254. return NPERR_INVALID_INSTANCE_ERROR;
  255. printf("Loading main file %s (%s)\n", stream->url, type);
  256. if ( strcmp(type,"text/html") == 0 ) // original HTML file
  257. return NPERR_NO_ERROR;
  258. This->stream_total = stream->end;
  259. This->stream_retrieved = 0;
  260. This->main_file_store = NPN_MemAlloc(stream->end*sizeof(unsigned char));
  261. if (!This->main_file_store) {
  262. fprintf(stderr, "Blender plugin: Out of memory! "
  263. "Cannot get chunk for loading animation.\n");
  264. return NPERR_OUT_OF_MEMORY_ERROR;
  265. }
  266. This->main_file_stream = stream;
  267. return NPERR_NO_ERROR;
  268. }
  269. /* PLUGIN DEVELOPERS:
  270. * These next 2 functions are directly relevant in a plug-in which
  271. * handles the data in a streaming manner. If you want zero bytes
  272. * because no buffer space is YET available, return 0. As long as
  273. * the stream has not been written to the plugin, Navigator will
  274. * continue trying to send bytes. If the plugin doesn't want them,
  275. * just return some large number from NPP_WriteReady(), and
  276. * ignore them in NPP_Write(). For a NP_ASFILE stream, they are
  277. * still called but can safely be ignored using this strategy.
  278. */
  279. int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
  280. * mode so we can take any size stream in our
  281. * write call (since we ignore it) */
  282. int32
  283. NPP_WriteReady(
  284. NPP instance,
  285. NPStream *stream
  286. )
  287. {
  288. BlenderPluginInstance* This = NULL;
  289. int acceptable = 0;
  290. log_entry("NPP_WriteReady");
  291. if (instance == NULL)
  292. return NPERR_INVALID_INSTANCE_ERROR;
  293. This = (BlenderPluginInstance*) instance->pdata;
  294. if (This == NULL)
  295. return NPERR_INVALID_INSTANCE_ERROR;
  296. /* Check whether buffers already exist: */
  297. if ((This->main_file_stream && This->main_file_store)) {
  298. acceptable = STREAMBUFSIZE;
  299. }
  300. return acceptable;
  301. }
  302. int32
  303. NPP_Write(
  304. NPP instance,
  305. NPStream *stream,
  306. int32 offset,
  307. int32 len,
  308. void *buffer
  309. )
  310. {
  311. BlenderPluginInstance* This = NULL;
  312. int accepted = 0;
  313. log_entry("NPP_Write");
  314. if (instance == NULL)
  315. return NPERR_INVALID_INSTANCE_ERROR;
  316. This = (BlenderPluginInstance*) instance->pdata;
  317. if (This == NULL)
  318. return NPERR_INVALID_INSTANCE_ERROR;
  319. if (stream == This->main_file_stream) {
  320. log_entry("NPP_Write: loading main_file_stream");
  321. memcpy(((unsigned char*)This->main_file_store) + This->stream_retrieved, buffer, len);
  322. accepted = len;
  323. This->stream_retrieved += len;
  324. if (This->stream_retrieved >= This->stream_total) {
  325. log_entry("NPP_Write: main_file_stream loaded");
  326. execute_blenderplayer(This);
  327. }
  328. }
  329. else {
  330. /* the stream ref wasn't set yet..*/
  331. log_entry("NPP_Write: not main stream");
  332. log_entry(stream->url);
  333. accepted = len;
  334. }
  335. return accepted;
  336. }
  337. NPError
  338. NPP_DestroyStream(
  339. NPP instance,
  340. NPStream *stream,
  341. NPError reason
  342. )
  343. {
  344. BlenderPluginInstance* This = NULL;
  345. log_entry("NPP_DestroyStream");
  346. if (instance == NULL)
  347. return NPERR_INVALID_INSTANCE_ERROR;
  348. This = (BlenderPluginInstance*) instance->pdata;
  349. if (This) {
  350. if (reason != NPRES_DONE) {
  351. if (stream == This->main_file_stream) {
  352. // stream destroyed by NPP_Destroy
  353. NPN_Status(instance, "Cannot read animation file");
  354. //main_file_failed(This->application);
  355. }
  356. }
  357. return NPERR_NO_ERROR;
  358. }
  359. else {
  360. return NPERR_INVALID_INSTANCE_ERROR;
  361. }
  362. }
  363. /* Not supposed to be called anymore... Anyway, we don't need the
  364. * results. Some Moz implementations will call this one regardless the
  365. * desired transfer mode! */
  366. void
  367. NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname )
  368. {
  369. /* log_entry("NPP_StreamAsFile"); */
  370. }
  371. void
  372. NPP_Print(NPP instance, NPPrint* printInfo )
  373. {
  374. log_entry("NPP_Print");
  375. if (printInfo == NULL)
  376. return;
  377. if (instance != NULL) {
  378. if (printInfo->mode == NP_FULL) {
  379. printInfo->print.fullPrint.pluginPrinted = FALSE;
  380. }
  381. else { /* If not fullscreen, we must be embedded */
  382. }
  383. }
  384. }
  385. void
  386. execute_blenderplayer(BlenderPluginInstance* instance)
  387. {
  388. char file_name[] = "/tmp/blender.XXXXXX";
  389. int fd = mkstemp(file_name);
  390. ssize_t real_size = write(fd, instance->main_file_store, instance->stream_retrieved);
  391. close(fd);
  392. instance->temp_mail_file_name = NPN_MemAlloc(strlen(file_name) + 1);
  393. strcpy(instance->temp_mail_file_name, file_name);
  394. instance->pID = fork();
  395. //XSelectInput(This->display , This->window, SubstructureNotifyMask);
  396. //XSync(This->display, FALSE);
  397. #if defined(WITH_APPARMOR)
  398. const char* executable = "blenderplayer-web";
  399. #elif defined(WITH_PRIVSEP)
  400. const char* executable = "blenderplayer-wrapper";
  401. #else
  402. const char* executable = "blenderplayer";
  403. #endif
  404. if (instance->pID == 0) { // child
  405. char window_id[50];
  406. sprintf(window_id, "%d", instance->window);
  407. //exit(0);
  408. #ifdef WITH_PRIVSEP
  409. execlp(executable, executable, file_name, window_id, (char*)NULL);
  410. #else
  411. execlp(executable, executable, "-i", window_id, file_name, (char*)NULL);
  412. #endif
  413. }
  414. else if (instance->pID < 0) { // failed to fork
  415. printf("Failed to fork!!!\n");
  416. }
  417. /*XEvent e;
  418. int started = 0;
  419. while (!started) {
  420. XNextEvent(This->display, &e);
  421. printf("Event type %d\n", e.type);
  422. if (e.type == MapNotify) {
  423. started = 1;
  424. XCreateWindowEvent event = e.xcreatewindow;
  425. printf("Created window x:%d, y: %d, h: %d, w: %d\n", event.x, event.y, event.height, event.width);
  426. }
  427. }*/
  428. }
  429. /* --------------------------------------------------------------------- */
  430. static void
  431. log_entry(char* msg)
  432. {
  433. #ifdef NZC_GENERATE_LOG
  434. FILE* fp = fopen("/tmp/plugin_log","a");
  435. if (!fp) return;
  436. fprintf(fp, "--> Unixshell:: %s\n",
  437. msg);
  438. fflush(fp);
  439. fclose (fp);
  440. #endif
  441. }
  442. /* --------------------------------------------------------------------- */