PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/v5_9_5_debian/drivers/wxwidgets.cpp

#
C++ | 1320 lines | 754 code | 230 blank | 336 comment | 112 complexity | b6b2360c4a7031ee3d4bed2a880f12be 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 10360 2009-09-01 06:47:01Z 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. plexit( "Insufficient memory" );
  307. }
  308. pls->dev = (void*)dev;
  309. /* be verbose and write out debug messages */
  310. #ifdef _DEBUG
  311. pls->verbose = 1;
  312. pls->debug = 1;
  313. #else
  314. pls->verbose = 0;
  315. pls->debug = 0;
  316. #endif
  317. pls->color = 1; /* Is a color device */
  318. pls->dev_flush = 1; /* Handles flushes */
  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->dev_flush = 0; /* No need for flushes */
  462. pls->termin = 0; /* file oriented device */
  463. 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) */
  464. pls->page = 0;
  465. dev->showGUI = false;
  466. dev->bitmapType = wxBITMAP_TYPE_PNG;
  467. }
  468. #endif /* PLD_wxpng */
  469. /*--------------------------------------------------------------------------
  470. * void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a,
  471. * short x2a, short y2a )
  472. *
  473. * Draws a line from (x1a, y1a) to (x2a, y2a).
  474. *--------------------------------------------------------------------------*/
  475. void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
  476. {
  477. // Log_Verbose( "plD_line_wxwidgets(x1a=%d, y1a=%d, x2a=%d, y2a=%d)", x1a, y1a, x2a, y2a );
  478. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  479. if( !(dev->ready) )
  480. install_buffer( pls );
  481. dev->DrawLine( x1a, y1a, x2a, y2a );
  482. if( !(dev->resizing) && dev->ownGUI ) {
  483. dev->comcount++;
  484. if( dev->comcount>MAX_COMCOUNT ) {
  485. wxRunApp( pls, true );
  486. dev->comcount=0;
  487. }
  488. }
  489. }
  490. /*--------------------------------------------------------------------------
  491. * void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya,
  492. * PLINT npts )
  493. *
  494. * Draw a poly line - points are in xa and ya arrays.
  495. *--------------------------------------------------------------------------*/
  496. void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya, PLINT npts )
  497. {
  498. // Log_Verbose( "plD_polyline_wxwidgets()" );
  499. /* should be changed to use the wxDC::DrawLines function? */
  500. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  501. if( !(dev->ready) )
  502. install_buffer( pls );
  503. dev->DrawPolyline( xa, ya, npts );
  504. if( !(dev->resizing) && dev->ownGUI ) {
  505. dev->comcount++;
  506. if( dev->comcount>MAX_COMCOUNT ) {
  507. wxRunApp( pls, true );
  508. dev->comcount=0;
  509. }
  510. }
  511. }
  512. /*--------------------------------------------------------------------------
  513. * void plD_eop_wxwidgets( PLStream *pls )
  514. *
  515. * End of Page. This function is called if a "end of page" is send by the
  516. * user. This command is ignored if we have the plot embedded in a
  517. * wxWidgets application, otherwise the application created by the device
  518. * takes over.
  519. *--------------------------------------------------------------------------*/
  520. void plD_eop_wxwidgets( PLStream *pls )
  521. {
  522. // Log_Verbose( "plD_eop_wxwidgets()" );
  523. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  524. if( dev->bitmapType ) {
  525. wxMemoryDC memDC;
  526. wxBitmap bitmap( dev->width, dev->height, -1 );
  527. memDC.SelectObject( bitmap );
  528. dev->BlitRectangle( &memDC, 0, 0, dev->width, dev->height );
  529. wxImage buffer=bitmap.ConvertToImage();
  530. wxFFileOutputStream fstream( pls->OutFile );
  531. if(!(buffer.SaveFile( fstream, dev->bitmapType )))
  532. puts("Troubles saving file!");
  533. memDC.SelectObject( wxNullBitmap );
  534. }
  535. if( dev->ownGUI )
  536. if ( pls->nopause || !dev->showGUI )
  537. wxRunApp( pls, true );
  538. else
  539. wxRunApp( pls );
  540. }
  541. /*--------------------------------------------------------------------------
  542. * void plD_bop_wxwidgets( PLStream *pls )
  543. *
  544. * Begin of page. Before any plot command, this function is called, If we
  545. * have already a dc the background is cleared in background color and some
  546. * state calls are resent - this is because at the first call of this
  547. * function, a dc does most likely not exist, but state calls are recorded
  548. * and when a new dc is created this function is called again.
  549. *--------------------------------------------------------------------------*/
  550. void plD_bop_wxwidgets( PLStream *pls )
  551. {
  552. // Log_Verbose( "plD_bop_wxwidgets()" );
  553. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  554. if( dev->ready ) {
  555. /*if( pls->termin==0 ) {
  556. plGetFam( pls );*/
  557. /* force new file if pls->family set for all subsequent calls to plGetFam
  558. n.b. putting this after plGetFam call is important since plinit calls
  559. bop, and you don't want the familying sequence started until after
  560. that first call to bop.*/
  561. /* n.b. pls->dev can change because of an indirect call to plD_init_png
  562. from plGetFam if familying is enabled. Thus, wait to define dev until
  563. now. */
  564. /*dev = (wxPLDevBase*)pls->dev;
  565. pls->famadv = 1;
  566. pls->page++;
  567. }*/
  568. /* clear background */
  569. PLINT bgr, bgg, bgb; /* red, green, blue */
  570. plgcolbg( &bgr, &bgg, &bgb); /* get background color information */
  571. dev->ClearBackground( bgr, bgg, bgb );
  572. /* Replay escape calls that come in before PLESC_DEVINIT. All of them
  573. * required a DC that didn't exist yet.
  574. */
  575. if( dev->plstate_width )
  576. plD_state_wxwidgets( pls, PLSTATE_WIDTH );
  577. dev->plstate_width = false;
  578. if( dev->plstate_color0 )
  579. plD_state_wxwidgets( pls, PLSTATE_COLOR0 );
  580. dev->plstate_color0 = false;
  581. if( dev->plstate_color1 )
  582. plD_state_wxwidgets( pls, PLSTATE_COLOR1 );
  583. dev->plstate_color1 = false;
  584. /* why this? xwin driver has this */
  585. /* pls->page++; */
  586. }
  587. }
  588. /*--------------------------------------------------------------------------
  589. * void plD_tidy_wxwidgets( PLStream *pls )
  590. *
  591. * This function is called, if all plots are done.
  592. *--------------------------------------------------------------------------*/
  593. void plD_tidy_wxwidgets( PLStream *pls )
  594. {
  595. // Log_Verbose( "plD_tidy_wxwidgets()" );
  596. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  597. #ifdef HAVE_FREETYPE
  598. if( dev->freetype ) {
  599. FT_Data *FT=(FT_Data *)pls->FT;
  600. plscmap0n( FT->ncol0_org );
  601. plD_FreeType_Destroy( pls );
  602. }
  603. #endif
  604. if( dev->ownGUI ) {
  605. wxPLGetApp().RemoveFrame( dev->m_frame );
  606. if( !wxPLGetApp().FrameCount() )
  607. wxUninitialize();
  608. }
  609. delete dev;
  610. pls->dev=NULL; /* since in plcore.c pls->dev is free_mem'd */
  611. }
  612. /*--------------------------------------------------------------------------*\
  613. * void plD_state_wxwidgets( PLStream *pls, PLINT op )
  614. *
  615. * Handler for several state codes. Here we take care of setting the width
  616. * and color of the pen.
  617. \*--------------------------------------------------------------------------*/
  618. void plD_state_wxwidgets( PLStream *pls, PLINT op )
  619. {
  620. // Log_Verbose( "plD_state_wxwidgets(op=%d)", op );
  621. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  622. switch( op ) {
  623. case PLSTATE_WIDTH: /* 1 */
  624. if( dev->ready )
  625. dev->SetWidth( pls );
  626. else
  627. dev->plstate_width = true;
  628. break;
  629. case PLSTATE_COLOR0: /* 2 */
  630. if( dev->ready )
  631. dev->SetColor0( pls );
  632. else
  633. dev->plstate_color0 = true;
  634. break;
  635. case PLSTATE_COLOR1: /* 3 */
  636. if( dev->ready )
  637. dev->SetColor1( pls );
  638. else
  639. dev->plstate_color1 = true;
  640. break;
  641. default:
  642. if( !(dev->ready) )
  643. install_buffer( pls );
  644. }
  645. }
  646. /*--------------------------------------------------------------------------*\
  647. * void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
  648. *
  649. * Handler for several escape codes. Here we take care of filled polygons,
  650. * XOR or copy mode, initialize device (install dc from outside), and if
  651. * there is freetype support, rerendering of text.
  652. \*--------------------------------------------------------------------------*/
  653. void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
  654. {
  655. // Log_Verbose( "plD_esc_wxwidgets(op=%d, ptr=%x)", op, ptr );
  656. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  657. switch (op) {
  658. case PLESC_FILL:
  659. fill_polygon( pls );
  660. break;
  661. case PLESC_XORMOD:
  662. /* switch between wxXOR and wxCOPY */
  663. /* if( dev->ready ) {
  664. if( dev->m_dc->GetLogicalFunction() == wxCOPY )
  665. dev->m_dc->SetLogicalFunction( wxXOR );
  666. else if( dev->m_dc->GetLogicalFunction() == wxXOR )
  667. dev->m_dc->SetLogicalFunction( wxCOPY );
  668. } */
  669. break;
  670. case PLESC_DEVINIT:
  671. dev->SetExternalBuffer( ptr );
  672. /* replay begin of page call and state settings */
  673. plD_bop_wxwidgets( pls );
  674. break;
  675. case PLESC_HAS_TEXT:
  676. if( !(dev->ready) )
  677. install_buffer( pls );
  678. if( dev->freetype ) {
  679. #ifdef HAVE_FREETYPE
  680. plD_render_freetype_text( pls, (EscText *)ptr );
  681. #endif
  682. } else
  683. dev->ProcessString( pls, (EscText *)ptr );
  684. break;
  685. case PLESC_RESIZE:
  686. {
  687. wxSize* size=(wxSize*)ptr;
  688. wx_set_size( pls, size->GetWidth(), size->GetHeight() );
  689. }
  690. break;
  691. case PLESC_CLEAR:
  692. if( !(dev->ready) )
  693. install_buffer( pls );
  694. /* Since the plot is updated only every MAX_COMCOUNT commands (usually 5000)
  695. before we clear the screen we need to show the plot at least once :) */
  696. if( !(dev->resizing) && dev->ownGUI ) {
  697. wxRunApp( pls, true );
  698. dev->comcount=0;
  699. }
  700. dev->ClearBackground( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b,
  701. pls->sppxmi, pls->sppymi, pls->sppxma, pls->sppyma );
  702. break;
  703. case PLESC_FLUSH: /* forced update of the window */
  704. if( !(dev->resizing) && dev->ownGUI ) {
  705. wxRunApp( pls, true );
  706. dev->comcount=0;
  707. }
  708. break;
  709. case PLESC_GETC:
  710. if( dev->ownGUI )
  711. GetCursorCmd( pls, (PLGraphicsIn *) ptr );
  712. break;
  713. case PLESC_GETBACKEND:
  714. *((int*)ptr) = dev->backend;
  715. break;
  716. default:
  717. break;
  718. }
  719. }
  720. /*--------------------------------------------------------------------------*\
  721. * static void fill_polygon( PLStream *pls )
  722. *
  723. * Fill polygon described in points pls->dev_x[] and pls->dev_y[].
  724. \*--------------------------------------------------------------------------*/
  725. static void fill_polygon( PLStream *pls )
  726. {
  727. // Log_Verbose( "fill_polygon(), npts=%d, x[0]=%d, y[0]=%d", pls->dev_npts, pls->dev_y[0], pls->dev_y[0] );
  728. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  729. if( !(dev->ready) )
  730. install_buffer( pls );
  731. dev->FillPolygon( pls );
  732. if( !(dev->resizing) && dev->ownGUI ) {
  733. dev->comcount+=10;
  734. if( dev->comcount>MAX_COMCOUNT ) {
  735. wxRunApp( pls, true );
  736. dev->comcount=0;
  737. }
  738. }
  739. }
  740. /*--------------------------------------------------------------------------*\
  741. * void wx_set_size( PLStream* pls, int width, int height )
  742. *
  743. * Adds a dc to the stream. The associated device is attached to the canvas
  744. * as the property "dev".
  745. \*--------------------------------------------------------------------------*/
  746. void wx_set_size( PLStream* pls, int width, int height )
  747. {
  748. /* TODO: buffer must be resized here or in wxplotstream */
  749. // Log_Verbose( "wx_set_size()" );
  750. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  751. /* set new size and scale parameters */
  752. dev->width = width;
  753. dev->height = height;
  754. dev->scalex=(PLFLT)(dev->xmax-dev->xmin)/dev->width;
  755. dev->scaley=(PLFLT)(dev->ymax-dev->ymin)/dev->height;
  756. /* recalculate the dpi used in calculation of fontsize */
  757. pls->xdpi = VIRTUAL_PIXELS_PER_IN/dev->scalex;
  758. pls->ydpi = VIRTUAL_PIXELS_PER_IN/dev->scaley;
  759. /* clear background if we have a dc, since it's invalid (TODO: why, since in bop
  760. it must be cleared anyway?) */
  761. if( dev->ready ) {
  762. PLINT bgr, bgg, bgb; /* red, green, blue */
  763. plgcolbg( &bgr, &bgg, &bgb); /* get background color information */
  764. dev->CreateCanvas();
  765. dev->ClearBackground( bgr, bgg, bgb );
  766. }
  767. /* freetype parameters must also be changed */
  768. #ifdef HAVE_FREETYPE
  769. if( dev->freetype ) {
  770. FT_Data *FT=(FT_Data *)pls->FT;
  771. FT->scalex=dev->scalex;
  772. FT->scaley=dev->scaley;
  773. FT->ymax=dev->height;
  774. }
  775. #endif
  776. }
  777. /*----------------------------------------------------------------------
  778. * int plD_errorexithandler_wxwidgets( const char *errormessage )
  779. *
  780. * If an PLplot error occurs, this function shows a dialog regarding
  781. * this error and than exits.
  782. *----------------------------------------------------------------------*/
  783. int plD_errorexithandler_wxwidgets( const char *errormessage )
  784. {
  785. if( errormessage[0] ) {
  786. wxMessageDialog dialog( 0, wxString(errormessage, *wxConvCurrent),wxString("wxWidgets PLplot App error",*wxConvCurrent),wxOK|wxICON_ERROR );
  787. dialog.ShowModal();
  788. }
  789. return 0;
  790. }
  791. /*----------------------------------------------------------------------
  792. * void plD_erroraborthandler_wxwidgets( const char *errormessage )
  793. *
  794. * If PLplot aborts, this function shows a dialog regarding
  795. * this error.
  796. *----------------------------------------------------------------------*/
  797. void plD_erroraborthandler_wxwidgets( const char *errormessage )
  798. {
  799. if( errormessage[0] ) {
  800. wxMessageDialog dialog( 0,(wxString(errormessage, *wxConvCurrent)+wxString(" aborting operation...", *wxConvCurrent)), wxString("wxWidgets PLplot App abort",*wxConvCurrent), wxOK|wxICON_ERROR );
  801. dialog.ShowModal();
  802. }
  803. }
  804. #ifdef HAVE_FREETYPE
  805. /*----------------------------------------------------------------------*\
  806. * static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  807. *
  808. * callback function, of type "plD_pixel_fp", which specifies how a single
  809. * pixel is set in the current colour.
  810. \*----------------------------------------------------------------------*/
  811. static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  812. {
  813. // Log_Verbose( "plD_pixel_wxwidgets" );
  814. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  815. if( !(dev->ready) )
  816. install_buffer( pls );
  817. dev->PutPixel( x, y );
  818. if( !(dev->resizing) && dev->ownGUI ) {
  819. dev->comcount++;
  820. if( dev->comcount>MAX_COMCOUNT ) {
  821. wxRunApp( pls, true );
  822. dev->comcount=0;
  823. }
  824. }
  825. }
  826. /*----------------------------------------------------------------------*\
  827. * static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  828. *
  829. * callback function, of type "plD_pixel_fp", which specifies how a single
  830. * pixel is set in the current colour.
  831. \*----------------------------------------------------------------------*/
  832. static void plD_set_pixel_wxwidgets( PLStream *pls, short x, short y, PLINT colour)
  833. {
  834. // Log_Verbose( "plD_set_pixel_wxwidgets" );
  835. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  836. if( !(dev->ready) )
  837. install_buffer( pls );
  838. dev->PutPixel( x, y, colour );
  839. if( !(dev->resizing) && dev->ownGUI ) {
  840. dev->comcount++;
  841. if( dev->comcount>MAX_COMCOUNT ) {
  842. wxRunApp( pls, true );
  843. dev->comcount=0;
  844. }
  845. }
  846. }
  847. /*--------------------------------------------------------------------------*\
  848. * void plD_read_pixel_wxwidgets (PLStream *pls, short x, short y)
  849. *
  850. * callback function, of type "plD_pixel_fp", which specifies how a single
  851. * pixel is read.
  852. \*--------------------------------------------------------------------------*/
  853. static PLINT plD_read_pixel_wxwidgets ( PLStream *pls, short x, short y )
  854. {
  855. // Log_Verbose( "plD_read_pixel_wxwidgets" );
  856. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  857. if( !(dev->ready) )
  858. install_buffer( pls );
  859. return dev->GetPixel( x, y );
  860. }
  861. /*----------------------------------------------------------------------*\
  862. * void init_freetype_lv1 (PLStream *pls)
  863. *
  864. * "level 1" initialisation of the freetype library.
  865. * "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
  866. * memory to the pls->FT structure, then sets up the pixel callback
  867. * function.
  868. \*----------------------------------------------------------------------*/
  869. static void init_freetype_lv1( PLStream *pls )
  870. {
  871. // Log_Verbose( "init_freetype_lv1" );
  872. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  873. plD_FreeType_init( pls );
  874. FT_Data *FT=(FT_Data *)pls->FT;
  875. FT->pixel = (plD_pixel_fp)plD_pixel_wxwidgets;
  876. /*
  877. * See if we have a 24 bit device (or better), in which case
  878. * we can use the better antialising.
  879. */
  880. // the bitmap we are using in the antialized case has always
  881. // 32 bit depth
  882. FT->BLENDED_ANTIALIASING=1;
  883. FT->read_pixel= (plD_read_pixel_fp)plD_read_pixel_wxwidgets;
  884. FT->set_pixel= (plD_set_pixel_fp)plD_set_pixel_wxwidgets;
  885. }
  886. /*----------------------------------------------------------------------*\
  887. * void init_freetype_lv2 (PLStream *pls)
  888. *
  889. * "Level 2" initialisation of the freetype library.
  890. * "Level 2" fills in a few setting that aren't public until after the
  891. * graphics sub-syetm has been initialised.
  892. * The "level 2" initialisation fills in a few things that are defined
  893. * later in the initialisation process for the GD driver.
  894. *
  895. * FT->scale is a scaling factor to convert co-ordinates. This is used by
  896. * the GD and other drivers to scale back a larger virtual page and this
  897. * eliminate the "hidden line removal bug". Set it to 1 if your device
  898. * doesn't have scaling.
  899. *
  900. * Some coordinate systems have zero on the bottom, others have zero on
  901. * the top. Freetype does it one way, and most everything else does it the
  902. * other. To make sure everything is working ok, we have to "flip" the
  903. * coordinates, and to do this we need to know how big in the Y dimension
  904. * the page is, and whether we have to invert the page or leave it alone.
  905. *
  906. * FT->ymax specifies the size of the page FT->invert_y=1 tells us to
  907. * invert the y-coordinates, FT->invert_y=0 will not invert the
  908. * coordinates.
  909. \*----------------------------------------------------------------------*/
  910. static void init_freetype_lv2( PLStream *pls )
  911. {
  912. // Log_Verbose( "init_freetype_lv2" );
  913. wxPLDevBase *dev=(wxPLDevBase *)pls->dev;
  914. FT_Data *FT=(FT_Data *)pls->FT;
  915. FT->scalex=dev->scalex;
  916. FT->scaley=dev->scaley;
  917. FT->ymax=dev->height;
  918. FT->invert_y=1;
  919. FT->smooth_text=0;
  920. if ((FT->want_smooth_text==1)&&(FT->BLENDED_ANTIALIASING==0)) /* do we want to at least *try* for smoothing ? */
  921. {
  922. FT->ncol0_org=pls->ncol0; /* save a copy of the original size of ncol0 */
  923. FT->ncol0_xtra=16777216-(pls->ncol1+pls->ncol0); /* work out how many free slots we have */
  924. FT->ncol0_width=FT->ncol0_xtra/(pls->ncol0-1); /* find out how many different shades of anti-aliasing we can do */
  925. if (FT->ncol0_width>4) /* are there enough colour slots free for text smoothing ? */
  926. {
  927. if (FT->ncol0_width>max_number_of_grey_levels_used_in_text_smoothing)
  928. FT->ncol0_width=max_number_of_grey_levels_used_in_text_smoothing; /* set a maximum number of shades */
  929. plscmap0n(FT->ncol0_org+(FT->ncol0_width*pls->ncol0)); /* redefine the size of cmap0 */
  930. /* the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
  931. * call in plscmap0 which (a) leads to segfaults since the GD image is
  932. * not defined at this point and (b) would be inefficient in any case since
  933. * setcmap is always called later (see plD_bop_png) to update the driver
  934. * color palette to be consistent with cmap0. */
  935. {
  936. PLINT level_save;
  937. level_save = pls->level;
  938. pls->level = 0;
  939. pl_set_extended_cmap0(pls, FT->ncol0_width, FT->ncol0_org); /* call the function to add the extra cmap0 entries and calculate stuff */
  940. pls->level = level_save;
  941. }
  942. FT->smooth_text=1; /* Yippee ! We had success setting up the extended cmap0 */
  943. }
  944. else
  945. plwarn("Insufficient colour slots available in CMAP0 to do text smoothing.");
  946. } 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 */
  947. {
  948. FT->smooth_text=1;
  949. }
  950. }
  951. #endif
  952. /*--------------------------------------------------------------------------
  953. * GetCursorCmd()
  954. *
  955. * Waits for a graphics input event and returns coordinates.
  956. *--------------------------------------------------------------------------*/
  957. static void GetCursorCmd( PLStream* pls, PLGraphicsIn* ptr)
  958. {
  959. // Log_Verbose( "GetCursorCmd" );
  960. wxPLDevBase *dev=(wxPLDevBase *)pls->dev;
  961. PLGraphicsIn *gin = &(dev->gin);
  962. /* Initialize */
  963. plGinInit( gin );
  964. dev->locate_mode = LOCATE_INVOKED_VIA_API;
  965. dev->draw_xhair=true;
  966. /* Run event loop until a point is selected */
  967. wxRunApp( pls, false );
  968. *ptr = *gin;
  969. if( dev->locate_mode ) {
  970. dev->locate_mode = 0;
  971. dev->draw_xhair=false;
  972. }
  973. }
  974. /*----------------------------------------------------------------------
  975. * This part includes wxWidgets specific functions, which allow to
  976. * open a window from the command line, if needed.
  977. *----------------------------------------------------------------------*/
  978. /*----------------------------------------------------------------------
  979. * void install_buffer( PLStream *pls )
  980. *
  981. * If this driver is called from a command line executable (and not
  982. * from within a wxWidgets program), this function prepares a DC and a
  983. * bitmap to plot into.
  984. *----------------------------------------------------------------------*/
  985. static void install_buffer( PLStream *pls )
  986. {
  987. // Log_Verbose( "install_buffer" );
  988. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  989. static bool initApp=false;
  990. if( !initApp ) {
  991. /* this hack enables to have a GUI on Mac OSX even if the
  992. program was called from the command line (and isn't a bundle) */
  993. #ifdef __WXMAC__
  994. ProcessSerialNumber psn;
  995. GetCurrentProcess( &psn );
  996. CPSEnableForegroundOperation( &psn );
  997. SetFrontProcess( &psn );
  998. #endif
  999. /* initialize wxWidgets */
  1000. wxInitialize();
  1001. wxLog::GetActiveTarget();
  1002. wxTRY {
  1003. wxPLGetApp().CallOnInit();
  1004. }
  1005. wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); plexit( "Can't init wxWidgets!"); )
  1006. initApp=true;
  1007. }
  1008. wxString title=wxT("wxWidgets PLplot App");
  1009. switch(dev->backend) {
  1010. case wxBACKEND_DC:
  1011. title += wxT(" (basic)");
  1012. break;
  1013. case wxBACKEND_GC:
  1014. title += wxT(" (wxGC)");
  1015. break;
  1016. case wxBACKEND_AGG:
  1017. title += wxT(" (AGG)");
  1018. break;
  1019. default:
  1020. break;
  1021. }
  1022. dev->m_frame = new wxPLplotFrame( title, pls );
  1023. wxPLGetApp().AddFrame( dev->m_frame );
  1024. /* set size and position of window */
  1025. dev->m_frame->SetClientSize( dev->width, dev->height );
  1026. if( dev->xpos!=0 || dev->ypos!=0)
  1027. dev->m_frame->SetSize( dev->xpos, dev->ypos,
  1028. wxDefaultCoord, wxDefaultCoord,
  1029. wxSIZE_USE_EXISTING );
  1030. if( dev->showGUI ) {
  1031. dev->m_frame->Show( true );
  1032. dev->m_frame->Raise();
  1033. }
  1034. else
  1035. dev->m_frame->Show( false );
  1036. /* get a DC and a bitmap or an imagebuffer */
  1037. dev->ownGUI = true;
  1038. dev->bm_width=dev->width;
  1039. dev->bm_height=dev->height;
  1040. dev->CreateCanvas();
  1041. dev->ready = true;
  1042. /* Set wx error handler for various errors in plplot*/
  1043. plsexit( plD_errorexithandler_wxwidgets );
  1044. plsabort( plD_erroraborthandler_wxwidgets );
  1045. /* replay command we may have missed */
  1046. plD_bop_wxwidgets( pls );
  1047. }
  1048. /*----------------------------------------------------------------------
  1049. * void wxRunApp( PLStream *pls, bool runonce )
  1050. *
  1051. * This is a hacked wxEntry-function, so that wxUninitialize is not
  1052. * called twice. Here we actually start the wxApplication.
  1053. *----------------------------------------------------------------------*/
  1054. static void wxRunApp( PLStream *pls, bool runonce )
  1055. {
  1056. // Log_Verbose( "wxRunApp" );
  1057. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  1058. dev->waiting=true;
  1059. wxTRY
  1060. {
  1061. class CallOnExit
  1062. {
  1063. public:
  1064. /* only call OnExit if exit is true (i.e. due an exception) */
  1065. ~CallOnExit() { if(exit) wxPLGetApp().OnExit(); }
  1066. bool exit;
  1067. } callOnExit;
  1068. callOnExit.exit=true;
  1069. wxPLGetApp().SetAdvanceFlag( runonce );
  1070. wxPLGetApp().SetRefreshFlag();
  1071. /* add an idle event is necessary for Linux (wxGTK2)
  1072. but not for Windows, but it doesn't harm */
  1073. wxIdleEvent event;
  1074. wxPLGetApp().AddPendingEvent( event );
  1075. wxPLGetApp().OnRun(); /* start wxWidgets application */
  1076. callOnExit.exit=false;
  1077. }
  1078. wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); plexit("Problem running wxWidgets!"); )
  1079. if( dev->exit ) {
  1080. wxPLGetApp().OnExit();
  1081. plexit("");
  1082. }
  1083. dev->waiting=false;
  1084. }