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