No changes, just fix a typo in a comment in docview event handling code.
[wxWidgets.git] / src / common / utilscmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/utilscmn.cpp
3 // Purpose: Miscellaneous utility functions and classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 29/01/98
7 // Copyright: (c) 1998 Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/app.h"
28 #include "wx/string.h"
29 #include "wx/utils.h"
30 #include "wx/intl.h"
31 #include "wx/log.h"
32
33 #if wxUSE_GUI
34 #include "wx/window.h"
35 #include "wx/frame.h"
36 #include "wx/menu.h"
37 #include "wx/msgdlg.h"
38 #include "wx/textdlg.h"
39 #include "wx/textctrl.h" // for wxTE_PASSWORD
40 #if wxUSE_ACCEL
41 #include "wx/menuitem.h"
42 #include "wx/accel.h"
43 #endif // wxUSE_ACCEL
44 #endif // wxUSE_GUI
45 #endif // WX_PRECOMP
46
47 #include "wx/apptrait.h"
48
49 #include "wx/process.h"
50 #include "wx/txtstrm.h"
51 #include "wx/uri.h"
52 #include "wx/mimetype.h"
53 #include "wx/config.h"
54 #include "wx/versioninfo.h"
55
56 #if defined(__WXWINCE__) && wxUSE_DATETIME
57 #include "wx/datetime.h"
58 #endif
59
60 #include <ctype.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64
65 #if !wxONLY_WATCOM_EARLIER_THAN(1,4)
66 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
67 #include <errno.h>
68 #endif
69 #endif
70
71 #if wxUSE_GUI
72 #include "wx/notebook.h"
73 #include "wx/statusbr.h"
74 #endif // wxUSE_GUI
75
76 #ifndef __WXWINCE__
77 #include <time.h>
78 #else
79 #include "wx/msw/wince/time.h"
80 #endif
81
82 #ifdef __WXMAC__
83 #include "wx/osx/private.h"
84 #endif
85
86 #if !defined(__WXWINCE__)
87 #include <sys/types.h>
88 #include <sys/stat.h>
89 #endif
90
91 #if defined(__WINDOWS__)
92 #include "wx/msw/private.h"
93 #include "wx/filesys.h"
94 #endif
95
96 #if wxUSE_GUI && defined(__WXGTK__)
97 #include <gtk/gtk.h> // for GTK_XXX_VERSION constants
98 #endif
99
100 #if wxUSE_BASE
101
102 // ============================================================================
103 // implementation
104 // ============================================================================
105
106 // Array used in DecToHex conversion routine.
107 static const wxChar hexArray[] = wxT("0123456789ABCDEF");
108
109 // Convert 2-digit hex number to decimal
110 int wxHexToDec(const wxString& str)
111 {
112 char buf[2];
113 buf[0] = str.GetChar(0);
114 buf[1] = str.GetChar(1);
115 return wxHexToDec((const char*) buf);
116 }
117
118 // Convert decimal integer to 2-character hex string
119 void wxDecToHex(int dec, wxChar *buf)
120 {
121 int firstDigit = (int)(dec/16.0);
122 int secondDigit = (int)(dec - (firstDigit*16.0));
123 buf[0] = hexArray[firstDigit];
124 buf[1] = hexArray[secondDigit];
125 buf[2] = 0;
126 }
127
128 // Convert decimal integer to 2 characters
129 void wxDecToHex(int dec, char* ch1, char* ch2)
130 {
131 int firstDigit = (int)(dec/16.0);
132 int secondDigit = (int)(dec - (firstDigit*16.0));
133 (*ch1) = (char) hexArray[firstDigit];
134 (*ch2) = (char) hexArray[secondDigit];
135 }
136
137 // Convert decimal integer to 2-character hex string
138 wxString wxDecToHex(int dec)
139 {
140 wxChar buf[3];
141 wxDecToHex(dec, buf);
142 return wxString(buf);
143 }
144
145 // ----------------------------------------------------------------------------
146 // misc functions
147 // ----------------------------------------------------------------------------
148
149 // Return the current date/time
150 wxString wxNow()
151 {
152 #ifdef __WXWINCE__
153 #if wxUSE_DATETIME
154 wxDateTime now = wxDateTime::Now();
155 return now.Format();
156 #else
157 return wxEmptyString;
158 #endif
159 #else
160 time_t now = time(NULL);
161 char *date = ctime(&now);
162 date[24] = '\0';
163 return wxString::FromAscii(date);
164 #endif
165 }
166
167 #if WXWIN_COMPATIBILITY_2_8
168 void wxUsleep(unsigned long milliseconds)
169 {
170 wxMilliSleep(milliseconds);
171 }
172 #endif
173
174 const wxChar *wxGetInstallPrefix()
175 {
176 wxString prefix;
177
178 if ( wxGetEnv(wxT("WXPREFIX"), &prefix) )
179 return prefix.c_str();
180
181 #ifdef wxINSTALL_PREFIX
182 return wxT(wxINSTALL_PREFIX);
183 #else
184 return wxEmptyString;
185 #endif
186 }
187
188 wxString wxGetDataDir()
189 {
190 wxString dir = wxGetInstallPrefix();
191 dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx");
192 return dir;
193 }
194
195 bool wxIsPlatformLittleEndian()
196 {
197 // Are we little or big endian? This method is from Harbison & Steele.
198 union
199 {
200 long l;
201 char c[sizeof(long)];
202 } u;
203 u.l = 1;
204
205 return u.c[0] == 1;
206 }
207
208
209 // ----------------------------------------------------------------------------
210 // wxPlatform
211 // ----------------------------------------------------------------------------
212
213 /*
214 * Class to make it easier to specify platform-dependent values
215 */
216
217 wxArrayInt* wxPlatform::sm_customPlatforms = NULL;
218
219 void wxPlatform::Copy(const wxPlatform& platform)
220 {
221 m_longValue = platform.m_longValue;
222 m_doubleValue = platform.m_doubleValue;
223 m_stringValue = platform.m_stringValue;
224 }
225
226 wxPlatform wxPlatform::If(int platform, long value)
227 {
228 if (Is(platform))
229 return wxPlatform(value);
230 else
231 return wxPlatform();
232 }
233
234 wxPlatform wxPlatform::IfNot(int platform, long value)
235 {
236 if (!Is(platform))
237 return wxPlatform(value);
238 else
239 return wxPlatform();
240 }
241
242 wxPlatform& wxPlatform::ElseIf(int platform, long value)
243 {
244 if (Is(platform))
245 m_longValue = value;
246 return *this;
247 }
248
249 wxPlatform& wxPlatform::ElseIfNot(int platform, long value)
250 {
251 if (!Is(platform))
252 m_longValue = value;
253 return *this;
254 }
255
256 wxPlatform wxPlatform::If(int platform, double value)
257 {
258 if (Is(platform))
259 return wxPlatform(value);
260 else
261 return wxPlatform();
262 }
263
264 wxPlatform wxPlatform::IfNot(int platform, double value)
265 {
266 if (!Is(platform))
267 return wxPlatform(value);
268 else
269 return wxPlatform();
270 }
271
272 wxPlatform& wxPlatform::ElseIf(int platform, double value)
273 {
274 if (Is(platform))
275 m_doubleValue = value;
276 return *this;
277 }
278
279 wxPlatform& wxPlatform::ElseIfNot(int platform, double value)
280 {
281 if (!Is(platform))
282 m_doubleValue = value;
283 return *this;
284 }
285
286 wxPlatform wxPlatform::If(int platform, const wxString& value)
287 {
288 if (Is(platform))
289 return wxPlatform(value);
290 else
291 return wxPlatform();
292 }
293
294 wxPlatform wxPlatform::IfNot(int platform, const wxString& value)
295 {
296 if (!Is(platform))
297 return wxPlatform(value);
298 else
299 return wxPlatform();
300 }
301
302 wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value)
303 {
304 if (Is(platform))
305 m_stringValue = value;
306 return *this;
307 }
308
309 wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value)
310 {
311 if (!Is(platform))
312 m_stringValue = value;
313 return *this;
314 }
315
316 wxPlatform& wxPlatform::Else(long value)
317 {
318 m_longValue = value;
319 return *this;
320 }
321
322 wxPlatform& wxPlatform::Else(double value)
323 {
324 m_doubleValue = value;
325 return *this;
326 }
327
328 wxPlatform& wxPlatform::Else(const wxString& value)
329 {
330 m_stringValue = value;
331 return *this;
332 }
333
334 void wxPlatform::AddPlatform(int platform)
335 {
336 if (!sm_customPlatforms)
337 sm_customPlatforms = new wxArrayInt;
338 sm_customPlatforms->Add(platform);
339 }
340
341 void wxPlatform::ClearPlatforms()
342 {
343 wxDELETE(sm_customPlatforms);
344 }
345
346 /// Function for testing current platform
347
348 bool wxPlatform::Is(int platform)
349 {
350 #ifdef __WINDOWS__
351 if (platform == wxOS_WINDOWS)
352 return true;
353 #endif
354 #ifdef __WXWINCE__
355 if (platform == wxOS_WINDOWS_CE)
356 return true;
357 #endif
358
359 #if 0
360
361 // FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols
362
363 #if defined(__WXWINCE__) && defined(__POCKETPC__)
364 if (platform == wxWinPocketPC)
365 return true;
366 #endif
367 #if defined(__WXWINCE__) && defined(__SMARTPHONE__)
368 if (platform == wxWinSmartPhone)
369 return true;
370 #endif
371
372 #endif
373
374 #ifdef __WXGTK__
375 if (platform == wxPORT_GTK)
376 return true;
377 #endif
378 #ifdef __WXMAC__
379 if (platform == wxPORT_MAC)
380 return true;
381 #endif
382 #ifdef __WXX11__
383 if (platform == wxPORT_X11)
384 return true;
385 #endif
386 #ifdef __UNIX__
387 if (platform == wxOS_UNIX)
388 return true;
389 #endif
390 #ifdef __OS2__
391 if (platform == wxOS_OS2)
392 return true;
393 #endif
394 #ifdef __WXPM__
395 if (platform == wxPORT_PM)
396 return true;
397 #endif
398 #ifdef __WXCOCOA__
399 if (platform == wxPORT_MAC)
400 return true;
401 #endif
402
403 if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND)
404 return true;
405
406 return false;
407 }
408
409 // ----------------------------------------------------------------------------
410 // network and user id functions
411 // ----------------------------------------------------------------------------
412
413 // Get Full RFC822 style email address
414 bool wxGetEmailAddress(wxChar *address, int maxSize)
415 {
416 wxString email = wxGetEmailAddress();
417 if ( !email )
418 return false;
419
420 wxStrlcpy(address, email.t_str(), maxSize);
421
422 return true;
423 }
424
425 wxString wxGetEmailAddress()
426 {
427 wxString email;
428
429 wxString host = wxGetFullHostName();
430 if ( !host.empty() )
431 {
432 wxString user = wxGetUserId();
433 if ( !user.empty() )
434 {
435 email << user << wxT('@') << host;
436 }
437 }
438
439 return email;
440 }
441
442 wxString wxGetUserId()
443 {
444 static const int maxLoginLen = 256; // FIXME arbitrary number
445
446 wxString buf;
447 bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen);
448
449 if ( !ok )
450 buf.Empty();
451
452 return buf;
453 }
454
455 wxString wxGetUserName()
456 {
457 static const int maxUserNameLen = 1024; // FIXME arbitrary number
458
459 wxString buf;
460 bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen);
461
462 if ( !ok )
463 buf.Empty();
464
465 return buf;
466 }
467
468 wxString wxGetHostName()
469 {
470 static const size_t hostnameSize = 257;
471
472 wxString buf;
473 bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
474
475 if ( !ok )
476 buf.Empty();
477
478 return buf;
479 }
480
481 wxString wxGetFullHostName()
482 {
483 static const size_t hostnameSize = 257;
484
485 wxString buf;
486 bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
487
488 if ( !ok )
489 buf.Empty();
490
491 return buf;
492 }
493
494 wxString wxGetHomeDir()
495 {
496 wxString home;
497 wxGetHomeDir(&home);
498
499 return home;
500 }
501
502 #if 0
503
504 wxString wxGetCurrentDir()
505 {
506 wxString dir;
507 size_t len = 1024;
508 bool ok;
509 do
510 {
511 ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL;
512 dir.UngetWriteBuf();
513
514 if ( !ok )
515 {
516 if ( errno != ERANGE )
517 {
518 wxLogSysError(wxT("Failed to get current directory"));
519
520 return wxEmptyString;
521 }
522 else
523 {
524 // buffer was too small, retry with a larger one
525 len *= 2;
526 }
527 }
528 //else: ok
529 } while ( !ok );
530
531 return dir;
532 }
533
534 #endif // 0
535
536 // ----------------------------------------------------------------------------
537 // Environment
538 // ----------------------------------------------------------------------------
539
540 #ifdef __WXOSX__
541 #if wxOSX_USE_COCOA_OR_CARBON
542 #include <crt_externs.h>
543 #endif
544 #endif
545
546 bool wxGetEnvMap(wxEnvVariableHashMap *map)
547 {
548 wxCHECK_MSG( map, false, wxS("output pointer can't be NULL") );
549
550 #if defined(__VISUALC__)
551 // This variable only exists to force the CRT to fill the wide char array,
552 // it might only have it in narrow char version until now as we use main()
553 // (and not _wmain()) as our entry point.
554 static wxChar* s_dummyEnvVar = _tgetenv(wxT("TEMP"));
555
556 wxChar **env = _tenviron;
557 #elif defined(__VMS)
558 // Now this routine wil give false for OpenVMS
559 // TODO : should we do something with logicals?
560 char **env=NULL;
561 #elif defined(__DARWIN__)
562 #if wxOSX_USE_COCOA_OR_CARBON
563 // Under Mac shared libraries don't have access to the global environ
564 // variable so use this Mac-specific function instead as advised by
565 // environ(7) under Darwin
566 char ***penv = _NSGetEnviron();
567 if ( !penv )
568 return false;
569 char **env = *penv;
570 #else
571 char **env=NULL;
572 // todo translate NSProcessInfo environment into map
573 #endif
574 #else // non-MSVC non-Mac
575 // Not sure if other compilers have _tenviron so use the (more standard)
576 // ANSI version only for them.
577
578 // Both POSIX and Single UNIX Specification say that this variable must
579 // exist but not that it must be declared anywhere and, indeed, it's not
580 // declared in several common systems (some BSDs, Solaris with native CC)
581 // so we (re)declare it ourselves to deal with these cases. However we do
582 // not do this under MSW where there can be DLL-related complications, i.e.
583 // the variable might be DLL-imported or not. Luckily we don't have to
584 // worry about this as all MSW compilers do seem to define it in their
585 // standard headers anyhow so we can just rely on already having the
586 // correct declaration. And if this turns out to be wrong, we can always
587 // add a configure test checking whether it is declared later.
588 #ifndef __WINDOWS__
589 extern char **environ;
590 #endif // !__WINDOWS__
591
592 char **env = environ;
593 #endif
594
595 if ( env )
596 {
597 wxString name,
598 value;
599 while ( *env )
600 {
601 const wxString var(*env);
602
603 name = var.BeforeFirst(wxS('='), &value);
604
605 (*map)[name] = value;
606
607 env++;
608 }
609
610 return true;
611 }
612
613 return false;
614 }
615
616 // ----------------------------------------------------------------------------
617 // wxExecute
618 // ----------------------------------------------------------------------------
619
620 // wxDoExecuteWithCapture() helper: reads an entire stream into one array if
621 // the stream is non-NULL (it doesn't do anything if it's NULL).
622 //
623 // returns true if ok, false if error
624 #if wxUSE_STREAMS
625 static bool ReadAll(wxInputStream *is, wxArrayString& output)
626 {
627 if ( !is )
628 return true;
629
630 // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
631 is->Reset();
632
633 wxTextInputStream tis(*is);
634
635 for ( ;; )
636 {
637 wxString line = tis.ReadLine();
638
639 // check for EOF before other errors as it's not really an error
640 if ( is->Eof() )
641 {
642 // add the last, possibly incomplete, line
643 if ( !line.empty() )
644 output.Add(line);
645 break;
646 }
647
648 // any other error is fatal
649 if ( !*is )
650 return false;
651
652 output.Add(line);
653 }
654
655 return true;
656 }
657 #endif // wxUSE_STREAMS
658
659 // this is a private function because it hasn't a clean interface: the first
660 // array is passed by reference, the second by pointer - instead we have 2
661 // public versions of wxExecute() below
662 static long wxDoExecuteWithCapture(const wxString& command,
663 wxArrayString& output,
664 wxArrayString* error,
665 int flags,
666 const wxExecuteEnv *env)
667 {
668 // create a wxProcess which will capture the output
669 wxProcess *process = new wxProcess;
670 process->Redirect();
671
672 long rc = wxExecute(command, wxEXEC_SYNC | flags, process, env);
673
674 #if wxUSE_STREAMS
675 // Notice that while -1 indicates an error exit code for us, a program
676 // exiting with this code could still have written something to its stdout
677 // and, especially, stderr, so we still need to read from them.
678 if ( !ReadAll(process->GetInputStream(), output) )
679 rc = -1;
680
681 if ( error )
682 {
683 if ( !ReadAll(process->GetErrorStream(), *error) )
684 rc = -1;
685 }
686 #else
687 wxUnusedVar(output);
688 wxUnusedVar(error);
689 #endif // wxUSE_STREAMS/!wxUSE_STREAMS
690
691 delete process;
692
693 return rc;
694 }
695
696 long wxExecute(const wxString& command, wxArrayString& output, int flags,
697 const wxExecuteEnv *env)
698 {
699 return wxDoExecuteWithCapture(command, output, NULL, flags, env);
700 }
701
702 long wxExecute(const wxString& command,
703 wxArrayString& output,
704 wxArrayString& error,
705 int flags,
706 const wxExecuteEnv *env)
707 {
708 return wxDoExecuteWithCapture(command, output, &error, flags, env);
709 }
710
711 // ----------------------------------------------------------------------------
712 // Id functions
713 // ----------------------------------------------------------------------------
714
715 // Id generation
716 static int wxCurrentId = 100;
717
718 int wxNewId()
719 {
720 // skip the part of IDs space that contains hard-coded values:
721 if (wxCurrentId == wxID_LOWEST)
722 wxCurrentId = wxID_HIGHEST + 1;
723
724 return wxCurrentId++;
725 }
726
727 int
728 wxGetCurrentId(void) { return wxCurrentId; }
729
730 void
731 wxRegisterId (int id)
732 {
733 if (id >= wxCurrentId)
734 wxCurrentId = id + 1;
735 }
736
737 // ----------------------------------------------------------------------------
738 // wxQsort, adapted by RR to allow user_data
739 // ----------------------------------------------------------------------------
740
741 /* This file is part of the GNU C Library.
742 Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
743
744 Douglas Schmidt kindly gave permission to relicence the
745 code under the wxWindows licence:
746
747 From: "Douglas C. Schmidt" <schmidt@dre.vanderbilt.edu>
748 To: Robert Roebling <robert.roebling@uni-ulm.de>
749 Subject: Re: qsort licence
750 Date: Mon, 23 Jul 2007 03:44:25 -0500
751 Sender: schmidt@dre.vanderbilt.edu
752 Message-Id: <20070723084426.64F511000A8@tango.dre.vanderbilt.edu>
753
754 Hi Robert,
755
756 > [...] I'm asking if you'd be willing to relicence your code
757 > under the wxWindows licence. [...]
758
759 That's fine with me [...]
760
761 Thanks,
762
763 Doug */
764
765
766 /* Byte-wise swap two items of size SIZE. */
767 #define SWAP(a, b, size) \
768 do \
769 { \
770 register size_t __size = (size); \
771 register char *__a = (a), *__b = (b); \
772 do \
773 { \
774 char __tmp = *__a; \
775 *__a++ = *__b; \
776 *__b++ = __tmp; \
777 } while (--__size > 0); \
778 } while (0)
779
780 /* Discontinue quicksort algorithm when partition gets below this size.
781 This particular magic number was chosen to work best on a Sun 4/260. */
782 #define MAX_THRESH 4
783
784 /* Stack node declarations used to store unfulfilled partition obligations. */
785 typedef struct
786 {
787 char *lo;
788 char *hi;
789 } stack_node;
790
791 /* The next 4 #defines implement a very fast in-line stack abstraction. */
792 #define STACK_SIZE (8 * sizeof(unsigned long int))
793 #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
794 #define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
795 #define STACK_NOT_EMPTY (stack < top)
796
797
798 /* Order size using quicksort. This implementation incorporates
799 four optimizations discussed in Sedgewick:
800
801 1. Non-recursive, using an explicit stack of pointer that store the
802 next array partition to sort. To save time, this maximum amount
803 of space required to store an array of MAX_INT is allocated on the
804 stack. Assuming a 32-bit integer, this needs only 32 *
805 sizeof(stack_node) == 136 bits. Pretty cheap, actually.
806
807 2. Chose the pivot element using a median-of-three decision tree.
808 This reduces the probability of selecting a bad pivot value and
809 eliminates certain extraneous comparisons.
810
811 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
812 insertion sort to order the MAX_THRESH items within each partition.
813 This is a big win, since insertion sort is faster for small, mostly
814 sorted array segments.
815
816 4. The larger of the two sub-partitions is always pushed onto the
817 stack first, with the algorithm then concentrating on the
818 smaller partition. This *guarantees* no more than log (n)
819 stack size is needed (actually O(1) in this case)! */
820
821 void wxQsort(void* pbase, size_t total_elems,
822 size_t size, wxSortCallback cmp, const void* user_data)
823 {
824 register char *base_ptr = (char *) pbase;
825 const size_t max_thresh = MAX_THRESH * size;
826
827 if (total_elems == 0)
828 /* Avoid lossage with unsigned arithmetic below. */
829 return;
830
831 if (total_elems > MAX_THRESH)
832 {
833 char *lo = base_ptr;
834 char *hi = &lo[size * (total_elems - 1)];
835 stack_node stack[STACK_SIZE];
836 stack_node *top = stack;
837
838 PUSH (NULL, NULL);
839
840 while (STACK_NOT_EMPTY)
841 {
842 char *left_ptr;
843 char *right_ptr;
844
845 /* Select median value from among LO, MID, and HI. Rearrange
846 LO and HI so the three values are sorted. This lowers the
847 probability of picking a pathological pivot value and
848 skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
849
850 char *mid = lo + size * ((hi - lo) / size >> 1);
851
852 if ((*cmp) ((void *) mid, (void *) lo, user_data) < 0)
853 SWAP (mid, lo, size);
854 if ((*cmp) ((void *) hi, (void *) mid, user_data) < 0)
855 SWAP (mid, hi, size);
856 else
857 goto jump_over;
858 if ((*cmp) ((void *) mid, (void *) lo, user_data) < 0)
859 SWAP (mid, lo, size);
860 jump_over:;
861 left_ptr = lo + size;
862 right_ptr = hi - size;
863
864 /* Here's the famous ``collapse the walls'' section of quicksort.
865 Gotta like those tight inner loops! They are the main reason
866 that this algorithm runs much faster than others. */
867 do
868 {
869 while ((*cmp) ((void *) left_ptr, (void *) mid, user_data) < 0)
870 left_ptr += size;
871
872 while ((*cmp) ((void *) mid, (void *) right_ptr, user_data) < 0)
873 right_ptr -= size;
874
875 if (left_ptr < right_ptr)
876 {
877 SWAP (left_ptr, right_ptr, size);
878 if (mid == left_ptr)
879 mid = right_ptr;
880 else if (mid == right_ptr)
881 mid = left_ptr;
882 left_ptr += size;
883 right_ptr -= size;
884 }
885 else if (left_ptr == right_ptr)
886 {
887 left_ptr += size;
888 right_ptr -= size;
889 break;
890 }
891 }
892 while (left_ptr <= right_ptr);
893
894 /* Set up pointers for next iteration. First determine whether
895 left and right partitions are below the threshold size. If so,
896 ignore one or both. Otherwise, push the larger partition's
897 bounds on the stack and continue sorting the smaller one. */
898
899 if ((size_t) (right_ptr - lo) <= max_thresh)
900 {
901 if ((size_t) (hi - left_ptr) <= max_thresh)
902 /* Ignore both small partitions. */
903 POP (lo, hi);
904 else
905 /* Ignore small left partition. */
906 lo = left_ptr;
907 }
908 else if ((size_t) (hi - left_ptr) <= max_thresh)
909 /* Ignore small right partition. */
910 hi = right_ptr;
911 else if ((right_ptr - lo) > (hi - left_ptr))
912 {
913 /* Push larger left partition indices. */
914 PUSH (lo, right_ptr);
915 lo = left_ptr;
916 }
917 else
918 {
919 /* Push larger right partition indices. */
920 PUSH (left_ptr, hi);
921 hi = right_ptr;
922 }
923 }
924 }
925
926 /* Once the BASE_PTR array is partially sorted by quicksort the rest
927 is completely sorted using insertion sort, since this is efficient
928 for partitions below MAX_THRESH size. BASE_PTR points to the beginning
929 of the array to sort, and END_PTR points at the very last element in
930 the array (*not* one beyond it!). */
931
932 {
933 char *const end_ptr = &base_ptr[size * (total_elems - 1)];
934 char *tmp_ptr = base_ptr;
935 char *thresh = base_ptr + max_thresh;
936 if ( thresh > end_ptr )
937 thresh = end_ptr;
938 register char *run_ptr;
939
940 /* Find smallest element in first threshold and place it at the
941 array's beginning. This is the smallest array element,
942 and the operation speeds up insertion sort's inner loop. */
943
944 for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
945 if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0)
946 tmp_ptr = run_ptr;
947
948 if (tmp_ptr != base_ptr)
949 SWAP (tmp_ptr, base_ptr, size);
950
951 /* Insertion sort, running from left-hand-side up to right-hand-side. */
952
953 run_ptr = base_ptr + size;
954 while ((run_ptr += size) <= end_ptr)
955 {
956 tmp_ptr = run_ptr - size;
957 while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0)
958 tmp_ptr -= size;
959
960 tmp_ptr += size;
961 if (tmp_ptr != run_ptr)
962 {
963 char *trav;
964
965 trav = run_ptr + size;
966 while (--trav >= run_ptr)
967 {
968 char c = *trav;
969 char *hi, *lo;
970
971 for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
972 *hi = *lo;
973 *hi = c;
974 }
975 }
976 }
977 }
978 }
979
980 #endif // wxUSE_BASE
981
982
983
984 // ============================================================================
985 // GUI-only functions from now on
986 // ============================================================================
987
988 #if wxUSE_GUI
989
990 // this function is only really implemented for X11-based ports, including GTK1
991 // (GTK2 sets detectable auto-repeat automatically anyhow)
992 #if !(defined(__WXX11__) || defined(__WXMOTIF__) || \
993 (defined(__WXGTK__) && !defined(__WXGTK20__)))
994 bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
995 {
996 return true;
997 }
998 #endif // !X11-based port
999
1000 // ----------------------------------------------------------------------------
1001 // Launch default browser
1002 // ----------------------------------------------------------------------------
1003
1004 #if defined(__WINDOWS__)
1005
1006 // implemented in a port-specific utils source file:
1007 bool wxDoLaunchDefaultBrowser(const wxString& url, const wxString& scheme, int flags);
1008
1009 #elif defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXCOCOA__) || \
1010 (defined(__WXOSX__) )
1011
1012 // implemented in a port-specific utils source file:
1013 bool wxDoLaunchDefaultBrowser(const wxString& url, int flags);
1014
1015 #else
1016
1017 // a "generic" implementation:
1018 bool wxDoLaunchDefaultBrowser(const wxString& url, int flags)
1019 {
1020 // on other platforms try to use mime types or wxExecute...
1021
1022 bool ok = false;
1023 wxString cmd;
1024
1025 #if wxUSE_MIMETYPE
1026 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(wxT("html"));
1027 if ( ft )
1028 {
1029 wxString mt;
1030 ft->GetMimeType(&mt);
1031
1032 ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
1033 delete ft;
1034 }
1035 #endif // wxUSE_MIMETYPE
1036
1037 if ( !ok || cmd.empty() )
1038 {
1039 // fallback to checking for the BROWSER environment variable
1040 if ( !wxGetEnv(wxT("BROWSER"), &cmd) || cmd.empty() )
1041 cmd << wxT(' ') << url;
1042 }
1043
1044 ok = ( !cmd.empty() && wxExecute(cmd) );
1045 if (ok)
1046 return ok;
1047
1048 // no file type for HTML extension
1049 wxLogError(_("No default application configured for HTML files."));
1050
1051 return false;
1052 }
1053 #endif
1054
1055 static bool DoLaunchDefaultBrowserHelper(const wxString& urlOrig, int flags)
1056 {
1057 // NOTE: we don't have to care about the wxBROWSER_NOBUSYCURSOR flag
1058 // as it was already handled by wxLaunchDefaultBrowser
1059
1060 wxUnusedVar(flags);
1061
1062 wxString url(urlOrig), scheme;
1063 wxURI uri(url);
1064
1065 // this check is useful to avoid that wxURI recognizes as scheme parts of
1066 // the filename, in case urlOrig is a local filename
1067 // (e.g. "C:\\test.txt" when parsed by wxURI reports a scheme == "C")
1068 bool hasValidScheme = uri.HasScheme() && uri.GetScheme().length() > 1;
1069
1070 #if defined(__WINDOWS__)
1071
1072 // NOTE: when testing wxMSW's wxLaunchDefaultBrowser all possible forms
1073 // of the URL/flags should be tested; e.g.:
1074 //
1075 // for (int i=0; i<2; i++)
1076 // {
1077 // // test arguments without a valid URL scheme:
1078 // wxLaunchDefaultBrowser("C:\\test.txt", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1079 // wxLaunchDefaultBrowser("wxwidgets.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1080 //
1081 // // test arguments with different valid schemes:
1082 // wxLaunchDefaultBrowser("file:/C%3A/test.txt", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1083 // wxLaunchDefaultBrowser("http://wxwidgets.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1084 // wxLaunchDefaultBrowser("mailto:user@host.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1085 // }
1086 // (assuming you have a C:\test.txt file)
1087
1088 if ( !hasValidScheme )
1089 {
1090 if (wxFileExists(urlOrig) || wxDirExists(urlOrig))
1091 {
1092 scheme = "file";
1093 // do not prepend the file scheme to the URL as ShellExecuteEx() doesn't like it
1094 }
1095 else
1096 {
1097 url.Prepend(wxS("http://"));
1098 scheme = "http";
1099 }
1100 }
1101 else if ( hasValidScheme )
1102 {
1103 scheme = uri.GetScheme();
1104
1105 if ( uri.GetScheme() == "file" )
1106 {
1107 // TODO: extract URLToFileName() to some always compiled in
1108 // function
1109 #if wxUSE_FILESYSTEM
1110 // ShellExecuteEx() doesn't like the "file" scheme when opening local files;
1111 // remove it
1112 url = wxFileSystem::URLToFileName(url).GetFullPath();
1113 #endif // wxUSE_FILESYSTEM
1114 }
1115 }
1116
1117 if (wxDoLaunchDefaultBrowser(url, scheme, flags))
1118 return true;
1119 //else: call wxLogSysError
1120 #else
1121 if ( !hasValidScheme )
1122 {
1123 // set the scheme of url to "http" or "file" if it does not have one
1124 if (wxFileExists(urlOrig) || wxDirExists(urlOrig))
1125 url.Prepend(wxS("file://"));
1126 else
1127 url.Prepend(wxS("http://"));
1128 }
1129
1130 if (wxDoLaunchDefaultBrowser(url, flags))
1131 return true;
1132 //else: call wxLogSysError
1133 #endif
1134
1135 wxLogSysError(_("Failed to open URL \"%s\" in default browser."),
1136 url.c_str());
1137
1138 return false;
1139 }
1140
1141 bool wxLaunchDefaultBrowser(const wxString& url, int flags)
1142 {
1143 // NOTE: as documented, "url" may be both a real well-formed URL
1144 // and a local file name
1145
1146 if ( flags & wxBROWSER_NOBUSYCURSOR )
1147 return DoLaunchDefaultBrowserHelper(url, flags);
1148
1149 wxBusyCursor bc;
1150 return DoLaunchDefaultBrowserHelper(url, flags);
1151 }
1152
1153 // ----------------------------------------------------------------------------
1154 // Menu accelerators related functions
1155 // ----------------------------------------------------------------------------
1156
1157 #if WXWIN_COMPATIBILITY_2_6
1158 wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out)
1159 {
1160 #if wxUSE_MENUS
1161 wxString s = wxMenuItem::GetLabelText(in);
1162 #else
1163 wxString str(in);
1164 wxString s = wxStripMenuCodes(str);
1165 #endif // wxUSE_MENUS
1166 if ( out )
1167 {
1168 // go smash their buffer if it's not big enough - I love char * params
1169 memcpy(out, s.c_str(), s.length() * sizeof(wxChar));
1170 }
1171 else
1172 {
1173 out = new wxChar[s.length() + 1];
1174 wxStrcpy(out, s.c_str());
1175 }
1176
1177 return out;
1178 }
1179 #endif
1180
1181 wxString wxStripMenuCodes(const wxString& in, int flags)
1182 {
1183 wxASSERT_MSG( flags, wxT("this is useless to call without any flags") );
1184
1185 wxString out;
1186
1187 size_t len = in.length();
1188 out.reserve(len);
1189
1190 for ( wxString::const_iterator it = in.begin(); it != in.end(); ++it )
1191 {
1192 wxChar ch = *it;
1193 if ( (flags & wxStrip_Mnemonics) && ch == wxT('&') )
1194 {
1195 // skip it, it is used to introduce the accel char (or to quote
1196 // itself in which case it should still be skipped): note that it
1197 // can't be the last character of the string
1198 if ( ++it == in.end() )
1199 {
1200 wxLogDebug(wxT("Invalid menu string '%s'"), in.c_str());
1201 }
1202 else
1203 {
1204 // use the next char instead
1205 ch = *it;
1206 }
1207 }
1208 else if ( (flags & wxStrip_Accel) && ch == wxT('\t') )
1209 {
1210 // everything after TAB is accel string, exit the loop
1211 break;
1212 }
1213
1214 out += ch;
1215 }
1216
1217 return out;
1218 }
1219
1220 // ----------------------------------------------------------------------------
1221 // Window search functions
1222 // ----------------------------------------------------------------------------
1223
1224 /*
1225 * If parent is non-NULL, look through children for a label or title
1226 * matching the specified string. If NULL, look through all top-level windows.
1227 *
1228 */
1229
1230 wxWindow *
1231 wxFindWindowByLabel (const wxString& title, wxWindow * parent)
1232 {
1233 return wxWindow::FindWindowByLabel( title, parent );
1234 }
1235
1236
1237 /*
1238 * If parent is non-NULL, look through children for a name
1239 * matching the specified string. If NULL, look through all top-level windows.
1240 *
1241 */
1242
1243 wxWindow *
1244 wxFindWindowByName (const wxString& name, wxWindow * parent)
1245 {
1246 return wxWindow::FindWindowByName( name, parent );
1247 }
1248
1249 // Returns menu item id or wxNOT_FOUND if none.
1250 int
1251 wxFindMenuItemId(wxFrame *frame,
1252 const wxString& menuString,
1253 const wxString& itemString)
1254 {
1255 #if wxUSE_MENUS
1256 wxMenuBar *menuBar = frame->GetMenuBar ();
1257 if ( menuBar )
1258 return menuBar->FindMenuItem (menuString, itemString);
1259 #else // !wxUSE_MENUS
1260 wxUnusedVar(frame);
1261 wxUnusedVar(menuString);
1262 wxUnusedVar(itemString);
1263 #endif // wxUSE_MENUS/!wxUSE_MENUS
1264
1265 return wxNOT_FOUND;
1266 }
1267
1268 // Try to find the deepest child that contains 'pt'.
1269 // We go backwards, to try to allow for controls that are spacially
1270 // within other controls, but are still siblings (e.g. buttons within
1271 // static boxes). Static boxes are likely to be created _before_ controls
1272 // that sit inside them.
1273 wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt)
1274 {
1275 if (!win->IsShown())
1276 return NULL;
1277
1278 // Hack for wxNotebook case: at least in wxGTK, all pages
1279 // claim to be shown, so we must only deal with the selected one.
1280 #if wxUSE_NOTEBOOK
1281 if (wxDynamicCast(win, wxNotebook))
1282 {
1283 wxNotebook* nb = (wxNotebook*) win;
1284 int sel = nb->GetSelection();
1285 if (sel >= 0)
1286 {
1287 wxWindow* child = nb->GetPage(sel);
1288 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1289 if (foundWin)
1290 return foundWin;
1291 }
1292 }
1293 #endif
1294
1295 wxWindowList::compatibility_iterator node = win->GetChildren().GetLast();
1296 while (node)
1297 {
1298 wxWindow* child = node->GetData();
1299 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1300 if (foundWin)
1301 return foundWin;
1302 node = node->GetPrevious();
1303 }
1304
1305 wxPoint pos = win->GetPosition();
1306 wxSize sz = win->GetSize();
1307 if ( !win->IsTopLevel() && win->GetParent() )
1308 {
1309 pos = win->GetParent()->ClientToScreen(pos);
1310 }
1311
1312 wxRect rect(pos, sz);
1313 if (rect.Contains(pt))
1314 return win;
1315
1316 return NULL;
1317 }
1318
1319 wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt)
1320 {
1321 // Go backwards through the list since windows
1322 // on top are likely to have been appended most
1323 // recently.
1324 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast();
1325 while (node)
1326 {
1327 wxWindow* win = node->GetData();
1328 wxWindow* found = wxFindWindowAtPoint(win, pt);
1329 if (found)
1330 return found;
1331 node = node->GetPrevious();
1332 }
1333 return NULL;
1334 }
1335
1336 // ----------------------------------------------------------------------------
1337 // GUI helpers
1338 // ----------------------------------------------------------------------------
1339
1340 /*
1341 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
1342 * since otherwise the generic code may be pulled in unnecessarily.
1343 */
1344
1345 #if wxUSE_MSGDLG
1346
1347 int wxMessageBox(const wxString& message, const wxString& caption, long style,
1348 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
1349 {
1350 // add the appropriate icon unless this was explicitly disabled by use of
1351 // wxICON_NONE
1352 if ( !(style & wxICON_NONE) && !(style & wxICON_MASK) )
1353 {
1354 style |= style & wxYES ? wxICON_QUESTION : wxICON_INFORMATION;
1355 }
1356
1357 wxMessageDialog dialog(parent, message, caption, style);
1358
1359 int ans = dialog.ShowModal();
1360 switch ( ans )
1361 {
1362 case wxID_OK:
1363 return wxOK;
1364 case wxID_YES:
1365 return wxYES;
1366 case wxID_NO:
1367 return wxNO;
1368 case wxID_CANCEL:
1369 return wxCANCEL;
1370 case wxID_HELP:
1371 return wxHELP;
1372 }
1373
1374 wxFAIL_MSG( wxT("unexpected return code from wxMessageDialog") );
1375
1376 return wxCANCEL;
1377 }
1378
1379 wxVersionInfo wxGetLibraryVersionInfo()
1380 {
1381 // don't translate these strings, they're for diagnostics purposes only
1382 wxString msg;
1383 msg.Printf(wxS("wxWidgets Library (%s port)\n")
1384 wxS("Version %d.%d.%d (Unicode: %s, debug level: %d),\n")
1385 wxS("compiled at %s %s\n\n")
1386 wxS("Runtime version of toolkit used is %d.%d.\n"),
1387 wxPlatformInfo::Get().GetPortIdName(),
1388 wxMAJOR_VERSION,
1389 wxMINOR_VERSION,
1390 wxRELEASE_NUMBER,
1391 #if wxUSE_UNICODE_UTF8
1392 "UTF-8",
1393 #elif wxUSE_UNICODE
1394 "wchar_t",
1395 #else
1396 "none",
1397 #endif
1398 wxDEBUG_LEVEL,
1399 __TDATE__,
1400 __TTIME__,
1401 wxPlatformInfo::Get().GetToolkitMajorVersion(),
1402 wxPlatformInfo::Get().GetToolkitMinorVersion()
1403 );
1404
1405 #ifdef __WXGTK__
1406 msg += wxString::Format("Compile-time GTK+ version is %d.%d.%d.\n",
1407 GTK_MAJOR_VERSION,
1408 GTK_MINOR_VERSION,
1409 GTK_MICRO_VERSION);
1410 #endif // __WXGTK__
1411
1412 return wxVersionInfo(wxS("wxWidgets"),
1413 wxMAJOR_VERSION,
1414 wxMINOR_VERSION,
1415 wxRELEASE_NUMBER,
1416 msg,
1417 wxS("Copyright (c) 1995-2011 wxWidgets team"));
1418 }
1419
1420 void wxInfoMessageBox(wxWindow* parent)
1421 {
1422 wxVersionInfo info = wxGetLibraryVersionInfo();
1423 wxString msg = info.ToString();
1424
1425 msg << wxS("\n") << info.GetCopyright();
1426
1427 wxMessageBox(msg, wxT("wxWidgets information"),
1428 wxICON_INFORMATION | wxOK,
1429 parent);
1430 }
1431
1432 #endif // wxUSE_MSGDLG
1433
1434 #if wxUSE_TEXTDLG
1435
1436 wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
1437 const wxString& defaultValue, wxWindow *parent,
1438 wxCoord x, wxCoord y, bool centre )
1439 {
1440 wxString str;
1441 long style = wxTextEntryDialogStyle;
1442
1443 if (centre)
1444 style |= wxCENTRE;
1445 else
1446 style &= ~wxCENTRE;
1447
1448 wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y));
1449
1450 if (dialog.ShowModal() == wxID_OK)
1451 {
1452 str = dialog.GetValue();
1453 }
1454
1455 return str;
1456 }
1457
1458 wxString wxGetPasswordFromUser(const wxString& message,
1459 const wxString& caption,
1460 const wxString& defaultValue,
1461 wxWindow *parent,
1462 wxCoord x, wxCoord y, bool centre )
1463 {
1464 wxString str;
1465 long style = wxTextEntryDialogStyle;
1466
1467 if (centre)
1468 style |= wxCENTRE;
1469 else
1470 style &= ~wxCENTRE;
1471
1472 wxPasswordEntryDialog dialog(parent, message, caption, defaultValue,
1473 style, wxPoint(x, y));
1474 if ( dialog.ShowModal() == wxID_OK )
1475 {
1476 str = dialog.GetValue();
1477 }
1478
1479 return str;
1480 }
1481
1482 #endif // wxUSE_TEXTDLG
1483
1484 // ----------------------------------------------------------------------------
1485 // wxSafeYield and supporting functions
1486 // ----------------------------------------------------------------------------
1487
1488 void wxEnableTopLevelWindows(bool enable)
1489 {
1490 wxWindowList::compatibility_iterator node;
1491 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1492 node->GetData()->Enable(enable);
1493 }
1494
1495 #if defined(__WXOSX__) && wxOSX_USE_COCOA
1496
1497 // defined in evtloop.mm
1498
1499 #else
1500
1501 wxWindowDisabler::wxWindowDisabler(bool disable)
1502 {
1503 m_disabled = disable;
1504 if ( disable )
1505 DoDisable();
1506 }
1507
1508 wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
1509 {
1510 m_disabled = true;
1511 DoDisable(winToSkip);
1512 }
1513
1514 void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
1515 {
1516 // remember the top level windows which were already disabled, so that we
1517 // don't reenable them later
1518 m_winDisabled = NULL;
1519
1520 wxWindowList::compatibility_iterator node;
1521 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1522 {
1523 wxWindow *winTop = node->GetData();
1524 if ( winTop == winToSkip )
1525 continue;
1526
1527 // we don't need to disable the hidden or already disabled windows
1528 if ( winTop->IsEnabled() && winTop->IsShown() )
1529 {
1530 winTop->Disable();
1531 }
1532 else
1533 {
1534 if ( !m_winDisabled )
1535 {
1536 m_winDisabled = new wxWindowList;
1537 }
1538
1539 m_winDisabled->Append(winTop);
1540 }
1541 }
1542 }
1543
1544 wxWindowDisabler::~wxWindowDisabler()
1545 {
1546 if ( !m_disabled )
1547 return;
1548
1549 wxWindowList::compatibility_iterator node;
1550 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1551 {
1552 wxWindow *winTop = node->GetData();
1553 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
1554 {
1555 winTop->Enable();
1556 }
1557 //else: had been already disabled, don't reenable
1558 }
1559
1560 delete m_winDisabled;
1561 }
1562
1563 #endif
1564
1565 // Yield to other apps/messages and disable user input to all windows except
1566 // the given one
1567 bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
1568 {
1569 wxWindowDisabler wd(win);
1570
1571 bool rc;
1572 if (onlyIfNeeded)
1573 rc = wxYieldIfNeeded();
1574 else
1575 rc = wxYield();
1576
1577 return rc;
1578 }
1579
1580 // ----------------------------------------------------------------------------
1581 // wxApp::Yield() wrappers for backwards compatibility
1582 // ----------------------------------------------------------------------------
1583
1584 bool wxYield()
1585 {
1586 return wxTheApp && wxTheApp->Yield();
1587 }
1588
1589 bool wxYieldIfNeeded()
1590 {
1591 return wxTheApp && wxTheApp->Yield(true);
1592 }
1593
1594 #endif // wxUSE_GUI