PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/v5_9_8_debian/drivers/wxwidgets.cpp

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