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