]> git.saurik.com Git - wxWidgets.git/blob - src/common/utilscmn.cpp
document On{Open,Save}Document()
[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 wxCFRef< CFURLRef > curl( CFURLCreateWithString( kCFAllocatorDefault,
1059 wxCFStringRef( url ), NULL ) );
1060 OSStatus err = LSOpenCFURLRef( curl , NULL );
1061
1062 if (err == noErr)
1063 {
1064 return true;
1065 }
1066 else
1067 {
1068 wxLogDebug(wxT("Browser Launch error %d"), (int) err);
1069 return false;
1070 }
1071 #else
1072 // (non-Mac, non-MSW)
1073
1074 #ifdef __UNIX__
1075
1076 // Our best best is to use xdg-open from freedesktop.org cross-desktop
1077 // compatibility suite xdg-utils
1078 // (see http://portland.freedesktop.org/wiki/) -- this is installed on
1079 // most modern distributions and may be tweaked by them to handle
1080 // distribution specifics. Only if that fails, try to find the right
1081 // browser ourselves.
1082 wxString path, xdg_open;
1083 if ( wxGetEnv("PATH", &path) &&
1084 wxFindFileInPath(&xdg_open, path, "xdg-open") )
1085 {
1086 if ( wxExecute(xdg_open + " " + url) )
1087 return true;
1088 }
1089
1090 wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment();
1091
1092 // GNOME and KDE desktops have some applications which should be always installed
1093 // together with their main parts, which give us the
1094 if (desktop == wxT("GNOME"))
1095 {
1096 wxArrayString errors;
1097 wxArrayString output;
1098
1099 // gconf will tell us the path of the application to use as browser
1100 long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"),
1101 output, errors, wxEXEC_NODISABLE );
1102 if (res >= 0 && errors.GetCount() == 0)
1103 {
1104 wxString cmd = output[0];
1105 cmd << _T(' ') << url;
1106 if (wxExecute(cmd))
1107 return true;
1108 }
1109 }
1110 else if (desktop == wxT("KDE"))
1111 {
1112 // kfmclient directly opens the given URL
1113 if (wxExecute(wxT("kfmclient openURL ") + url))
1114 return true;
1115 }
1116 #endif
1117
1118 bool ok = false;
1119 wxString cmd;
1120
1121 #if wxUSE_MIMETYPE
1122 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html"));
1123 if ( ft )
1124 {
1125 wxString mt;
1126 ft->GetMimeType(&mt);
1127
1128 ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
1129 delete ft;
1130 }
1131 #endif // wxUSE_MIMETYPE
1132
1133 if ( !ok || cmd.empty() )
1134 {
1135 // fallback to checking for the BROWSER environment variable
1136 cmd = wxGetenv(wxT("BROWSER"));
1137 if ( !cmd.empty() )
1138 cmd << _T(' ') << url;
1139 }
1140
1141 ok = ( !cmd.empty() && wxExecute(cmd) );
1142 if (ok)
1143 return ok;
1144
1145 // no file type for HTML extension
1146 wxLogError(_("No default application configured for HTML files."));
1147
1148 #endif // !wxUSE_MIMETYPE && !__WXMSW__
1149
1150 wxLogSysError(_("Failed to open URL \"%s\" in default browser."),
1151 url.c_str());
1152
1153 return false;
1154 }
1155
1156 // ----------------------------------------------------------------------------
1157 // Menu accelerators related functions
1158 // ----------------------------------------------------------------------------
1159
1160 wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out)
1161 {
1162 #if wxUSE_MENUS
1163 wxString s = wxMenuItem::GetLabelText(in);
1164 #else
1165 wxString str(in);
1166 wxString s = wxStripMenuCodes(str);
1167 #endif // wxUSE_MENUS
1168 if ( out )
1169 {
1170 // go smash their buffer if it's not big enough - I love char * params
1171 memcpy(out, s.c_str(), s.length() * sizeof(wxChar));
1172 }
1173 else
1174 {
1175 out = new wxChar[s.length() + 1];
1176 wxStrcpy(out, s.c_str());
1177 }
1178
1179 return out;
1180 }
1181
1182 wxString wxStripMenuCodes(const wxString& in, int flags)
1183 {
1184 wxASSERT_MSG( flags, _T("this is useless to call without any flags") );
1185
1186 wxString out;
1187
1188 size_t len = in.length();
1189 out.reserve(len);
1190
1191 for ( size_t n = 0; n < len; n++ )
1192 {
1193 wxChar ch = in[n];
1194 if ( (flags & wxStrip_Mnemonics) && ch == _T('&') )
1195 {
1196 // skip it, it is used to introduce the accel char (or to quote
1197 // itself in which case it should still be skipped): note that it
1198 // can't be the last character of the string
1199 if ( ++n == len )
1200 {
1201 wxLogDebug(_T("Invalid menu string '%s'"), in.c_str());
1202 }
1203 else
1204 {
1205 // use the next char instead
1206 ch = in[n];
1207 }
1208 }
1209 else if ( (flags & wxStrip_Accel) && ch == _T('\t') )
1210 {
1211 // everything after TAB is accel string, exit the loop
1212 break;
1213 }
1214
1215 out += ch;
1216 }
1217
1218 return out;
1219 }
1220
1221 // ----------------------------------------------------------------------------
1222 // Window search functions
1223 // ----------------------------------------------------------------------------
1224
1225 /*
1226 * If parent is non-NULL, look through children for a label or title
1227 * matching the specified string. If NULL, look through all top-level windows.
1228 *
1229 */
1230
1231 wxWindow *
1232 wxFindWindowByLabel (const wxString& title, wxWindow * parent)
1233 {
1234 return wxWindow::FindWindowByLabel( title, parent );
1235 }
1236
1237
1238 /*
1239 * If parent is non-NULL, look through children for a name
1240 * matching the specified string. If NULL, look through all top-level windows.
1241 *
1242 */
1243
1244 wxWindow *
1245 wxFindWindowByName (const wxString& name, wxWindow * parent)
1246 {
1247 return wxWindow::FindWindowByName( name, parent );
1248 }
1249
1250 // Returns menu item id or wxNOT_FOUND if none.
1251 int
1252 wxFindMenuItemId(wxFrame *frame,
1253 const wxString& menuString,
1254 const wxString& itemString)
1255 {
1256 #if wxUSE_MENUS
1257 wxMenuBar *menuBar = frame->GetMenuBar ();
1258 if ( menuBar )
1259 return menuBar->FindMenuItem (menuString, itemString);
1260 #else // !wxUSE_MENUS
1261 wxUnusedVar(frame);
1262 wxUnusedVar(menuString);
1263 wxUnusedVar(itemString);
1264 #endif // wxUSE_MENUS/!wxUSE_MENUS
1265
1266 return wxNOT_FOUND;
1267 }
1268
1269 // Try to find the deepest child that contains 'pt'.
1270 // We go backwards, to try to allow for controls that are spacially
1271 // within other controls, but are still siblings (e.g. buttons within
1272 // static boxes). Static boxes are likely to be created _before_ controls
1273 // that sit inside them.
1274 wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt)
1275 {
1276 if (!win->IsShown())
1277 return NULL;
1278
1279 // Hack for wxNotebook case: at least in wxGTK, all pages
1280 // claim to be shown, so we must only deal with the selected one.
1281 #if wxUSE_NOTEBOOK
1282 if (win->IsKindOf(CLASSINFO(wxNotebook)))
1283 {
1284 wxNotebook* nb = (wxNotebook*) win;
1285 int sel = nb->GetSelection();
1286 if (sel >= 0)
1287 {
1288 wxWindow* child = nb->GetPage(sel);
1289 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1290 if (foundWin)
1291 return foundWin;
1292 }
1293 }
1294 #endif
1295
1296 wxWindowList::compatibility_iterator node = win->GetChildren().GetLast();
1297 while (node)
1298 {
1299 wxWindow* child = node->GetData();
1300 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1301 if (foundWin)
1302 return foundWin;
1303 node = node->GetPrevious();
1304 }
1305
1306 wxPoint pos = win->GetPosition();
1307 wxSize sz = win->GetSize();
1308 if ( !win->IsTopLevel() && win->GetParent() )
1309 {
1310 pos = win->GetParent()->ClientToScreen(pos);
1311 }
1312
1313 wxRect rect(pos, sz);
1314 if (rect.Contains(pt))
1315 return win;
1316
1317 return NULL;
1318 }
1319
1320 wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt)
1321 {
1322 // Go backwards through the list since windows
1323 // on top are likely to have been appended most
1324 // recently.
1325 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast();
1326 while (node)
1327 {
1328 wxWindow* win = node->GetData();
1329 wxWindow* found = wxFindWindowAtPoint(win, pt);
1330 if (found)
1331 return found;
1332 node = node->GetPrevious();
1333 }
1334 return NULL;
1335 }
1336
1337 // ----------------------------------------------------------------------------
1338 // GUI helpers
1339 // ----------------------------------------------------------------------------
1340
1341 /*
1342 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
1343 * since otherwise the generic code may be pulled in unnecessarily.
1344 */
1345
1346 #if wxUSE_MSGDLG
1347
1348 int wxMessageBox(const wxString& message, const wxString& caption, long style,
1349 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
1350 {
1351 long decorated_style = style;
1352
1353 if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 )
1354 {
1355 decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ;
1356 }
1357
1358 wxMessageDialog dialog(parent, message, caption, decorated_style);
1359
1360 int ans = dialog.ShowModal();
1361 switch ( ans )
1362 {
1363 case wxID_OK:
1364 return wxOK;
1365 case wxID_YES:
1366 return wxYES;
1367 case wxID_NO:
1368 return wxNO;
1369 case wxID_CANCEL:
1370 return wxCANCEL;
1371 }
1372
1373 wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") );
1374
1375 return wxCANCEL;
1376 }
1377
1378 void wxInfoMessageBox(wxWindow* parent)
1379 {
1380 // don't translate these strings, they're for diagnostics purposes only
1381 wxString msg;
1382 msg.Printf(_T("wxWidgets Library (%s port)\n")
1383 _T("Version %d.%d.%d%s%s, compiled at %s %s\n")
1384 _T("Runtime version of toolkit used is %d.%d.%s\n")
1385 _T("Copyright (c) 1995-2007 wxWidgets team"),
1386 wxPlatformInfo::Get().GetPortIdName().c_str(),
1387 wxMAJOR_VERSION,
1388 wxMINOR_VERSION,
1389 wxRELEASE_NUMBER,
1390 #if wxUSE_UNICODE
1391 L" (Unicode)",
1392 #else
1393 wxEmptyString,
1394 #endif
1395 #ifdef __WXDEBUG__
1396 _T(" Debug build"),
1397 #else
1398 wxEmptyString,
1399 #endif
1400 __TDATE__,
1401 __TTIME__,
1402 wxPlatformInfo::Get().GetToolkitMajorVersion(),
1403 wxPlatformInfo::Get().GetToolkitMinorVersion(),
1404 #ifdef __WXGTK__
1405 wxString::Format("\nThe compile-time GTK+ version is %d.%d.%d.",
1406 GTK_MAJOR_VERSION,
1407 GTK_MINOR_VERSION,
1408 GTK_MICRO_VERSION).c_str()
1409 #else
1410 wxEmptyString
1411 #endif
1412 );
1413 wxMessageBox(msg, _T("wxWidgets information"),
1414 wxICON_INFORMATION | wxOK,
1415 parent);
1416 }
1417
1418 #endif // wxUSE_MSGDLG
1419
1420 #if wxUSE_TEXTDLG
1421
1422 wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
1423 const wxString& defaultValue, wxWindow *parent,
1424 wxCoord x, wxCoord y, bool centre )
1425 {
1426 wxString str;
1427 long style = wxTextEntryDialogStyle;
1428
1429 if (centre)
1430 style |= wxCENTRE;
1431 else
1432 style &= ~wxCENTRE;
1433
1434 wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y));
1435
1436 if (dialog.ShowModal() == wxID_OK)
1437 {
1438 str = dialog.GetValue();
1439 }
1440
1441 return str;
1442 }
1443
1444 wxString wxGetPasswordFromUser(const wxString& message,
1445 const wxString& caption,
1446 const wxString& defaultValue,
1447 wxWindow *parent,
1448 wxCoord x, wxCoord y, bool centre )
1449 {
1450 wxString str;
1451 long style = wxTextEntryDialogStyle;
1452
1453 if (centre)
1454 style |= wxCENTRE;
1455 else
1456 style &= ~wxCENTRE;
1457
1458 wxPasswordEntryDialog dialog(parent, message, caption, defaultValue,
1459 style, wxPoint(x, y));
1460 if ( dialog.ShowModal() == wxID_OK )
1461 {
1462 str = dialog.GetValue();
1463 }
1464
1465 return str;
1466 }
1467
1468 #endif // wxUSE_TEXTDLG
1469
1470 #if wxUSE_COLOURDLG
1471
1472 wxColour wxGetColourFromUser(wxWindow *parent,
1473 const wxColour& colInit,
1474 const wxString& caption,
1475 wxColourData *ptrData)
1476 {
1477 // contains serialized representation of wxColourData used the last time
1478 // the dialog was shown: we want to reuse it the next time in order to show
1479 // the same custom colours to the user (and we can't just have static
1480 // wxColourData itself because it's a GUI object and so should be destroyed
1481 // before GUI shutdown and doing it during static cleanup is too late)
1482 static wxString s_strColourData;
1483
1484 wxColourData data;
1485 if ( !ptrData )
1486 {
1487 ptrData = &data;
1488 if ( !s_strColourData.empty() )
1489 {
1490 if ( !data.FromString(s_strColourData) )
1491 {
1492 wxFAIL_MSG( "bug in wxColourData::FromString()?" );
1493 }
1494
1495 #ifdef __WXMSW__
1496 // we don't get back the "choose full" flag value from the native
1497 // dialog and so we can't preserve it between runs, so we decide to
1498 // always use it as it seems better than not using it (user can
1499 // just ignore the extra controls in the dialog but having to click
1500 // a button each time to show them would be very annoying
1501 data.SetChooseFull(true);
1502 #endif // __WXMSW__
1503 }
1504 }
1505
1506 if ( colInit.IsOk() )
1507 {
1508 ptrData->SetColour(colInit);
1509 }
1510
1511 wxColour colRet;
1512 wxColourDialog dialog(parent, ptrData);
1513 if (!caption.empty())
1514 dialog.SetTitle(caption);
1515 if ( dialog.ShowModal() == wxID_OK )
1516 {
1517 *ptrData = dialog.GetColourData();
1518 colRet = ptrData->GetColour();
1519 s_strColourData = ptrData->ToString();
1520 }
1521 //else: leave colRet invalid
1522
1523 return colRet;
1524 }
1525
1526 #endif // wxUSE_COLOURDLG
1527
1528 #if wxUSE_FONTDLG
1529
1530 wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption)
1531 {
1532 wxFontData data;
1533 if ( fontInit.Ok() )
1534 {
1535 data.SetInitialFont(fontInit);
1536 }
1537
1538 wxFont fontRet;
1539 wxFontDialog dialog(parent, data);
1540 if (!caption.empty())
1541 dialog.SetTitle(caption);
1542 if ( dialog.ShowModal() == wxID_OK )
1543 {
1544 fontRet = dialog.GetFontData().GetChosenFont();
1545 }
1546 //else: leave it invalid
1547
1548 return fontRet;
1549 }
1550
1551 #endif // wxUSE_FONTDLG
1552
1553 // ----------------------------------------------------------------------------
1554 // wxSafeYield and supporting functions
1555 // ----------------------------------------------------------------------------
1556
1557 void wxEnableTopLevelWindows(bool enable)
1558 {
1559 wxWindowList::compatibility_iterator node;
1560 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1561 node->GetData()->Enable(enable);
1562 }
1563
1564 wxWindowDisabler::wxWindowDisabler(bool disable)
1565 {
1566 m_disabled = disable;
1567 if ( disable )
1568 DoDisable();
1569 }
1570
1571 wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
1572 {
1573 m_disabled = true;
1574 DoDisable(winToSkip);
1575 }
1576
1577 void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
1578 {
1579 // remember the top level windows which were already disabled, so that we
1580 // don't reenable them later
1581 m_winDisabled = NULL;
1582
1583 wxWindowList::compatibility_iterator node;
1584 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1585 {
1586 wxWindow *winTop = node->GetData();
1587 if ( winTop == winToSkip )
1588 continue;
1589
1590 // we don't need to disable the hidden or already disabled windows
1591 if ( winTop->IsEnabled() && winTop->IsShown() )
1592 {
1593 winTop->Disable();
1594 }
1595 else
1596 {
1597 if ( !m_winDisabled )
1598 {
1599 m_winDisabled = new wxWindowList;
1600 }
1601
1602 m_winDisabled->Append(winTop);
1603 }
1604 }
1605 }
1606
1607 wxWindowDisabler::~wxWindowDisabler()
1608 {
1609 if ( !m_disabled )
1610 return;
1611
1612 wxWindowList::compatibility_iterator node;
1613 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1614 {
1615 wxWindow *winTop = node->GetData();
1616 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
1617 {
1618 winTop->Enable();
1619 }
1620 //else: had been already disabled, don't reenable
1621 }
1622
1623 delete m_winDisabled;
1624 }
1625
1626 // Yield to other apps/messages and disable user input to all windows except
1627 // the given one
1628 bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
1629 {
1630 wxWindowDisabler wd(win);
1631
1632 bool rc;
1633 if (onlyIfNeeded)
1634 rc = wxYieldIfNeeded();
1635 else
1636 rc = wxYield();
1637
1638 return rc;
1639 }
1640
1641 // Don't synthesize KeyUp events holding down a key and producing KeyDown
1642 // events with autorepeat. On by default and always on in wxMSW. wxGTK version
1643 // in utilsgtk.cpp.
1644 #ifndef __WXGTK__
1645 bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
1646 {
1647 return true; // detectable auto-repeat is the only mode MSW supports
1648 }
1649 #endif // !wxGTK
1650
1651 #endif // wxUSE_GUI