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