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