1 // wxdemo.cpp
2 
3 // A sample wxWidgets application.
4 //
5 
6 /**************************************************************************
7  * Copyright (C) 2010, Codemist.                         A C Norman       *
8  *                                                                        *
bind_fingerprint()9  * Redistribution and use in source and binary forms, with or without     *
10  * modification, are permitted provided that the following conditions are *
11  * met:                                                                   *
12  *                                                                        *
13  *     * Redistributions of source code must retain the relevant          *
14  *       copyright notice, this list of conditions and the following      *
15  *       disclaimer.                                                      *
16  *     * Redistributions in binary form must reproduce the above          *
17  *       copyright notice, this list of conditions and the following      *
18  *       disclaimer in the documentation and/or other materials provided  *
19  *       with the distribution.                                           *
20  *                                                                        *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS    *
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT      *
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS      *
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE         *
25  * COPYRIGHT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   *
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,   *
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS  *
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR  *
30  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF     *
31  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
32  * DAMAGE.                                                                *
33  *************************************************************************/
34 
35 // $Id: wxdemo.cpp 5382 2020-08-08 07:53:42Z arthurcnorman $
36 
37 // This code is a small demonstration of what wxWidgets can do - but MOSTLY
38 // it is looking at the issues of placing characters precisely on the screen
39 // at various sizes.
40 //
41 // The expected output is a lilac screen.
42 // There is a sort of logo (taken from the wxWidgets documentation) at the
43 // top left. Then there are two large chunks of text which are notionally
44 // 1/3 and 2/3 of the way up the screen, and each underlined. They are
45 // positioned horizontally in a balanced way.
46 
47 // The upper "Welcome to wxWidgets" is on a thin red line and has its first
48 // for characters overprinted with red punctuation (to test and demonstrate
49 // overprinting). It was produced using a wxWidgets font directly and simply.
50 // The lower "Welcome" was generated by creating a 3-point font and setting
51 // wxWidgets to scale everything up by a large factor. One could fear that
52 // this would lead to blocky illegible characters, but it appears that on the
53 // platforms I have tested letter shapes are rendered at the size they are to
54 // be displayed. However on Windows and Linux the placement of every character
55 // will be forced to a whole number of pixels in the 3-point scale, and
56 // so in fact to a multiple of 12 pixels in the final display. This can mess
57 // with  inter-character spacing and hence how well the text is centred on
58 // the line. Observe the (green) underlining is thick because if has been
59 // scaled up. Also how the thick green line and the text do not end up
60 // aligned the same way relative to each other on different platforms.
61 //
62 // Then there are (up to) three double lines of small letters. Each has a row
63 // of "e" then a row of "m". The top one uses wxGraphicsContext where placement
64 // and the like can be specified using floating point. The middle one uses
65 // a 60-point font scaled down to 10 points using the ordinary facilities
66 // of wxDC. The lower one first renders characters onto bitmaps at high
67 // resolution then shrinks that and in doing so achieves a form of anti-
68 // aliasing and sub-pixel placement of characters, but at the cost of being
69 // slower and of having the rendering utterly unaware of the display's pixel
70 // layout (hence characters may tend to end up blurred somewhat).
71 
72 // This is what I observe on various platforms:
73 //
74 // (1) Windows: The top line using wxGraphicsContext can not be generated
75 //     without an ACN private extension to wxWidgets -- and so that strategy
76 //     will only be good if it ends up yielding a much better display
77 //     or running significantly faster than the other options. The issue
78 //     that causes delicacy is supporting custom application-specific fonts
79 //     with GdiPlus. I have also had some trouble with crashes when the
80 //     application terminates.
81 //     (a) The GraphicsContext characters are well-formed but both horizontal
82 //         and veritical character placement click to pixel positions on the
83 //         screen. The effect is that the row "mmmmm" shows a pair of letters
84 //         unduly close together every so often, and the changes in vertical
85 //         position have a stepped effect.
86 //     (b) The direct use of characters scaled down by wxWidgets in a normal
87 //         device context suffer similar spacing issues but also have much
88 //         less well-formed characters. In particular the cross-bar of the
89 //         letters "e" is perhaps rather thin and in pretty well every case
90 //         it ends up invisible. This is the worst of the three options.
91 //     (c) With my own anti-aliasing the characters end up lighter and perhaps
92 //         fuzzier than for (a), but when you step back the shapes and
93 //         placement are respectable.
94 // I do have an issue I need to note about antialiasing in this way. For some
95 // big delimiters I will be building up (eg) a huge "{" out of top and
96 // bottom hooks, a middle piece and some extension chunks. If I anti-alias
97 // the ends of the glyphs where they are expected to join and then write
98 // stuff to the output the result will be bad. So I may need to assemble
99 // the whole delimiter and anti-alias it as a single unit. There is perhaps
100 // a similar issue with rules.
101 //
102 // (2) X11: The notes here are based on a test using cygwin and X11. The
103 //     display shows (a) and (b) both with crisp well-formed characters,
104 //     but both with irregular spacing because of target-space quantization.
105 //     They do not slip pixels in the same place, but both suffer the same way.
106 //     The software anti-aliased version comes out noticably lighter on
107 //     the screen, but as before has good positioning.
108 //
109 // (3) Macintosh: Version (a) via a wxGraphicsWindow looks to me like good
110 //     horizontal character placement but steppy vertical positioning. Version
111 //     (b) with the simplest code looks identical (or at least very similar)
112 //     so again horizontally there is sub-pixel positioning but vertically
113 //     there is not. With my own anti-aliasing the characters are no worse
114 //     than on Windows or Linux, but are significantly less good than the
115 //     versions that the Mac can draw for itself. Another difference arises
116 //     because (I think) the Mac is probably thinking in terms of 72 dpi
117 //     and Windows in terms of 96 dpi. So when I ask for a "36 point" font
118 //     I end up with noticably different sizes. The issues of pixel counts,
119 //     default wxWidgets coordinate units and "point sizes" for fonts
120 //     seems to be a real can of worms. And the Macbook I am testing on has
121 //     a "retina" display so has more pixels to play with. which tends to
122 //     improve the appearance (by the application of brute force).
123 //     It is possible that my own anti-aliasing on the Mac is suffering
124 //     because with their higher resolution display I am not over-sampling
125 //     by anything like as large a factor as I had perhaps planned to?
126 //
127 
128 // Having looked at other images that I have rescaled (using method (a),
129 // i.e. a scaled wxGraphicsContext, I see some on-screen effects that are
130 // really rather bad when I try to render mathematics. Specifically when I
131 // draw a tall delimiter using multiple glyphs patched together at some
132 // scales the different parts of the tower can end up with their edges
133 // offset from each other horizontally by one pixel (I certainly see that
134 // using both Windows and X11). The effect is that what should be a vertical
135 // stroke that would be (say) 3 pixels wide ends up ragged and really noticably
136 // ugly.
137 
138 
139 #include "wxfwin.h"
140 
141 #include "wx/wxprec.h"
142 
143 #ifndef WX_PRECOMP
144 #include "wx/wx.h"
145 #endif
146 
147 #include "wx/dcgraph.h"
148 
149 #if !defined __WXMSW__ && !defined __WXPM__
150 #include "fwin.xpm" // Icon to use in non-Windows cases
151 #endif
152 
153 int main(int argc, const char *argv[])
154 {   find_program_directory(argv[0]);
155     add_custom_fonts();
156     display_font_information();
157     wxEntry(argc, (char **)argv);
158 }
159 
160 class wxDemo : public wxApp
161 {
162 public:
163     virtual bool OnInit();
164 };
165 
166 class DemoFrame : public wxFrame
167 {
168 public:
169     DemoFrame(const wxString& title);
170 
171     void OnQuit(wxCommandEvent& event);
172     void OnPaint(wxPaintEvent& event);
173 
174 private:
175     DECLARE_EVENT_TABLE()
176 };
177 
178 enum
179 {   ACN_Quit = wxID_EXIT,
180     ACN_About = wxID_ABOUT
181 };
182 
183 BEGIN_EVENT_TABLE(DemoFrame, wxFrame)
184     EVT_MENU(ACN_Quit,  DemoFrame::OnQuit)
185     EVT_PAINT(          DemoFrame::OnPaint)
186 END_EVENT_TABLE()
187 
188 
189 IMPLEMENT_APP_NO_MAIN(wxDemo)
190 
191 static wxFont *ff1 = nullptr;
192 static wxFont *ff2 = nullptr;
193 static wxFont *ff3 = nullptr;
194 
195 #define FONTSIZE1 36
196 #define FONTSIZE2  3
197 #define FONTSIZE3 60
198 
199 #define SCALE ((double)FONTSIZE1/(double)FONTSIZE2)
200 
201 #define WIDTH    600
202 #define HEIGHT   400
203 
204 bool wxDemo::OnInit()
205 {   ::wxInitAllImageHandlers();
206     wxFontInfo ffi;
207     ffi.FaceName("cslSTIXMath");
208     ff1 = new wxFont(ffi);
209     ff1->SetPointSize(FONTSIZE1);
210     ff2 = new wxFont(ffi);
211     ff2->SetPointSize(FONTSIZE2);
212     ff3 = new wxFont(ffi);
213     ff3->SetPointSize(FONTSIZE3);
214 #if defined WIN64
215 #define name "wxdemo (win64)"
216 #elif defined WIN32
217 #define name "wxdemo (win32)"
218 #elif defined __CYGWIN32__
219 #define name "wxdemo (32-bit cygwin)"
220 #elif defined __CYGWIN__
221 #define name "wxdemo (64-bit cygwin)"
222 #elif defined __linux__ && defined __amd64
223 #define name "wxdemo (64-bit linux)"
224 #elif defined __linux
225 #define name "wxdemo (linux)"
226 #elif defined __APPLE__
227 #define name "wxdemo (Macintosh)"
228 #elif defined unix
229 #define name "wxdemo (Unix)"
230 #else
231 #define name "wxdemo"
232 #endif
233     DemoFrame *frame = new DemoFrame(name);
234     frame->Show(true);
235     return true;
236 }
237 
238 DemoFrame::DemoFrame(const wxString& title)
239     : wxFrame(nullptr, wxID_ANY, title)
240 {   SetIcon(wxICON(fwin));
241 
242 // The size specified here is the size of the client area of the
243 // window, and so should lead to consistent (client area) visuals on
244 // all platforms. I make the window a fixed size...
245     wxSize winsize(WIDTH, HEIGHT);
246     SetClientSize(winsize);
247     SetMinClientSize(winsize);
248     SetMaxClientSize(winsize);
249     Centre();
250 }
251 
252 
253 void DemoFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
254 {   Close(true);
255 }
256 
257 void DemoFrame::OnPaint(wxPaintEvent& event)
258 {   wxPaintDC dc(this);
259 // This is a fairly simple test of wxWidgets, but I am now using it
260 // to illustrate the SetUserScale capability.
261     dc.SetUserScale(1.0,
262                     1.0);  // This should be how it starts off anyway.
263 // First draw a pale purple background for the window.
264     wxColour background_colour(230, 200, 255);
265     wxBrush background_brush(background_colour);
266     dc.SetBackground(background_brush);
267     dc.Clear();
268 
269     wxGraphicsContext *gc = wxGraphicsContext::Create(dc);
270     if (gc == nullptr)
271     {   wxPrintf("Unable to create Graphics Context\n");
272         return;
273     }
274 // make a path that contains a circle and some lines. This is from the
275 // wxWidgets documentation and helps confirm that the wxGraphicsContext
276 // is present and in order.
277     gc->SetPen( *wxRED_PEN );
278     wxGraphicsPath path = gc->CreatePath();
279     path.AddCircle( 50.0, 50.0, 50.0 );
280     path.MoveToPoint(0.0, 50.0);
281     path.AddLineToPoint(100.0, 50.0);
282     path.MoveToPoint(50.0, 0.0);
283     path.AddLineToPoint(50.0, 100.0 );
284     path.CloseSubpath();
285     path.AddRectangle(25.0, 25.0, 50.0, 50.0);
286     gc->StrokePath(path);
287 
288 
289     wxDouble dwidth=99.0, dheight=99.0, ddepth=99.0, dleading=99.0;
290     gc->SetFont(*ff3, *wxBLACK);
291     wxString letter_X(wxT("X"));
292     gc->GetTextExtent(letter_X, &dwidth, &dheight, &ddepth, &dleading);
293 // One thing that this reveals is that when I set a Scale in a Graphics
294 // Context the TextExtents show the size of the scaled item not of the
295 // original.
296     wxPrintf("Letter 'X' in GraphicsContext w=%.2f h=%.2f d=%.2f l=%.2f\n",
297              dwidth, dheight, ddepth, dleading);
298     std::fflush(stdout);
299 
300     dc.SetPen(*wxRED_PEN);
301     dc.DrawLine(0, HEIGHT/3, WIDTH, HEIGHT/3);
302 
303 // First I will use a 36-point font and draw some text with UserScale 1.0.
304 // I will draw it so that the font baseline is positioned at the horizontal
305 // line I just drew.
306     const char *msg = "Welcome to wxWidgets";
307 // Note that wxWidgets uses the top left hand corner of the text as its
308 // index point, while here I want the left hand side of the base-line. When I
309 // do GetTextExtent it produces a bounding box that will contain everything,
310 // and the reported "height" is the total height of that box. The "depth" is
311 // the distance from the bottom of the box to the baseline. So (h-d) is the
312 // amount I have to adjust by here to get the positioning I want.
313     dc.SetFont(*ff1);
314     wxCoord w, h, d, xl;
315     dc.GetTextExtent(msg, &w, &h, &d, &xl);
316     wxPrintf("Width if text measured as %d\n", w);
317     dc.DrawText(msg, (WIDTH - w)/2,
318                 HEIGHT/3 - (h-d));
319 // Now to investigate overprinting... What I THINK this shows is that the
320 // default behaviour is that the body of letters get written but the
321 // background is untouched. This is as per SetBackgroundMode(wxTRANSPARENT).
322     dc.SetTextForeground(*wxRED);
323 // Uncommenting these two lines causes bacground to letters to be filled with
324 // yellow... and by the fact it confirms that the default behaviour is
325 // to write letters with a transparent background.
326 //  dc.SetTextBackground(*wxYELLOW);
327 //  dc.SetBackgroundMode(wxSOLID);
328 // This overprints the first few characters of my message with some junk.
329     dc.DrawText(".. ++", (WIDTH - w)/2,
330                 HEIGHT/3 - (h-d));
331     dc.SetTextForeground(*wxBLACK);
332 
333 
334 //
335 // Now I will do something similar but using a 3-point font with a UserScale
336 // factor of 12.
337     dc.SetUserScale(SCALE, SCALE);
338 // A wxPen object has an integer size, with a default of 1. That leads to
339 // a reasonably delicate line when drawn at UserScale 1.0, but when I
340 // magnify - as here - it will lead to a line with is rather broad. The
341 // visual effect on the display helps to confirm that scaling has been in
342 // effect, and I can check for consistency across platforms.
343     dc.SetPen(*wxGREEN_PEN);
344     dc.DrawLine(0, static_cast<int>((2*HEIGHT)/(3*SCALE)),
345                 static_cast<int>(WIDTH/SCALE),
346                 static_cast<int>((2*HEIGHT)/(3*SCALE)));
347 
348     dc.SetFont(*ff2);
349 // GetTextExtents gives me a width based on the 3-point size of the font,
350 // which means it is a much smaller integer values than I had with the
351 // bigger font, and so quantization effects will be greater. Perhaps the
352 // more important message that emerges here is that GetTextExtents does
353 // not consuder UserScale when it returns its measurements - they come back
354 // as if the text was rendered at scale 1. In that case the width here comes
355 // out as a small number, and it LOOKS to me as if at least on some platforms
356 // character placement (eg moving things to a pixel boundary) leads to
357 // the width of the string overall not being scaled exactly linearly with font
358 // size. Specifically here I find that on Windows the width I get here
359 // does match the previous measure merely divided by the scale factor (and
360 // hence there is a truncation error that has an effect on placement) but
361 // with the X11 version I see a bigger discrepancy.
362 //
363 // The take-away mesage is that GetTextExtent only really works the way I
364 // might expect when UserScale is 1.0, and that text on the screen will
365 // not in general scale in width as neatly as one might hope when other
366 // scale factors are used. So characters should usually be placed one by
367 // one under full user control! Oh dear!! Well discovering things like
368 // this is what this code is for.
369     dc.GetTextExtent(msg, &w, &h, &d, &xl);
370     wxPrintf("Width of text when scaled = %.2f*%d = %.2f\n", SCALE, w,
371              w*SCALE);
372     std::fflush(stdout);
373     dc.DrawText(msg, (static_cast<int>(WIDTH/SCALE) - w)/2,
374                 static_cast<int>((2*HEIGHT)/(3*SCALE)) - (h-d));
375     dc.SetUserScale(1.0, 1.0);
376 
377 // Now I will draw a sequence is small characters across the middle of the
378 // screen using a large real font and using user-scaling that shrinks things
379 // severely so I get small items on-screen. Specifically I start with a font
380 // that is set up to be 60-point and scale it down to 10 point. The issue
381 // that I explore/demonstrate here is the cleanliness of display that results
382 // and whether sub-pixel character placement arises.
383 //
384 
385 
386     dc.SetFont(*ff3);
387     int ewidth, mwidth;
388     dc.SetUserScale(1.0/6.0, 1.0/6.0);
389     dc.SetPen(*wxCYAN_PEN);
390     dc.DrawLine(0, HEIGHT*6/2, WIDTH*6, HEIGHT*6/2);
391     dc.SetUserScale(1.0, 1.0);
392 
393     for (int y=0; y<10; y++)
394         for (int x=0; x<10; x++)
395         {   int x1, x2, y1, y2;
396 //=======================================================================
397 // First I draw the 60 point characters scaled down to 10 points using
398 // UserScale. This - as noted above leaves characters positioned at pixel
399 // boundaries on some platforms, and renders some characters badly when
400 // the font does not provide enough hinting information.
401 // On Windows this renders "eee" especially badly with the horizontal bar in
402 // the letters "e" often missing.
403 
404 // I measure "e" and "m" and space by characters an odd number of pixels
405 // in the high resolution space, so that on-screen they do not all fall
406 // at natural pixel boundaries. On Windows and Unix the characters as
407 // drawn are clicked back onto a pixel boundary leading to irregular
408 // horizontal spacing.
409             dc.GetTextExtent("e", &ewidth, &h, &d, &xl);
410             dc.GetTextExtent("m", &mwidth, &h, &d, &xl);
411             while (ewidth%2==0 || ewidth%3==0) ewidth++;
412             while (mwidth%2==0 || mwidth%3==0) mwidth++;
413 
414             dc.SetUserScale(1.0/6.0, 1.0/6.0);
415             dc.DrawText("e", x1=ewidth*(x+10*y), y1=HEIGHT*6/2-(h-d)+y);
416             dc.DrawText("m", x2=mwidth*(x+10*y), y1+60);
417             dc.SetUserScale(1.0, 1.0);
418 
419 //=======================================================================
420 // Next, and towards the top of the screen, I will use a wxGraphicsContext
421 // because there I can naturally use floating point positioning and scaling.
422 // Unexpectedly the use of Scale on the wxGraphicsContext and SetUserScale
423 // on the underlying wxDC interact, so I need to take care to use
424 // only one scaling at a time. On Windows and Unix both x and y coordinates
425 // click to pixel positions. On the mac the y coordinates do.
426 
427             gc->Scale(1.0/6.0, 1.0/6.0);
428             gc->DrawText(wxString("e"), x1, y2=y1-HEIGHT*6/3);
429             gc->DrawText(wxString("m"), x2, y2+60);
430             gc->Scale(6.0, 6.0);
431 
432 
433 //=======================================================================
434 //
435 // Now a more complicated scheme. I will explicitly draw onto a large
436 // bitmap then shrink it in a way that has an anti-aliasing effect. The
437 // result is liable to be not that sharp but (on at least some platforms) it
438 // may be fairer.
439 //
440 // I will want to have a bitmap that will be neatly aligned against the
441 // main grid when I print from it. I am coding this on the basis that my
442 // high resolution regime has 6 times the resolution of the low resolution
443 // one.
444             int x1a = 6*(x1/6);
445             int x2a = 6*(x2/6);
446             int y1a = 6*(y1/6);
447 // The size needs to be big enough for the largest character in my font. I
448 // am not worrying about that issue JUST yet...
449             wxBitmap bitmap(90, 120, 32);
450             wxMemoryDC memdc;
451             memdc.SelectObject(bitmap);
452             memdc.SetBackground(background_brush);
453             memdc.Clear();
454             memdc.SetFont(*ff3);
455 // I will write a black letter on a standard (well in my case lilac) background.
456             memdc.GetTextExtent(wxT("e"), &w, &h, &d, &xl);
457             memdc.DrawText(wxT("e"), x1-x1a, y1-y1a+60-(h-d));
458 // I believe I need to detach the bitmap from the Device Context before
459 // messing around further.
460             memdc.SelectObject(wxNullBitmap);
461             wxImage im = bitmap.ConvertToImage();
462 // Rescaling at "high quality" performs averaging over the pixels in the
463 // source. This gives an impression of more accurate positioning and character
464 // shape than the simple use of DrawText direct on the output - but the cost
465 // is that I lose hints and tend to end up with characters that have blurry
466 // edges. The original character was drawn as a black charecter on a white
467 // background, but it may have ended up with some multi-colour fringes where
468 // anti-aliasing believes it knows about LCD pixel layout. That is NOT
469 // useful here because I am about to scale the image. But a consequence
470 // can be that the resulting scaled image is also colourful. To avoid any
471 // confusion I will map onto grayscales here...
472             im.ConvertToGreyscale();
473 // Now I shrink the image to the size that characters should appear on the
474 // screen.
475             im.Rescale(15, 20, wxIMAGE_QUALITY_HIGH);
476 // This image now has black foreground and my standard background. I need to
477 // give it a mask so that background bits do not get displayed...
478             im.SetMaskColour(background_colour.Red(),
479                              background_colour.Green(),
480                              background_colour.Blue());
481             wxBitmap bm2(im);
482             dc.DrawBitmap(bm2, x1a/6, y1a/6+HEIGHT/3, true);
483 
484 
485 // Now basically the same stuff but without interleaved commentary, so you
486 // can see it is not THAT much code after all! But also so that I can see
487 // where it might be allocating fresh memory for each character it renders!
488 
489             memdc.SelectObject(bitmap);
490             memdc.SetBackground(background_brush);
491             memdc.Clear();
492             memdc.GetTextExtent(wxT("m"), &w, &h, &d, &xl);
493             memdc.DrawText(wxT("m"), x2-x2a, y1-y1a+60-(h-d));
494             memdc.SelectObject(wxNullBitmap);
495 // I wamt to have a single wxImage object here rather than creating a fresh
496 // one every time...
497             im = bitmap.ConvertToImage();
498 // I hope that the Grayscale convrsion is in-place.
499             im.ConvertToGreyscale();
500 // I am concerned that Rescale might allocate fresh memory.
501             im.Rescale(15, 20, wxIMAGE_QUALITY_HIGH);
502 // Space may be needed for the mask, and that has to be allocated at
503 // some stage.
504             im.SetMaskColour(background_colour.Red(),
505                              background_colour.Green(),
506                              background_colour.Blue());
507 // ... and that this new bitmap may also involve extra memory management.
508             wxBitmap bm3(im);
509             dc.DrawBitmap(bm3, x2a/6, y1a/6+HEIGHT/3+20, true);
510         }
511     delete gc;
512 }
513 
514 // A dummy definition that is needed because of wxfwin.cpp
515 
516 int windowed_worker(int argc, const char *argv[],
517                     fwin_entrypoint *fwin_main)
518 {   return 0;
519 }
520 
521 
522 // end of wxdemo.cpp
523 
524