PLplot: wxwidgets.cpp Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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