PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/hbabcock/drivers/wxwidgets.cpp

#
C++ | 1312 lines | 747 code | 229 blank | 336 comment | 110 complexity | 414699c9c86c3d1202f4c477e9ed01a3 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0
  1. /* $Id: wxwidgets.cpp 9715 2009-03-11 14:33:48Z smekal $
  2. Copyright (C) 2005 Werner Smekal, Sjaak Verdoold
  3. Copyright (C) 2005 Germain Carrera Corraleche
  4. Copyright (C) 1999 Frank Huebner
  5. This file is part of PLplot.
  6. PLplot is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Library Public License as published
  8. by the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. PLplot is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public License
  15. along with PLplot; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. /* TODO:
  19. * - NA
  20. */
  21. /* wxwidgets headers */
  22. #include <wx/wx.h>
  23. #include <wx/wfstream.h>
  24. #include <wx/except.h>
  25. #include "plDevs.h"
  26. /* plplot headers */
  27. #include "plplotP.h"
  28. #include "drivers.h"
  29. /* C/C++ headers */
  30. #include <cstdio>
  31. #include "wxwidgets.h"
  32. #ifdef __WXMAC__
  33. #include <Carbon/Carbon.h>
  34. extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
  35. #endif
  36. DECLARE_PLAPP( wxPLplotApp )
  37. /*--------------------------------------------------------------------------
  38. * void Log_Verbose( const char *fmt, ... )
  39. *
  40. * Print verbose debug message to stderr (printf style).
  41. *--------------------------------------------------------------------------*/
  42. void Log_Verbose( const char *fmt, ... )
  43. {
  44. #ifdef _DEBUG_VERBOSE
  45. va_list args;
  46. va_start( args, fmt );
  47. fprintf( stderr, "Verbose: " );
  48. vfprintf( stderr, fmt, args );
  49. fprintf( stderr, "\n" );
  50. va_end( args );
  51. fflush( stderr );
  52. #endif
  53. }
  54. /*--------------------------------------------------------------------------
  55. * void Log_Debug( const char *fmt, ... )
  56. *
  57. * Print debug message to stderr (printf style).
  58. *--------------------------------------------------------------------------*/
  59. void Log_Debug( const char *fmt, ... )
  60. {
  61. #ifdef _DEBUG
  62. va_list args;
  63. va_start( args, fmt );
  64. fprintf( stderr, "Debug: " );
  65. vfprintf( stderr, fmt, args );
  66. fprintf( stderr, "\n" );
  67. va_end( args );
  68. fflush( stderr );
  69. #endif
  70. }
  71. /*----------------------------------------------------------------------
  72. * In the following you'll find the driver functions which are
  73. * are needed by the plplot core.
  74. *----------------------------------------------------------------------*/
  75. /* Device info */
  76. #ifdef __cplusplus
  77. extern "C" {
  78. #endif
  79. PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_wxwidgets =
  80. #ifdef PLD_wxwidgets
  81. "wxwidgets:wxWidgets Driver:1:wxwidgets:51:wxwidgets\n"
  82. #endif
  83. #ifdef PLD_wxpng
  84. "wxpng:wxWidgets PNG Driver:0:wxwidgets:52:wxpng\n"
  85. #endif
  86. ;
  87. #ifdef __cplusplus
  88. }
  89. #endif
  90. /*--------------------------------------------------------------------------
  91. * wxPLDevBase::wxPLDevBase( void )
  92. *
  93. * Contructor of base class of wxPLDev classes.
  94. *--------------------------------------------------------------------------*/
  95. wxPLDevBase::wxPLDevBase( int bcknd ) : backend(bcknd)
  96. {
  97. // Log_Verbose( "wxPLDevBase::wxPLDevBase()" );
  98. ready = false;
  99. ownGUI = false;
  100. waiting = false;
  101. resizing = false;
  102. exit=false;
  103. comcount = 0;
  104. m_frame=NULL;
  105. xpos=0;
  106. ypos=0;
  107. // width, height are set in plD_init_wxwidgets
  108. // bm_width, bm_height are set in install_buffer
  109. // xmin, xmax, ymin, ymax are set in plD_init_wxwidgets
  110. // scalex, scaley are set in plD_init_wxwidgets
  111. plstate_width = false;
  112. plstate_color0 = false;
  113. plstate_color1 = false;
  114. locate_mode=0;
  115. draw_xhair=false;
  116. newclipregion=true;
  117. clipminx=1024;
  118. clipmaxx=0;
  119. clipminy=800;
  120. clipmaxy=0;
  121. freetype=0;
  122. smooth_text=0;
  123. devName = (const char **)malloc( NDEV * sizeof(char**) );
  124. memset( devName, '\0', NDEV * sizeof(char**) );
  125. devDesc = (const char **)malloc( NDEV * sizeof(char**) );
  126. memset( devDesc, '\0', NDEV * sizeof(char**) );
  127. ndev=NDEV;
  128. }
  129. wxPLDevBase::~wxPLDevBase( void )
  130. {
  131. if( devDesc )
  132. free( devDesc );
  133. if( devName )
  134. free( devName );
  135. }
  136. void wxPLDevBase::AddtoClipRegion( int x1, int y1, int x2, int y2 )
  137. {
  138. newclipregion=false;
  139. if( x1<x2 ) {
  140. if( x1<clipminx ) clipminx=x1;
  141. if( x2>clipmaxx ) clipmaxx=x2;
  142. } else {
  143. if( x2<clipminx ) clipminx=x2;
  144. if( x1>clipmaxx ) clipmaxx=x1;
  145. }
  146. if( y1<y2 ) {
  147. if( y1<clipminy ) clipminy=y1;
  148. if( y2>clipmaxy ) clipmaxy=y2;
  149. } else {
  150. if( y2<clipminy ) clipminy=y2;
  151. if( y1>clipmaxy ) clipmaxy=y1;
  152. }
  153. }
  154. void wxPLDevBase::PSDrawText( PLUNICODE* ucs4, int ucs4Len, bool drawText )
  155. {
  156. int i = 0;
  157. char utf8_string[max_string_length];
  158. char utf8[5];
  159. memset( utf8_string, '\0', max_string_length );
  160. /* Get PLplot escape character */
  161. char plplotEsc;
  162. plgesc( &plplotEsc );
  163. /* Get the curent font */
  164. fontScale = 1.0;
  165. yOffset = 0.0;
  166. PLUNICODE fci;
  167. plgfci( &fci );
  168. PSSetFont( fci );
  169. textWidth=0;
  170. textHeight=0;
  171. while( i < ucs4Len ) {
  172. if( ucs4[i] < PL_FCI_MARK ) { /* not a font change */
  173. if( ucs4[i] != (PLUNICODE)plplotEsc ) { /* a character to display */
  174. ucs4_to_utf8( ucs4[i], utf8 );
  175. strncat( utf8_string, utf8, max_string_length );
  176. i++;
  177. continue;
  178. }
  179. i++;
  180. if( ucs4[i] == (PLUNICODE)plplotEsc ) { /* a escape character to display */
  181. ucs4_to_utf8( ucs4[i], utf8 );
  182. strncat( utf8_string, utf8, max_string_length );
  183. i++;
  184. continue;
  185. } else {
  186. if( ucs4[i] == (PLUNICODE)'u' ) { /* Superscript */
  187. // draw string so far
  188. PSDrawTextToDC( utf8_string, drawText );
  189. // change font scale
  190. if( yOffset<0.0 )
  191. fontScale *= 1.25; /* Subscript scaling parameter */
  192. else
  193. fontScale *= 0.8; /* Subscript scaling parameter */
  194. PSSetFont( fci );
  195. yOffset += scaley * fontSize * fontScale / 2.;
  196. }
  197. if( ucs4[i] == (PLUNICODE)'d' ) { /* Subscript */
  198. // draw string so far
  199. PSDrawTextToDC( utf8_string, drawText );
  200. // change font scale
  201. double old_fontScale=fontScale;
  202. if( yOffset>0.0 )
  203. fontScale *= 1.25; /* Subscript scaling parameter */
  204. else
  205. fontScale *= 0.8; /* Subscript scaling parameter */
  206. PSSetFont( fci );
  207. yOffset -= scaley * fontSize * old_fontScale / 2.;
  208. }
  209. if( ucs4[i] == (PLUNICODE)'-' ) { /* underline */
  210. // draw string so far
  211. PSDrawTextToDC( utf8_string, drawText );
  212. underlined = !underlined;
  213. PSSetFont( fci );
  214. }
  215. if( ucs4[i] == (PLUNICODE)'+' ) { /* overline */
  216. /* not implemented yet */
  217. }
  218. i++;
  219. }
  220. } else { /* a font change */
  221. // draw string so far
  222. PSDrawTextToDC( utf8_string, drawText );
  223. // get new font
  224. fci = ucs4[i];
  225. PSSetFont( fci );
  226. i++;
  227. }
  228. }
  229. PSDrawTextToDC( utf8_string, drawText );
  230. }
  231. /*--------------------------------------------------------------------------
  232. * void common_init( PLStream *pls )
  233. *
  234. * Basic initialization for all devices.
  235. *--------------------------------------------------------------------------*/
  236. wxPLDevBase* common_init( PLStream *pls )
  237. {
  238. // Log_Verbose( "common_init()" );
  239. wxPLDevBase* dev;
  240. /* default options */
  241. static PLINT freetype=-1;
  242. static PLINT smooth_text=1;
  243. static PLINT text=-1;
  244. static PLINT hrshsym = 0;
  245. /* default backend uses wxGraphicsContext, if not available
  246. the agg library will be used, if not available the basic
  247. backend will be used. */
  248. static PLINT backend=wxBACKEND_DC;
  249. #if wxUSE_GRAPHICS_CONTEXT
  250. backend=wxBACKEND_GC;
  251. #else
  252. #ifdef HAVE_AGG
  253. backend=wxBACKEND_AGG;
  254. #endif
  255. #endif
  256. DrvOpt wx_options[] = {
  257. #ifdef HAVE_FREETYPE
  258. {"freetype", DRV_INT, &freetype, "Use FreeType library"},
  259. {"smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)"},
  260. #endif
  261. {"hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)"},
  262. {"backend", DRV_INT, &backend, "Choose backend: (0) standard, (1) using AGG library, (2) using wxGraphicsContext"},
  263. {"text", DRV_INT, &text, "Use own text routines (text=0|1)"},
  264. {NULL, DRV_INT, NULL, NULL}
  265. };
  266. /* Check for and set up driver options */
  267. plParseDrvOpts( wx_options );
  268. /* allocate memory for the device storage */
  269. switch( backend )
  270. {
  271. case wxBACKEND_GC:
  272. /* in case wxGraphicsContext isn't available, the next backend (agg
  273. if available) in this list will be used */
  274. #if wxUSE_GRAPHICS_CONTEXT
  275. dev = new wxPLDevGC;
  276. /* by default the own text routines are used for wxGC */
  277. if(text==-1)
  278. text=1;
  279. freetype = 0; /* this backend is vector oriented and doesn't know pixels */
  280. break;
  281. #endif
  282. case wxBACKEND_AGG:
  283. /* in case the agg library isn't available, the standard backend
  284. will be used */
  285. #ifdef HAVE_AGG
  286. dev = new wxPLDevAGG;
  287. /* by default the freetype text routines are used for wxAGG */
  288. text = 0; /* text processing doesn't work yet for the AGG backend */
  289. if(freetype==-1)
  290. freetype=1;
  291. break;
  292. #endif
  293. default:
  294. dev = new wxPLDevDC;
  295. /* by default the own text routines are used for wxDC */
  296. if(text==-1)
  297. if(freetype!=1)
  298. text=1;
  299. else
  300. text=0;
  301. if(freetype==-1)
  302. freetype=0;
  303. break;
  304. }
  305. if( dev == NULL) {
  306. fprintf( stderr, "Insufficient memory\n" );
  307. exit( 0 );
  308. }
  309. pls->dev = (void*)dev;
  310. /* be verbose and write out debug messages */
  311. #ifdef _DEBUG
  312. pls->verbose = 1;
  313. pls->debug = 1;
  314. #else
  315. pls->verbose = 0;
  316. pls->debug = 0;
  317. #endif
  318. pls->color = 1; /* Is a color device */
  319. pls->dev_fill0 = 1; /* Can handle solid fills */
  320. pls->dev_fill1 = 0; /* Can't handle pattern fills */
  321. pls->dev_dash = 0;
  322. pls->dev_clear = 1; /* driver supports clear */
  323. if( text ) {
  324. pls->dev_text = 1; /* want to draw text */
  325. pls->dev_unicode = 1; /* want unicode */
  326. if( hrshsym )
  327. pls->dev_hrshsym = 1;
  328. }
  329. #ifdef HAVE_FREETYPE
  330. /* own text routines have higher priority over freetype
  331. if text and freetype option are set to 1 */
  332. if( !text) {
  333. dev->smooth_text=smooth_text;
  334. dev->freetype=freetype;
  335. }
  336. if( dev->freetype ) {
  337. pls->dev_text = 1; /* want to draw text */
  338. pls->dev_unicode = 1; /* want unicode */
  339. if( hrshsym )
  340. pls->dev_hrshsym = 1;
  341. init_freetype_lv1( pls );
  342. FT_Data* FT=(FT_Data *)pls->FT;
  343. FT->want_smooth_text=smooth_text;
  344. }
  345. #endif
  346. /* initialize frame size and position */
  347. if( pls->xlength <= 0 || pls->ylength <=0 )
  348. plspage( 0.0, 0.0, (PLINT)(CANVAS_WIDTH*DEVICE_PIXELS_PER_IN),
  349. (PLINT)(CANVAS_HEIGHT*DEVICE_PIXELS_PER_IN), 0, 0 );
  350. dev->width=pls->xlength;
  351. dev->height=pls->ylength;
  352. dev->clipminx=pls->xlength;
  353. dev->clipminy=pls->ylength;
  354. if( pls->xoffset!=0 || pls->yoffset!=0) {
  355. dev->xpos = (int)(pls->xoffset);
  356. dev->ypos = (int)(pls->yoffset);
  357. }
  358. /* If portrait mode, apply a rotation and set freeaspect */
  359. if( pls->portrait ) {
  360. plsdiori( (PLFLT)(4 - ORIENTATION) );
  361. pls->freeaspect = 1;
  362. }
  363. /* Set the number of pixels per mm */
  364. plP_setpxl( (PLFLT)VIRTUAL_PIXELS_PER_MM, (PLFLT)VIRTUAL_PIXELS_PER_MM );
  365. /* Set up physical limits of plotting device (in drawing units) */
  366. plP_setphy( (PLINT)0, (PLINT)(CANVAS_WIDTH*VIRTUAL_PIXELS_PER_IN),
  367. (PLINT)0, (PLINT)(CANVAS_HEIGHT*VIRTUAL_PIXELS_PER_IN) );
  368. /* get physical device limits coordinates */
  369. plP_gphy( &dev->xmin, &dev->xmax, &dev->ymin, &dev->ymax );
  370. /* setting scale factors */
  371. dev->scalex=(PLFLT)(dev->xmax-dev->xmin)/(dev->width);
  372. dev->scaley=(PLFLT)(dev->ymax-dev->ymin)/(dev->height);
  373. /* set dpi */
  374. plspage(VIRTUAL_PIXELS_PER_IN/dev->scalex, VIRTUAL_PIXELS_PER_IN/dev->scaley, 0, 0, 0, 0);
  375. #ifdef HAVE_FREETYPE
  376. if( dev->freetype )
  377. init_freetype_lv2( pls );
  378. #endif
  379. /* find out what file drivers are available */
  380. plgFileDevs( &dev->devDesc, &dev->devName, &dev->ndev );
  381. return dev;
  382. }
  383. #ifdef PLD_wxwidgets
  384. /*--------------------------------------------------------------------------
  385. * void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
  386. *
  387. * Make wxwidgets driver functions known to plplot.
  388. *--------------------------------------------------------------------------*/
  389. void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
  390. {
  391. #ifndef ENABLE_DYNDRIVERS
  392. pdt->pl_MenuStr = "wxWidgets DC";
  393. pdt->pl_DevName = "wxwidgets";
  394. #endif
  395. pdt->pl_type = plDevType_Interactive;
  396. pdt->pl_seq = 51;
  397. pdt->pl_init = (plD_init_fp) plD_init_wxwidgets;
  398. pdt->pl_line = (plD_line_fp) plD_line_wxwidgets;
  399. pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wxwidgets;
  400. pdt->pl_eop = (plD_eop_fp) plD_eop_wxwidgets;
  401. pdt->pl_bop = (plD_bop_fp) plD_bop_wxwidgets;
  402. pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wxwidgets;
  403. pdt->pl_state = (plD_state_fp) plD_state_wxwidgets;
  404. pdt->pl_esc = (plD_esc_fp) plD_esc_wxwidgets;
  405. }
  406. /*--------------------------------------------------------------------------
  407. * plD_init_wxwidgets( PLStream* pls )
  408. *
  409. * Initialize wxWidgets device.
  410. *--------------------------------------------------------------------------*/
  411. void plD_init_wxwidgets( PLStream* pls )
  412. {
  413. // Log_Verbose( "plD_init_wxwidgets()" );
  414. wxPLDevBase* dev;
  415. dev = common_init( pls );
  416. pls->plbuf_write = 1; /* use the plot buffer! */
  417. pls->termin = 1; /* interactive device */
  418. pls->graphx = GRAPHICS_MODE; /* No text mode for this driver (at least for now, might add a console window if I ever figure it out and have the inclination) */
  419. dev->showGUI = true;
  420. dev->bitmapType = (wxBitmapType)0;
  421. }
  422. #endif /* PLD_wxwidgets */
  423. #ifdef PLD_wxpng
  424. /*--------------------------------------------------------------------------
  425. * void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
  426. *
  427. * Make wxpng driver functions known to plplot.
  428. *--------------------------------------------------------------------------*/
  429. void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
  430. {
  431. #ifndef ENABLE_DYNDRIVERS
  432. pdt->pl_MenuStr = "wxWidgets PNG driver";
  433. pdt->pl_DevName = "wxpng";
  434. #endif
  435. pdt->pl_type = plDevType_FileOriented;
  436. pdt->pl_seq = 52;
  437. pdt->pl_init = (plD_init_fp) plD_init_wxpng;
  438. pdt->pl_line = (plD_line_fp) plD_line_wxwidgets;
  439. pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wxwidgets;
  440. pdt->pl_eop = (plD_eop_fp) plD_eop_wxwidgets;
  441. pdt->pl_bop = (plD_bop_fp) plD_bop_wxwidgets;
  442. pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wxwidgets;
  443. pdt->pl_state = (plD_state_fp) plD_state_wxwidgets;
  444. pdt->pl_esc = (plD_esc_fp) plD_esc_wxwidgets;
  445. }
  446. /*--------------------------------------------------------------------------
  447. * void plD_init_wxpng( PLStream *pls )
  448. *
  449. * Initialize wxpng device.
  450. *--------------------------------------------------------------------------*/
  451. void plD_init_wxpng( PLStream *pls )
  452. {
  453. // Log_Verbose( "plD_init_wxwidgets()" );
  454. wxPLDevBase* dev;
  455. dev = common_init( pls );
  456. /* Initialize family file info */
  457. plFamInit( pls );
  458. /* Prompt for a file name if not already set. */
  459. plOpenFile( pls );
  460. pls->plbuf_write = 1; /* use the plot buffer! */
  461. pls->termin = 0; /* file oriented device */
  462. pls->graphx = GRAPHICS_MODE; /* No text mode for this driver (at least for now, might add a console window if I ever figure it out and have the inclination) */
  463. pls->page = 0;
  464. dev->showGUI = false;
  465. dev->bitmapType = wxBITMAP_TYPE_PNG;
  466. }
  467. #endif /* PLD_wxpng */
  468. /*--------------------------------------------------------------------------
  469. * void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a,
  470. * short x2a, short y2a )
  471. *
  472. * Draws a line from (x1a, y1a) to (x2a, y2a).
  473. *--------------------------------------------------------------------------*/
  474. void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
  475. {
  476. // Log_Verbose( "plD_line_wxwidgets(x1a=%d, y1a=%d, x2a=%d, y2a=%d)", x1a, y1a, x2a, y2a );
  477. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  478. if( !(dev->ready) )
  479. install_buffer( pls );
  480. dev->DrawLine( x1a, y1a, x2a, y2a );
  481. if( !(dev->resizing) && dev->ownGUI ) {
  482. dev->comcount+=10;
  483. if( dev->comcount>MAX_COMCOUNT ) {
  484. wxRunApp( pls, true );
  485. dev->comcount=0;
  486. }
  487. }
  488. }
  489. /*--------------------------------------------------------------------------
  490. * void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya,
  491. * PLINT npts )
  492. *
  493. * Draw a poly line - points are in xa and ya arrays.
  494. *--------------------------------------------------------------------------*/
  495. void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya, PLINT npts )
  496. {
  497. // Log_Verbose( "plD_polyline_wxwidgets()" );
  498. /* should be changed to use the wxDC::DrawLines function? */
  499. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  500. if( !(dev->ready) )
  501. install_buffer( pls );
  502. dev->DrawPolyline( xa, ya, npts );
  503. if( !(dev->resizing) && dev->ownGUI ) {
  504. dev->comcount+=10;
  505. if( dev->comcount>MAX_COMCOUNT ) {
  506. wxRunApp( pls, true );
  507. dev->comcount=0;
  508. }
  509. }
  510. }
  511. /*--------------------------------------------------------------------------
  512. * void plD_eop_wxwidgets( PLStream *pls )
  513. *
  514. * End of Page. This function is called if a "end of page" is send by the
  515. * user. This command is ignored if we have the plot embedded in a
  516. * wxWidgets application, otherwise the application created by the device
  517. * takes over.
  518. *--------------------------------------------------------------------------*/
  519. void plD_eop_wxwidgets( PLStream *pls )
  520. {
  521. // Log_Verbose( "plD_eop_wxwidgets()" );
  522. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  523. if( dev->bitmapType ) {
  524. wxMemoryDC memDC;
  525. wxBitmap bitmap( dev->width, dev->height, -1 );
  526. memDC.SelectObject( bitmap );
  527. dev->BlitRectangle( &memDC, 0, 0, dev->width, dev->height );
  528. wxImage buffer=bitmap.ConvertToImage();
  529. wxFFileOutputStream fstream( pls->OutFile );
  530. if(!(buffer.SaveFile( fstream, dev->bitmapType )))
  531. puts("Troubles saving file!");
  532. memDC.SelectObject( wxNullBitmap );
  533. }
  534. if( dev->ownGUI )
  535. if ( pls->nopause || !dev->showGUI )
  536. wxRunApp( pls, true );
  537. else
  538. wxRunApp( pls );
  539. }
  540. /*--------------------------------------------------------------------------
  541. * void plD_bop_wxwidgets( PLStream *pls )
  542. *
  543. * Begin of page. Before any plot command, this function is called, If we
  544. * have already a dc the background is cleared in background color and some
  545. * state calls are resent - this is because at the first call of this
  546. * function, a dc does most likely not exist, but state calls are recorded
  547. * and when a new dc is created this function is called again.
  548. *--------------------------------------------------------------------------*/
  549. void plD_bop_wxwidgets( PLStream *pls )
  550. {
  551. // Log_Verbose( "plD_bop_wxwidgets()" );
  552. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  553. if( dev->ready ) {
  554. /*if( pls->termin==0 ) {
  555. plGetFam( pls );*/
  556. /* force new file if pls->family set for all subsequent calls to plGetFam
  557. n.b. putting this after plGetFam call is important since plinit calls
  558. bop, and you don't want the familying sequence started until after
  559. that first call to bop.*/
  560. /* n.b. pls->dev can change because of an indirect call to plD_init_png
  561. from plGetFam if familying is enabled. Thus, wait to define dev until
  562. now. */
  563. /*dev = (wxPLDevBase*)pls->dev;
  564. pls->famadv = 1;
  565. pls->page++;
  566. }*/
  567. /* clear background */
  568. PLINT bgr, bgg, bgb; /* red, green, blue */
  569. plgcolbg( &bgr, &bgg, &bgb); /* get background color information */
  570. dev->ClearBackground( bgr, bgg, bgb );
  571. /* Replay escape calls that come in before PLESC_DEVINIT. All of them
  572. * required a DC that didn't exist yet.
  573. */
  574. if( dev->plstate_width )
  575. plD_state_wxwidgets( pls, PLSTATE_WIDTH );
  576. dev->plstate_width = false;
  577. if( dev->plstate_color0 )
  578. plD_state_wxwidgets( pls, PLSTATE_COLOR0 );
  579. dev->plstate_color0 = false;
  580. if( dev->plstate_color1 )
  581. plD_state_wxwidgets( pls, PLSTATE_COLOR1 );
  582. dev->plstate_color1 = false;
  583. /* why this? xwin driver has this */
  584. /* pls->page++; */
  585. }
  586. }
  587. /*--------------------------------------------------------------------------
  588. * void plD_tidy_wxwidgets( PLStream *pls )
  589. *
  590. * This function is called, if all plots are done.
  591. *--------------------------------------------------------------------------*/
  592. void plD_tidy_wxwidgets( PLStream *pls )
  593. {
  594. // Log_Verbose( "plD_tidy_wxwidgets()" );
  595. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  596. #ifdef HAVE_FREETYPE
  597. if( dev->freetype ) {
  598. FT_Data *FT=(FT_Data *)pls->FT;
  599. plscmap0n( FT->ncol0_org );
  600. plD_FreeType_Destroy( pls );
  601. }
  602. #endif
  603. if( dev->ownGUI ) {
  604. wxPLGetApp().RemoveFrame( dev->m_frame );
  605. if( !wxPLGetApp().FrameCount() )
  606. wxUninitialize();
  607. }
  608. delete dev;
  609. pls->dev=NULL; /* since in plcore.c pls->dev is free_mem'd */
  610. }
  611. /*--------------------------------------------------------------------------*\
  612. * void plD_state_wxwidgets( PLStream *pls, PLINT op )
  613. *
  614. * Handler for several state codes. Here we take care of setting the width
  615. * and color of the pen.
  616. \*--------------------------------------------------------------------------*/
  617. void plD_state_wxwidgets( PLStream *pls, PLINT op )
  618. {
  619. // Log_Verbose( "plD_state_wxwidgets(op=%d)", op );
  620. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  621. switch( op ) {
  622. case PLSTATE_WIDTH: /* 1 */
  623. if( dev->ready )
  624. dev->SetWidth( pls );
  625. else
  626. dev->plstate_width = true;
  627. break;
  628. case PLSTATE_COLOR0: /* 2 */
  629. if( dev->ready )
  630. dev->SetColor0( pls );
  631. else
  632. dev->plstate_color0 = true;
  633. break;
  634. case PLSTATE_COLOR1: /* 3 */
  635. if( dev->ready )
  636. dev->SetColor1( pls );
  637. else
  638. dev->plstate_color1 = true;
  639. break;
  640. default:
  641. if( !(dev->ready) )
  642. install_buffer( pls );
  643. }
  644. }
  645. /*--------------------------------------------------------------------------*\
  646. * void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
  647. *
  648. * Handler for several escape codes. Here we take care of filled polygons,
  649. * XOR or copy mode, initialize device (install dc from outside), and if
  650. * there is freetype support, rerendering of text.
  651. \*--------------------------------------------------------------------------*/
  652. void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
  653. {
  654. // Log_Verbose( "plD_esc_wxwidgets(op=%d, ptr=%x)", op, ptr );
  655. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  656. switch (op) {
  657. case PLESC_FILL:
  658. fill_polygon( pls );
  659. break;
  660. case PLESC_XORMOD:
  661. /* switch between wxXOR and wxCOPY */
  662. /* if( dev->ready ) {
  663. if( dev->m_dc->GetLogicalFunction() == wxCOPY )
  664. dev->m_dc->SetLogicalFunction( wxXOR );
  665. else if( dev->m_dc->GetLogicalFunction() == wxXOR )
  666. dev->m_dc->SetLogicalFunction( wxCOPY );
  667. } */
  668. break;
  669. case PLESC_DEVINIT:
  670. dev->SetExternalBuffer( ptr );
  671. /* replay begin of page call and state settings */
  672. plD_bop_wxwidgets( pls );
  673. break;
  674. case PLESC_HAS_TEXT:
  675. if( !(dev->ready) )
  676. install_buffer( pls );
  677. if( dev->freetype ) {
  678. #ifdef HAVE_FREETYPE
  679. plD_render_freetype_text( pls, (EscText *)ptr );
  680. #endif
  681. } else
  682. dev->ProcessString( pls, (EscText *)ptr );
  683. break;
  684. case PLESC_RESIZE:
  685. {
  686. wxSize* size=(wxSize*)ptr;
  687. wx_set_size( pls, size->GetWidth(), size->GetHeight() );
  688. }
  689. break;
  690. case PLESC_CLEAR:
  691. if( !(dev->ready) )
  692. install_buffer( pls );
  693. /* Since the plot is updated only every MAX_COMCOUNT commands (usually 5000)
  694. before we clear the screen we need to show the plot at least once :) */
  695. if( !(dev->resizing) && dev->ownGUI ) {
  696. wxRunApp( pls, true );
  697. dev->comcount=0;
  698. }
  699. dev->ClearBackground( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b,
  700. pls->sppxmi, pls->sppymi, pls->sppxma, pls->sppyma );
  701. break;
  702. case PLESC_GETC:
  703. if( dev->ownGUI )
  704. GetCursorCmd( pls, (PLGraphicsIn *) ptr );
  705. break;
  706. case PLESC_GETBACKEND:
  707. *((int*)ptr) = dev->backend;
  708. break;
  709. default:
  710. break;
  711. }
  712. }
  713. /*--------------------------------------------------------------------------*\
  714. * static void fill_polygon( PLStream *pls )
  715. *
  716. * Fill polygon described in points pls->dev_x[] and pls->dev_y[].
  717. \*--------------------------------------------------------------------------*/
  718. static void fill_polygon( PLStream *pls )
  719. {
  720. // Log_Verbose( "fill_polygon(), npts=%d, x[0]=%d, y[0]=%d", pls->dev_npts, pls->dev_y[0], pls->dev_y[0] );
  721. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  722. if( !(dev->ready) )
  723. install_buffer( pls );
  724. dev->FillPolygon( pls );
  725. if( !(dev->resizing) && dev->ownGUI ) {
  726. dev->comcount+=10;
  727. if( dev->comcount>MAX_COMCOUNT ) {
  728. wxRunApp( pls, true );
  729. dev->comcount=0;
  730. }
  731. }
  732. }
  733. /*--------------------------------------------------------------------------*\
  734. * void wx_set_size( PLStream* pls, int width, int height )
  735. *
  736. * Adds a dc to the stream. The associated device is attached to the canvas
  737. * as the property "dev".
  738. \*--------------------------------------------------------------------------*/
  739. void wx_set_size( PLStream* pls, int width, int height )
  740. {
  741. /* TODO: buffer must be resized here or in wxplotstream */
  742. // Log_Verbose( "wx_set_size()" );
  743. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  744. /* set new size and scale parameters */
  745. dev->width = width;
  746. dev->height = height;
  747. dev->scalex=(PLFLT)(dev->xmax-dev->xmin)/dev->width;
  748. dev->scaley=(PLFLT)(dev->ymax-dev->ymin)/dev->height;
  749. /* recalculate the dpi used in calculation of fontsize */
  750. pls->xdpi = VIRTUAL_PIXELS_PER_IN/dev->scalex;
  751. pls->ydpi = VIRTUAL_PIXELS_PER_IN/dev->scaley;
  752. /* clear background if we have a dc, since it's invalid (TODO: why, since in bop
  753. it must be cleared anyway?) */
  754. if( dev->ready ) {
  755. PLINT bgr, bgg, bgb; /* red, green, blue */
  756. plgcolbg( &bgr, &bgg, &bgb); /* get background color information */
  757. dev->CreateCanvas();
  758. dev->ClearBackground( bgr, bgg, bgb );
  759. }
  760. /* freetype parameters must also be changed */
  761. #ifdef HAVE_FREETYPE
  762. if( dev->freetype ) {
  763. FT_Data *FT=(FT_Data *)pls->FT;
  764. FT->scalex=dev->scalex;
  765. FT->scaley=dev->scaley;
  766. FT->ymax=dev->height;
  767. }
  768. #endif
  769. }
  770. /*----------------------------------------------------------------------
  771. * int plD_errorexithandler_wxwidgets( const char *errormessage )
  772. *
  773. * If an PLplot error occurs, this function shows a dialog regarding
  774. * this error and than exits.
  775. *----------------------------------------------------------------------*/
  776. int plD_errorexithandler_wxwidgets( const char *errormessage )
  777. {
  778. if( errormessage[0] ) {
  779. wxMessageDialog dialog( 0, wxString(errormessage, *wxConvCurrent),wxString("wxWidgets PLplot App error",*wxConvCurrent),wxOK|wxICON_ERROR );
  780. dialog.ShowModal();
  781. }
  782. return 0;
  783. }
  784. /*----------------------------------------------------------------------
  785. * void plD_erroraborthandler_wxwidgets( const char *errormessage )
  786. *
  787. * If PLplot aborts, this function shows a dialog regarding
  788. * this error.
  789. *----------------------------------------------------------------------*/
  790. void plD_erroraborthandler_wxwidgets( const char *errormessage )
  791. {
  792. if( errormessage[0] ) {
  793. wxMessageDialog dialog( 0,(wxString(errormessage, *wxConvCurrent)+wxString(" aborting operation...", *wxConvCurrent)), wxString("wxWidgets PLplot App abort",*wxConvCurrent), wxOK|wxICON_ERROR );
  794. dialog.ShowModal();
  795. }
  796. }
  797. #ifdef HAVE_FREETYPE
  798. /*----------------------------------------------------------------------*\
  799. * static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  800. *
  801. * callback function, of type "plD_pixel_fp", which specifies how a single
  802. * pixel is set in the current colour.
  803. \*----------------------------------------------------------------------*/
  804. static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  805. {
  806. // Log_Verbose( "plD_pixel_wxwidgets" );
  807. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  808. if( !(dev->ready) )
  809. install_buffer( pls );
  810. dev->PutPixel( x, y );
  811. if( !(dev->resizing) && dev->ownGUI ) {
  812. dev->comcount++;
  813. if( dev->comcount>MAX_COMCOUNT ) {
  814. wxRunApp( pls, true );
  815. dev->comcount=0;
  816. }
  817. }
  818. }
  819. /*----------------------------------------------------------------------*\
  820. * static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  821. *
  822. * callback function, of type "plD_pixel_fp", which specifies how a single
  823. * pixel is set in the current colour.
  824. \*----------------------------------------------------------------------*/
  825. static void plD_set_pixel_wxwidgets( PLStream *pls, short x, short y, PLINT colour)
  826. {
  827. // Log_Verbose( "plD_set_pixel_wxwidgets" );
  828. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  829. if( !(dev->ready) )
  830. install_buffer( pls );
  831. dev->PutPixel( x, y, colour );
  832. if( !(dev->resizing) && dev->ownGUI ) {
  833. dev->comcount++;
  834. if( dev->comcount>MAX_COMCOUNT ) {
  835. wxRunApp( pls, true );
  836. dev->comcount=0;
  837. }
  838. }
  839. }
  840. /*--------------------------------------------------------------------------*\
  841. * void plD_read_pixel_wxwidgets (PLStream *pls, short x, short y)
  842. *
  843. * callback function, of type "plD_pixel_fp", which specifies how a single
  844. * pixel is read.
  845. \*--------------------------------------------------------------------------*/
  846. static PLINT plD_read_pixel_wxwidgets ( PLStream *pls, short x, short y )
  847. {
  848. // Log_Verbose( "plD_read_pixel_wxwidgets" );
  849. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  850. if( !(dev->ready) )
  851. install_buffer( pls );
  852. return dev->GetPixel( x, y );
  853. }
  854. /*----------------------------------------------------------------------*\
  855. * void init_freetype_lv1 (PLStream *pls)
  856. *
  857. * "level 1" initialisation of the freetype library.
  858. * "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
  859. * memory to the pls->FT structure, then sets up the pixel callback
  860. * function.
  861. \*----------------------------------------------------------------------*/
  862. static void init_freetype_lv1( PLStream *pls )
  863. {
  864. // Log_Verbose( "init_freetype_lv1" );
  865. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  866. plD_FreeType_init( pls );
  867. FT_Data *FT=(FT_Data *)pls->FT;
  868. FT->pixel = (plD_pixel_fp)plD_pixel_wxwidgets;
  869. /*
  870. * See if we have a 24 bit device (or better), in which case
  871. * we can use the better antialising.
  872. */
  873. // the bitmap we are using in the antialized case has always
  874. // 32 bit depth
  875. FT->BLENDED_ANTIALIASING=1;
  876. FT->read_pixel= (plD_read_pixel_fp)plD_read_pixel_wxwidgets;
  877. FT->set_pixel= (plD_set_pixel_fp)plD_set_pixel_wxwidgets;
  878. }
  879. /*----------------------------------------------------------------------*\
  880. * void init_freetype_lv2 (PLStream *pls)
  881. *
  882. * "Level 2" initialisation of the freetype library.
  883. * "Level 2" fills in a few setting that aren't public until after the
  884. * graphics sub-syetm has been initialised.
  885. * The "level 2" initialisation fills in a few things that are defined
  886. * later in the initialisation process for the GD driver.
  887. *
  888. * FT->scale is a scaling factor to convert co-ordinates. This is used by
  889. * the GD and other drivers to scale back a larger virtual page and this
  890. * eliminate the "hidden line removal bug". Set it to 1 if your device
  891. * doesn't have scaling.
  892. *
  893. * Some coordinate systems have zero on the bottom, others have zero on
  894. * the top. Freetype does it one way, and most everything else does it the
  895. * other. To make sure everything is working ok, we have to "flip" the
  896. * coordinates, and to do this we need to know how big in the Y dimension
  897. * the page is, and whether we have to invert the page or leave it alone.
  898. *
  899. * FT->ymax specifies the size of the page FT->invert_y=1 tells us to
  900. * invert the y-coordinates, FT->invert_y=0 will not invert the
  901. * coordinates.
  902. \*----------------------------------------------------------------------*/
  903. static void init_freetype_lv2( PLStream *pls )
  904. {
  905. // Log_Verbose( "init_freetype_lv2" );
  906. wxPLDevBase *dev=(wxPLDevBase *)pls->dev;
  907. FT_Data *FT=(FT_Data *)pls->FT;
  908. FT->scalex=dev->scalex;
  909. FT->scaley=dev->scaley;
  910. FT->ymax=dev->height;
  911. FT->invert_y=1;
  912. FT->smooth_text=0;
  913. if ((FT->want_smooth_text==1)&&(FT->BLENDED_ANTIALIASING==0)) /* do we want to at least *try* for smoothing ? */
  914. {
  915. FT->ncol0_org=pls->ncol0; /* save a copy of the original size of ncol0 */
  916. FT->ncol0_xtra=16777216-(pls->ncol1+pls->ncol0); /* work out how many free slots we have */
  917. FT->ncol0_width=FT->ncol0_xtra/(pls->ncol0-1); /* find out how many different shades of anti-aliasing we can do */
  918. if (FT->ncol0_width>4) /* are there enough colour slots free for text smoothing ? */
  919. {
  920. if (FT->ncol0_width>max_number_of_grey_levels_used_in_text_smoothing)
  921. FT->ncol0_width=max_number_of_grey_levels_used_in_text_smoothing; /* set a maximum number of shades */
  922. plscmap0n(FT->ncol0_org+(FT->ncol0_width*pls->ncol0)); /* redefine the size of cmap0 */
  923. /* the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
  924. * call in plscmap0 which (a) leads to segfaults since the GD image is
  925. * not defined at this point and (b) would be inefficient in any case since
  926. * setcmap is always called later (see plD_bop_png) to update the driver
  927. * color palette to be consistent with cmap0. */
  928. {
  929. PLINT level_save;
  930. level_save = pls->level;
  931. pls->level = 0;
  932. pl_set_extended_cmap0(pls, FT->ncol0_width, FT->ncol0_org); /* call the function to add the extra cmap0 entries and calculate stuff */
  933. pls->level = level_save;
  934. }
  935. FT->smooth_text=1; /* Yippee ! We had success setting up the extended cmap0 */
  936. }
  937. else
  938. plwarn("Insufficient colour slots available in CMAP0 to do text smoothing.");
  939. } else if ((FT->want_smooth_text==1)&&(FT->BLENDED_ANTIALIASING==1)) /* If we have a truecolour device, we wont even bother trying to change the palette */
  940. {
  941. FT->smooth_text=1;
  942. }
  943. }
  944. #endif
  945. /*--------------------------------------------------------------------------
  946. * GetCursorCmd()
  947. *
  948. * Waits for a graphics input event and returns coordinates.
  949. *--------------------------------------------------------------------------*/
  950. static void GetCursorCmd( PLStream* pls, PLGraphicsIn* ptr)
  951. {
  952. // Log_Verbose( "GetCursorCmd" );
  953. wxPLDevBase *dev=(wxPLDevBase *)pls->dev;
  954. PLGraphicsIn *gin = &(dev->gin);
  955. /* Initialize */
  956. plGinInit( gin );
  957. dev->locate_mode = LOCATE_INVOKED_VIA_API;
  958. dev->draw_xhair=true;
  959. /* Run event loop until a point is selected */
  960. wxRunApp( pls, false );
  961. *ptr = *gin;
  962. if( dev->locate_mode ) {
  963. dev->locate_mode = 0;
  964. dev->draw_xhair=false;
  965. }
  966. }
  967. /*----------------------------------------------------------------------
  968. * This part includes wxWidgets specific functions, which allow to
  969. * open a window from the command line, if needed.
  970. *----------------------------------------------------------------------*/
  971. /*----------------------------------------------------------------------
  972. * void install_buffer( PLStream *pls )
  973. *
  974. * If this driver is called from a command line executable (and not
  975. * from within a wxWidgets program), this function prepares a DC and a
  976. * bitmap to plot into.
  977. *----------------------------------------------------------------------*/
  978. static void install_buffer( PLStream *pls )
  979. {
  980. // Log_Verbose( "install_buffer" );
  981. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  982. static bool initApp=false;
  983. if( !initApp ) {
  984. /* this hack enables to have a GUI on Mac OSX even if the
  985. program was called from the command line (and isn't a bundle) */
  986. #ifdef __WXMAC__
  987. ProcessSerialNumber psn;
  988. GetCurrentProcess( &psn );
  989. CPSEnableForegroundOperation( &psn );
  990. SetFrontProcess( &psn );
  991. #endif
  992. /* initialize wxWidgets */
  993. wxInitialize();
  994. wxLog::GetActiveTarget();
  995. wxTRY {
  996. wxPLGetApp().CallOnInit();
  997. }
  998. wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); fprintf(stderr, "Can't init wxWidgets!\n"); exit(0); )
  999. initApp=true;
  1000. }
  1001. wxString title=wxT("wxWidgets PLplot App");
  1002. switch(dev->backend) {
  1003. case wxBACKEND_DC:
  1004. title += wxT(" (basic)");
  1005. break;
  1006. case wxBACKEND_GC:
  1007. title += wxT(" (wxGC)");
  1008. break;
  1009. case wxBACKEND_AGG:
  1010. title += wxT(" (AGG)");
  1011. break;
  1012. default:
  1013. break;
  1014. }
  1015. dev->m_frame = new wxPLplotFrame( title, pls );
  1016. wxPLGetApp().AddFrame( dev->m_frame );
  1017. /* set size and position of window */
  1018. dev->m_frame->SetClientSize( dev->width, dev->height );
  1019. if( dev->xpos!=0 || dev->ypos!=0)
  1020. dev->m_frame->SetSize( dev->xpos, dev->ypos,
  1021. wxDefaultCoord, wxDefaultCoord,
  1022. wxSIZE_USE_EXISTING );
  1023. if( dev->showGUI ) {
  1024. dev->m_frame->Show( true );
  1025. dev->m_frame->Raise();
  1026. }
  1027. else
  1028. dev->m_frame->Show( false );
  1029. /* get a DC and a bitmap or an imagebuffer */
  1030. dev->ownGUI = true;
  1031. dev->bm_width=dev->width;
  1032. dev->bm_height=dev->height;
  1033. dev->CreateCanvas();
  1034. dev->ready = true;
  1035. /* Set wx error handler for various errors in plplot*/
  1036. plsexit( plD_errorexithandler_wxwidgets );
  1037. plsabort( plD_erroraborthandler_wxwidgets );
  1038. /* replay command we may have missed */
  1039. plD_bop_wxwidgets( pls );
  1040. }
  1041. /*----------------------------------------------------------------------
  1042. * void wxRunApp( PLStream *pls, bool runonce )
  1043. *
  1044. * This is a hacked wxEntry-function, so that wxUninitialize is not
  1045. * called twice. Here we actually start the wxApplication.
  1046. *----------------------------------------------------------------------*/
  1047. static void wxRunApp( PLStream *pls, bool runonce )
  1048. {
  1049. // Log_Verbose( "wxRunApp" );
  1050. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  1051. dev->waiting=true;
  1052. wxTRY
  1053. {
  1054. class CallOnExit
  1055. {
  1056. public:
  1057. /* only call OnExit if exit is true (i.e. due an exception) */
  1058. ~CallOnExit() { if(exit) wxPLGetApp().OnExit(); }
  1059. bool exit;
  1060. } callOnExit;
  1061. callOnExit.exit=true;
  1062. wxPLGetApp().SetAdvanceFlag( runonce );
  1063. wxPLGetApp().SetRefreshFlag();
  1064. /* add an idle event is necessary for Linux (wxGTK2)
  1065. but not for Windows, but it doesn't harm */
  1066. wxIdleEvent event;
  1067. wxPLGetApp().AddPendingEvent( event );
  1068. wxPLGetApp().OnRun(); /* start wxWidgets application */
  1069. callOnExit.exit=false;
  1070. }
  1071. wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); fprintf(stderr, "Problem running wxWidgets!\n"); exit(0); )
  1072. if( dev->exit ) {
  1073. wxPLGetApp().OnExit();
  1074. plexit("");
  1075. }
  1076. dev->waiting=false;
  1077. }