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