]> git.saurik.com Git - wxWidgets.git/blame - src/common/utilscmn.cpp
Update OpenVMS compile support
[wxWidgets.git] / src / common / utilscmn.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
3452f00b 2// Name: src/common/utilscmn.cpp
c801d85f
KB
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
65571936 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
e90c1d2a
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
c801d85f
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
e90c1d2a 24 #pragma hdrstop
c801d85f
KB
25#endif
26
27#ifndef WX_PRECOMP
fcdb9b38 28 #include "wx/app.h"
e90c1d2a
VZ
29 #include "wx/string.h"
30 #include "wx/utils.h"
974e8d94
VZ
31 #include "wx/intl.h"
32 #include "wx/log.h"
e90c1d2a
VZ
33
34 #if wxUSE_GUI
35 #include "wx/window.h"
e90c1d2a 36 #include "wx/frame.h"
1e6feb95 37 #include "wx/menu.h"
e90c1d2a
VZ
38 #include "wx/msgdlg.h"
39 #include "wx/textdlg.h"
78bcfcfc 40 #include "wx/textctrl.h" // for wxTE_PASSWORD
974e8d94
VZ
41 #if wxUSE_ACCEL
42 #include "wx/menuitem.h"
43 #include "wx/accel.h"
44 #endif // wxUSE_ACCEL
e90c1d2a
VZ
45 #endif // wxUSE_GUI
46#endif // WX_PRECOMP
c801d85f 47
2739d4f0
VZ
48#include "wx/apptrait.h"
49
cd6ce4a9
VZ
50#include "wx/process.h"
51#include "wx/txtstrm.h"
498a1eeb
RN
52#include "wx/uri.h"
53#include "wx/mimetype.h"
54#include "wx/config.h"
cd6ce4a9 55
4676948b
JS
56#if defined(__WXWINCE__) && wxUSE_DATETIME
57#include "wx/datetime.h"
58#endif
59
c801d85f
KB
60#include <ctype.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
e90c1d2a 64
13ff2485 65#if !wxONLY_WATCOM_EARLIER_THAN(1,4)
3f4a0c5b
VZ
66 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
67 #include <errno.h>
68 #endif
c801d85f 69#endif
e90c1d2a 70
91b4c08d
VZ
71#if wxUSE_GUI
72 #include "wx/colordlg.h"
bf31fa26 73 #include "wx/fontdlg.h"
d1c8aaa3 74 #include "wx/notebook.h"
d1c8aaa3 75 #include "wx/statusbr.h"
91b4c08d
VZ
76#endif // wxUSE_GUI
77
9b4da627 78#ifndef __WXPALMOS5__
1c193821 79#ifndef __WXWINCE__
c801d85f 80#include <time.h>
1c193821
JS
81#else
82#include "wx/msw/wince/time.h"
83#endif
9b4da627 84#endif // ! __WXPALMOS5__
e90c1d2a 85
f14d6dd1 86#ifdef __WXMAC__
c933e267 87#include "wx/osx/private.h"
f14d6dd1
JS
88#endif
89
9b4da627 90#ifndef __WXPALMOS5__
4676948b 91#if !defined(__MWERKS__) && !defined(__WXWINCE__)
e90c1d2a
VZ
92 #include <sys/types.h>
93 #include <sys/stat.h>
469e1e5c 94#endif
9b4da627 95#endif // ! __WXPALMOS5__
c801d85f 96
82ef81ed 97#if defined(__WXMSW__)
5e1febfa 98 #include "wx/msw/private.h"
3452f00b 99 #include "wx/msw/registry.h"
b21d68c6 100 #include <shellapi.h> // needed for SHELLEXECUTEINFO
c801d85f
KB
101#endif
102
6ed3db08
VZ
103#if wxUSE_GUI && defined(__WXGTK__)
104 #include <gtk/gtk.h> // for GTK_XXX_VERSION constants
105#endif
106
ec67cff1 107#if wxUSE_BASE
7c072018 108
73deed44
VZ
109// ----------------------------------------------------------------------------
110// common data
111// ----------------------------------------------------------------------------
112
e90c1d2a
VZ
113// ============================================================================
114// implementation
115// ============================================================================
c801d85f 116
c801d85f 117// Array used in DecToHex conversion routine.
223d09f6 118static wxChar hexArray[] = wxT("0123456789ABCDEF");
c801d85f
KB
119
120// Convert 2-digit hex number to decimal
fd71308f 121int wxHexToDec(const wxString& buf)
c801d85f 122{
657a7545 123 int firstDigit, secondDigit;
3f4a0c5b 124
657a7545
WS
125 if (buf.GetChar(0) >= wxT('A'))
126 firstDigit = buf.GetChar(0) - wxT('A') + 10;
127 else
128 firstDigit = buf.GetChar(0) - wxT('0');
c801d85f 129
657a7545
WS
130 if (buf.GetChar(1) >= wxT('A'))
131 secondDigit = buf.GetChar(1) - wxT('A') + 10;
132 else
133 secondDigit = buf.GetChar(1) - wxT('0');
3f4a0c5b 134
657a7545 135 return (firstDigit & 0xF) * 16 + (secondDigit & 0xF );
c801d85f
KB
136}
137
138// Convert decimal integer to 2-character hex string
84fff0b3 139void wxDecToHex(int dec, wxChar *buf)
c801d85f 140{
657a7545
WS
141 int firstDigit = (int)(dec/16.0);
142 int secondDigit = (int)(dec - (firstDigit*16.0));
143 buf[0] = hexArray[firstDigit];
144 buf[1] = hexArray[secondDigit];
145 buf[2] = 0;
c801d85f
KB
146}
147
f728025e
JS
148// Convert decimal integer to 2 characters
149void wxDecToHex(int dec, char* ch1, char* ch2)
150{
151 int firstDigit = (int)(dec/16.0);
152 int secondDigit = (int)(dec - (firstDigit*16.0));
153 (*ch1) = (char) hexArray[firstDigit];
154 (*ch2) = (char) hexArray[secondDigit];
155}
156
fd71308f
JS
157// Convert decimal integer to 2-character hex string
158wxString wxDecToHex(int dec)
159{
84fff0b3 160 wxChar buf[3];
fd71308f
JS
161 wxDecToHex(dec, buf);
162 return wxString(buf);
163}
164
7c072018
VZ
165// ----------------------------------------------------------------------------
166// misc functions
167// ----------------------------------------------------------------------------
c801d85f
KB
168
169// Return the current date/time
e90c1d2a 170wxString wxNow()
c801d85f 171{
4676948b
JS
172#ifdef __WXWINCE__
173#if wxUSE_DATETIME
174 wxDateTime now = wxDateTime::Now();
175 return now.Format();
176#else
177 return wxEmptyString;
178#endif
179#else
2b5f62a0
VZ
180 time_t now = time((time_t *) NULL);
181 char *date = ctime(&now);
182 date[24] = '\0';
183 return wxString::FromAscii(date);
4676948b 184#endif
c801d85f
KB
185}
186
08873d36
VZ
187void wxUsleep(unsigned long milliseconds)
188{
189 wxMilliSleep(milliseconds);
190}
191
7c072018
VZ
192const wxChar *wxGetInstallPrefix()
193{
194 wxString prefix;
195
196 if ( wxGetEnv(wxT("WXPREFIX"), &prefix) )
197 return prefix.c_str();
198
199#ifdef wxINSTALL_PREFIX
200 return wxT(wxINSTALL_PREFIX);
201#else
525d8583 202 return wxEmptyString;
7c072018
VZ
203#endif
204}
205
206wxString wxGetDataDir()
207{
10f206ad
RL
208 wxString dir = wxGetInstallPrefix();
209 dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx");
7c072018
VZ
210 return dir;
211}
e90c1d2a 212
8bb6b2c0 213bool wxIsPlatformLittleEndian()
2739d4f0 214{
8bb6b2c0
VZ
215 // Are we little or big endian? This method is from Harbison & Steele.
216 union
217 {
218 long l;
219 char c[sizeof(long)];
220 } u;
221 u.l = 1;
222
223 return u.c[0] == 1;
2739d4f0 224}
1e6feb95 225
8bb6b2c0 226
230c9077
JS
227/*
228 * Class to make it easier to specify platform-dependent values
229 */
230
231wxArrayInt* wxPlatform::sm_customPlatforms = NULL;
232
4bfec179 233void wxPlatform::Copy(const wxPlatform& platform)
230c9077 234{
4bfec179
JS
235 m_longValue = platform.m_longValue;
236 m_doubleValue = platform.m_doubleValue;
237 m_stringValue = platform.m_stringValue;
238}
239
240wxPlatform wxPlatform::If(int platform, long value)
241{
242 if (Is(platform))
243 return wxPlatform(value);
244 else
245 return wxPlatform();
246}
247
248wxPlatform wxPlatform::IfNot(int platform, long value)
249{
250 if (!Is(platform))
251 return wxPlatform(value);
252 else
253 return wxPlatform();
254}
255
256wxPlatform& wxPlatform::ElseIf(int platform, long value)
257{
258 if (Is(platform))
230c9077
JS
259 m_longValue = value;
260 return *this;
261}
262
4bfec179 263wxPlatform& wxPlatform::ElseIfNot(int platform, long value)
230c9077 264{
4bfec179 265 if (!Is(platform))
230c9077
JS
266 m_longValue = value;
267 return *this;
268}
269
4bfec179 270wxPlatform wxPlatform::If(int platform, double value)
230c9077 271{
4bfec179
JS
272 if (Is(platform))
273 return wxPlatform(value);
274 else
275 return wxPlatform();
276}
277
278wxPlatform wxPlatform::IfNot(int platform, double value)
279{
280 if (!Is(platform))
281 return wxPlatform(value);
282 else
283 return wxPlatform();
284}
285
286wxPlatform& wxPlatform::ElseIf(int platform, double value)
287{
288 if (Is(platform))
230c9077
JS
289 m_doubleValue = value;
290 return *this;
291}
292
4bfec179 293wxPlatform& wxPlatform::ElseIfNot(int platform, double value)
230c9077 294{
4bfec179 295 if (!Is(platform))
230c9077
JS
296 m_doubleValue = value;
297 return *this;
298}
299
4bfec179
JS
300wxPlatform wxPlatform::If(int platform, const wxString& value)
301{
302 if (Is(platform))
303 return wxPlatform(value);
304 else
305 return wxPlatform();
306}
307
308wxPlatform wxPlatform::IfNot(int platform, const wxString& value)
309{
310 if (!Is(platform))
311 return wxPlatform(value);
312 else
313 return wxPlatform();
314}
315
316wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value)
230c9077 317{
4bfec179 318 if (Is(platform))
230c9077
JS
319 m_stringValue = value;
320 return *this;
321}
322
4bfec179 323wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value)
230c9077 324{
4bfec179 325 if (!Is(platform))
230c9077
JS
326 m_stringValue = value;
327 return *this;
328}
329
4bfec179 330wxPlatform& wxPlatform::Else(long value)
230c9077
JS
331{
332 m_longValue = value;
333 return *this;
334}
335
4bfec179 336wxPlatform& wxPlatform::Else(double value)
230c9077
JS
337{
338 m_doubleValue = value;
339 return *this;
340}
341
4bfec179 342wxPlatform& wxPlatform::Else(const wxString& value)
230c9077
JS
343{
344 m_stringValue = value;
345 return *this;
346}
347
348void wxPlatform::AddPlatform(int platform)
349{
350 if (!sm_customPlatforms)
351 sm_customPlatforms = new wxArrayInt;
352 sm_customPlatforms->Add(platform);
353}
354
355void wxPlatform::ClearPlatforms()
356{
357 delete sm_customPlatforms;
358 sm_customPlatforms = NULL;
359}
360
361/// Function for testing current platform
362
4bfec179 363bool wxPlatform::Is(int platform)
230c9077
JS
364{
365#ifdef __WXMSW__
216c3543 366 if (platform == wxOS_WINDOWS)
230c9077
JS
367 return true;
368#endif
369#ifdef __WXWINCE__
216c3543 370 if (platform == wxOS_WINDOWS_CE)
230c9077
JS
371 return true;
372#endif
a6e8c584
WS
373
374#if 0
375
376// FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols
377
230c9077
JS
378#if defined(__WXWINCE__) && defined(__POCKETPC__)
379 if (platform == wxWinPocketPC)
380 return true;
381#endif
382#if defined(__WXWINCE__) && defined(__SMARTPHONE__)
6aa68c25 383 if (platform == wxWinSmartPhone)
230c9077
JS
384 return true;
385#endif
a6e8c584
WS
386
387#endif
388
230c9077 389#ifdef __WXGTK__
216c3543 390 if (platform == wxPORT_GTK)
230c9077
JS
391 return true;
392#endif
393#ifdef __WXMAC__
216c3543 394 if (platform == wxPORT_MAC)
230c9077
JS
395 return true;
396#endif
397#ifdef __WXX11__
216c3543 398 if (platform == wxPORT_X11)
230c9077
JS
399 return true;
400#endif
401#ifdef __UNIX__
216c3543 402 if (platform == wxOS_UNIX)
230c9077
JS
403 return true;
404#endif
405#ifdef __WXMGL__
216c3543 406 if (platform == wxPORT_MGL)
230c9077
JS
407 return true;
408#endif
8ab09e65
SN
409#ifdef __OS2__
410 if (platform == wxOS_OS2)
411 return true;
412#endif
413#ifdef __WXPM__
414 if (platform == wxPORT_PM)
230c9077
JS
415 return true;
416#endif
55d452c6 417#ifdef __WXCOCOA__
216c3543 418 if (platform == wxPORT_MAC)
230c9077
JS
419 return true;
420#endif
421
422 if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND)
423 return true;
424
425 return false;
426}
427
e90c1d2a 428// ----------------------------------------------------------------------------
7c072018 429// network and user id functions
e90c1d2a 430// ----------------------------------------------------------------------------
c801d85f 431
7c072018
VZ
432// Get Full RFC822 style email address
433bool wxGetEmailAddress(wxChar *address, int maxSize)
c801d85f 434{
7c072018
VZ
435 wxString email = wxGetEmailAddress();
436 if ( !email )
cb719f2e 437 return false;
c801d85f 438
9d4943cd 439 wxStrlcpy(address, email.t_str(), maxSize);
7c072018 440
cb719f2e 441 return true;
c801d85f
KB
442}
443
7c072018 444wxString wxGetEmailAddress()
47bc1060 445{
7c072018 446 wxString email;
974e8d94 447
7c072018 448 wxString host = wxGetFullHostName();
4055ed82 449 if ( !host.empty() )
1e6feb95 450 {
7c072018 451 wxString user = wxGetUserId();
4055ed82 452 if ( !user.empty() )
1e6feb95 453 {
7c072018 454 email << user << wxT('@') << host;
974e8d94 455 }
974e8d94
VZ
456 }
457
7c072018 458 return email;
974e8d94
VZ
459}
460
7c072018 461wxString wxGetUserId()
c801d85f 462{
7c072018 463 static const int maxLoginLen = 256; // FIXME arbitrary number
c801d85f 464
7c072018 465 wxString buf;
4c3ebca9 466 bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen);
c801d85f 467
7c072018
VZ
468 if ( !ok )
469 buf.Empty();
c801d85f 470
7c072018 471 return buf;
c801d85f
KB
472}
473
7c072018 474wxString wxGetUserName()
c801d85f 475{
7c072018 476 static const int maxUserNameLen = 1024; // FIXME arbitrary number
1e6feb95 477
7c072018 478 wxString buf;
4c3ebca9 479 bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen);
7c072018
VZ
480
481 if ( !ok )
482 buf.Empty();
483
484 return buf;
59a12e90
JS
485}
486
7c072018 487wxString wxGetHostName()
59a12e90 488{
7c072018 489 static const size_t hostnameSize = 257;
c67d6888 490
7c072018 491 wxString buf;
4c3ebca9 492 bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
59a12e90 493
7c072018
VZ
494 if ( !ok )
495 buf.Empty();
59a12e90 496
7c072018 497 return buf;
59a12e90
JS
498}
499
7c072018 500wxString wxGetFullHostName()
59a12e90 501{
7c072018 502 static const size_t hostnameSize = 257;
c801d85f 503
7c072018 504 wxString buf;
4c3ebca9 505 bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
7c072018
VZ
506
507 if ( !ok )
508 buf.Empty();
c801d85f 509
7c072018
VZ
510 return buf;
511}
c801d85f 512
7c072018
VZ
513wxString wxGetHomeDir()
514{
515 wxString home;
516 wxGetHomeDir(&home);
c801d85f 517
7c072018
VZ
518 return home;
519}
c801d85f 520
c801d85f
KB
521#if 0
522
7c072018 523wxString wxGetCurrentDir()
c801d85f 524{
7c072018
VZ
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();
c801d85f 532
7c072018
VZ
533 if ( !ok )
534 {
535 if ( errno != ERANGE )
536 {
537 wxLogSysError(_T("Failed to get current directory"));
c801d85f 538
7c072018
VZ
539 return wxEmptyString;
540 }
3f4a0c5b 541 else
7c072018
VZ
542 {
543 // buffer was too small, retry with a larger one
544 len *= 2;
545 }
3f4a0c5b 546 }
7c072018
VZ
547 //else: ok
548 } while ( !ok );
c801d85f 549
7c072018 550 return dir;
c801d85f
KB
551}
552
7c072018 553#endif // 0
e90c1d2a
VZ
554
555// ----------------------------------------------------------------------------
7c072018 556// wxExecute
e90c1d2a 557// ----------------------------------------------------------------------------
ead7ce10 558
7c072018
VZ
559// wxDoExecuteWithCapture() helper: reads an entire stream into one array
560//
cb719f2e 561// returns true if ok, false if error
7c072018
VZ
562#if wxUSE_STREAMS
563static bool ReadAll(wxInputStream *is, wxArrayString& output)
dfad0599 564{
cb719f2e 565 wxCHECK_MSG( is, false, _T("NULL stream in wxExecute()?") );
dfad0599 566
7c072018
VZ
567 // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
568 is->Reset();
1e6feb95 569
7c072018 570 wxTextInputStream tis(*is);
1e6feb95 571
8bdc8a9c 572 for ( ;; )
d2f50933 573 {
7c072018 574 wxString line = tis.ReadLine();
8bdc8a9c
VZ
575
576 // check for EOF before other errors as it's not really an error
7c072018 577 if ( is->Eof() )
8bdc8a9c
VZ
578 {
579 // add the last, possibly incomplete, line
580 if ( !line.empty() )
581 output.Add(line);
7c072018 582 break;
8bdc8a9c 583 }
7c072018 584
8bdc8a9c 585 // any other error is fatal
7c072018 586 if ( !*is )
8bdc8a9c
VZ
587 return false;
588
589 output.Add(line);
d2f50933
VZ
590 }
591
8bdc8a9c 592 return true;
dfad0599 593}
7c072018 594#endif // wxUSE_STREAMS
d2f50933 595
7c072018
VZ
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
599static long wxDoExecuteWithCapture(const wxString& command,
600 wxArrayString& output,
4d172154
VZ
601 wxArrayString* error,
602 int flags)
d2f50933 603{
7c072018
VZ
604 // create a wxProcess which will capture the output
605 wxProcess *process = new wxProcess;
606 process->Redirect();
dfad0599 607
4d172154 608 long rc = wxExecute(command, wxEXEC_SYNC | flags, process);
1e6feb95 609
7c072018
VZ
610#if wxUSE_STREAMS
611 if ( rc != -1 )
bf31fa26 612 {
7c072018
VZ
613 if ( !ReadAll(process->GetInputStream(), output) )
614 rc = -1;
91b4c08d 615
7c072018
VZ
616 if ( error )
617 {
618 if ( !ReadAll(process->GetErrorStream(), *error) )
619 rc = -1;
620 }
91b4c08d 621
7c072018 622 }
e70ba80d
WS
623#else
624 wxUnusedVar(output);
625 wxUnusedVar(error);
626#endif // wxUSE_STREAMS/!wxUSE_STREAMS
91b4c08d 627
7c072018 628 delete process;
1e6feb95 629
7c072018 630 return rc;
7c072018 631}
bf31fa26 632
4d172154 633long wxExecute(const wxString& command, wxArrayString& output, int flags)
bf31fa26 634{
4d172154 635 return wxDoExecuteWithCapture(command, output, NULL, flags);
7c072018 636}
bf31fa26 637
7c072018
VZ
638long wxExecute(const wxString& command,
639 wxArrayString& output,
4d172154
VZ
640 wxArrayString& error,
641 int flags)
7c072018 642{
4d172154 643 return wxDoExecuteWithCapture(command, output, &error, flags);
bf31fa26
VZ
644}
645
c5f0d1f9
DE
646// ----------------------------------------------------------------------------
647// wxApp::Yield() wrappers for backwards compatibility
648// ----------------------------------------------------------------------------
649
650bool wxYield()
651{
652 return wxTheApp && wxTheApp->Yield();
653}
654
655bool wxYieldIfNeeded()
656{
657 return wxTheApp && wxTheApp->Yield(true);
658}
659
660// Id generation
661static long wxCurrentId = 100;
662
663long 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
672long
673wxGetCurrentId(void) { return wxCurrentId; }
674
675void
676wxRegisterId (long id)
677{
678 if (id >= wxCurrentId)
679 wxCurrentId = id + 1;
680}
681
fe5f448f
RR
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).
11fe6505 688
fe5f448f
RR
689 Douglas Schmidt kindly gave permission to relicence the
690 code under the wxWindows licence:
11fe6505 691
fe5f448f
RR
692From: "Douglas C. Schmidt" <schmidt@dre.vanderbilt.edu>
693To: Robert Roebling <robert.roebling@uni-ulm.de>
11fe6505 694Subject: Re: qsort licence
fe5f448f
RR
695Date: Mon, 23 Jul 2007 03:44:25 -0500
696Sender: schmidt@dre.vanderbilt.edu
697Message-Id: <20070723084426.64F511000A8@tango.dre.vanderbilt.edu>
698
699Hi Robert,
700
701> [...] I'm asking if you'd be willing to relicence your code
702> under the wxWindows licence. [...]
703
704That's fine with me [...]
705
706Thanks,
707
708 Doug */
709
710
711/* Byte-wise swap two items of size SIZE. */
11fe6505
VZ
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); \
fe5f448f
RR
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. */
730typedef 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. */
11fe6505 737#define STACK_SIZE (8 * sizeof(unsigned long int))
e71bf8b2
VZ
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)
fe5f448f
RR
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
766void wxQsort(void *const pbase, size_t total_elems,
11fe6505 767 size_t size, CMPFUNCDATA cmp, const void* user_data)
fe5f448f
RR
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
11fe6505
VZ
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);
fe5f448f
RR
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)
11fe6505 847 /* Ignore both small partitions. */
fe5f448f
RR
848 POP (lo, hi);
849 else
11fe6505 850 /* Ignore small left partition. */
fe5f448f
RR
851 lo = left_ptr;
852 }
853 else if ((size_t) (hi - left_ptr) <= max_thresh)
11fe6505 854 /* Ignore small right partition. */
fe5f448f
RR
855 hi = right_ptr;
856 else if ((right_ptr - lo) > (hi - left_ptr))
857 {
11fe6505 858 /* Push larger left partition indices. */
fe5f448f
RR
859 PUSH (lo, right_ptr);
860 lo = left_ptr;
861 }
862 else
863 {
11fe6505 864 /* Push larger right partition indices. */
fe5f448f
RR
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
fe5f448f
RR
877 {
878 char *const end_ptr = &base_ptr[size * (total_elems - 1)];
879 char *tmp_ptr = base_ptr;
e71bf8b2
VZ
880 char *thresh = base_ptr + max_thresh;
881 if ( thresh > end_ptr )
882 thresh = end_ptr;
fe5f448f
RR
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 {
11fe6505
VZ
901 tmp_ptr = run_ptr - size;
902 while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0)
903 tmp_ptr -= size;
fe5f448f 904
11fe6505 905 tmp_ptr += size;
fe5f448f
RR
906 if (tmp_ptr != run_ptr)
907 {
908 char *trav;
909
11fe6505
VZ
910 trav = run_ptr + size;
911 while (--trav >= run_ptr)
fe5f448f
RR
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
c5f0d1f9
DE
927#endif // wxUSE_BASE
928
929// ============================================================================
930// GUI-only functions from now on
931// ============================================================================
932
933#if wxUSE_GUI
934
1dea1566
RR
935// ----------------------------------------------------------------------------
936// Launch document with default app
937// ----------------------------------------------------------------------------
938
f06832c1 939bool wxLaunchDefaultApplication(const wxString& document, int flags)
1dea1566
RR
940{
941 wxUnusedVar(flags);
f75e0c15 942
979a7347
VZ
943#ifdef __WXMAC__
944 static const char * const OPEN_CMD = "/usr/bin/open";
65751a0e
VZ
945 if ( wxFileExists(OPEN_CMD) &&
946 wxExecute(wxString(OPEN_CMD) + " " + document) )
979a7347
VZ
947 return true;
948#elif defined(__UNIX__)
1dea1566
RR
949 // Our best best is to use xdg-open from freedesktop.org cross-desktop
950 // compatibility suite xdg-utils
951 // (see http://portland.freedesktop.org/wiki/) -- this is installed on
952 // most modern distributions and may be tweaked by them to handle
953 // distribution specifics.
954 wxString path, xdg_open;
955 if ( wxGetEnv("PATH", &path) &&
956 wxFindFileInPath(&xdg_open, path, "xdg-open") )
957 {
958 if ( wxExecute(xdg_open + " " + document) )
959 return true;
960 }
f06832c1 961#elif defined(__WXMSW__)
58ac79d3
VZ
962 WinStruct<SHELLEXECUTEINFO> sei;
963 sei.lpFile = document.wx_str();
964 sei.lpVerb = _T("open");
965 sei.nShow = SW_SHOWDEFAULT;
966
967 // avoid Windows message box in case of error for consistency with
968 // wxLaunchDefaultBrowser() even if don't show the error ourselves in this
969 // function
970 sei.fMask = SEE_MASK_FLAG_NO_UI;
971
972 if ( ::ShellExecuteEx(&sei) )
f06832c1 973 return true;
1dea1566
RR
974#endif
975
f06832c1 976 return false;
1dea1566
RR
977}
978
498a1eeb
RN
979// ----------------------------------------------------------------------------
980// Launch default browser
981// ----------------------------------------------------------------------------
982
4263bab0
DE
983#ifdef __WXCOCOA__
984// Private method in Objective-C++ source file.
985bool wxCocoaLaunchDefaultBrowser(const wxString& url, int flags);
986#endif
987
f75e0c15 988static bool DoLaunchDefaultBrowser(const wxString& urlOrig, int flags)
498a1eeb 989{
42d0df00
VZ
990 wxUnusedVar(flags);
991
7999124f 992 // set the scheme of url to http if it does not have one
889fda0c 993 // RR: This doesn't work if the url is just a local path
7999124f 994 wxString url(urlOrig);
6f6dd276
VZ
995 wxURI uri(url);
996 if ( !uri.HasScheme() )
d545f803
RR
997 {
998 if (wxFileExists(urlOrig))
999 url.Prepend( wxT("file://") );
1000 else
1001 url.Prepend(wxT("http://"));
1002 }
889fda0c 1003
532d575b 1004
7999124f 1005#if defined(__WXMSW__)
5ccb95f6
WS
1006
1007#if wxUSE_IPC
42d0df00
VZ
1008 if ( flags & wxBROWSER_NEW_WINDOW )
1009 {
1010 // ShellExecuteEx() opens the URL in an existing window by default so
1011 // we can't use it if we need a new window
6f6dd276
VZ
1012 wxRegKey key(wxRegKey::HKCR, uri.GetScheme() + _T("\\shell\\open"));
1013 if ( !key.Exists() )
1014 {
1015 // try default browser, it must be registered at least for http URLs
1016 key.SetName(wxRegKey::HKCR, _T("http\\shell\\open"));
1017 }
1018
42d0df00
VZ
1019 if ( key.Exists() )
1020 {
1021 wxRegKey keyDDE(key, wxT("DDEExec"));
1022 if ( keyDDE.Exists() )
1023 {
42d0df00
VZ
1024 // we only know the syntax of WWW_OpenURL DDE request for IE,
1025 // optimistically assume that all other browsers are compatible
1026 // with it
19abad60
VZ
1027 static const wxChar *TOPIC_OPEN_URL = wxT("WWW_OpenURL");
1028 wxString ddeCmd;
f524b093 1029 wxRegKey keyTopic(keyDDE, wxT("topic"));
53b849ea
VZ
1030 bool ok = keyTopic.Exists() &&
1031 keyTopic.QueryDefaultValue() == TOPIC_OPEN_URL;
42d0df00
VZ
1032 if ( ok )
1033 {
588c80de 1034 ddeCmd = keyDDE.QueryDefaultValue();
42d0df00
VZ
1035 ok = !ddeCmd.empty();
1036 }
1037
1038 if ( ok )
1039 {
1040 // for WWW_OpenURL, the index of the window to open the URL
1041 // in is -1 (meaning "current") by default, replace it with
1042 // 0 which means "new" (see KB article 160957)
1043 ok = ddeCmd.Replace(wxT("-1"), wxT("0"),
7929902d 1044 false /* only first occurrence */) == 1;
42d0df00
VZ
1045 }
1046
1047 if ( ok )
1048 {
1049 // and also replace the parameters: the topic should
1050 // contain a placeholder for the URL
1051 ok = ddeCmd.Replace(wxT("%1"), url, false) == 1;
1052 }
1053
1054 if ( ok )
1055 {
1056 // try to send it the DDE request now but ignore the errors
1057 wxLogNull noLog;
1058
1059 const wxString ddeServer = wxRegKey(keyDDE, wxT("application"));
19abad60 1060 if ( wxExecuteDDE(ddeServer, TOPIC_OPEN_URL, ddeCmd) )
42d0df00
VZ
1061 return true;
1062
1063 // this is not necessarily an error: maybe browser is
1064 // simply not running, but no matter, in any case we're
1065 // going to launch it using ShellExecuteEx() below now and
1066 // we shouldn't try to open a new window if we open a new
1067 // browser anyhow
1068 }
1069 }
1070 }
1071 }
5ccb95f6 1072#endif // wxUSE_IPC
42d0df00 1073
7999124f
VZ
1074 WinStruct<SHELLEXECUTEINFO> sei;
1075 sei.lpFile = url.c_str();
1076 sei.lpVerb = _T("open");
1077 sei.nShow = SW_SHOWNORMAL;
f524b093 1078 sei.fMask = SEE_MASK_FLAG_NO_UI; // we give error message ourselves
498a1eeb 1079
2190f6aa 1080 if ( ::ShellExecuteEx(&sei) )
7999124f 1081 return true;
4263bab0
DE
1082#elif defined(__WXCOCOA__)
1083 // NOTE: We need to call the real implementation from src/cocoa/utils.mm
1084 // because the code must use Objective-C features.
1085 return wxCocoaLaunchDefaultBrowser(url, flags);
c933e267 1086#elif defined(__WXMAC__) && !defined(__WXOSX_IPHONE__)
5d713a75
SC
1087 wxCFRef< CFURLRef > curl( CFURLCreateWithString( kCFAllocatorDefault,
1088 wxCFStringRef( url ), NULL ) );
1089 OSStatus err = LSOpenCFURLRef( curl , NULL );
f14d6dd1 1090
13a1e96f
DS
1091 if (err == noErr)
1092 {
f14d6dd1
JS
1093 return true;
1094 }
1095 else
1096 {
5d713a75 1097 wxLogDebug(wxT("Browser Launch error %d"), (int) err);
f14d6dd1
JS
1098 return false;
1099 }
f728025e 1100#else
889fda0c
RR
1101 // (non-Mac, non-MSW)
1102
1103#ifdef __UNIX__
17ede0b1 1104
ae46a7fd
VS
1105 // Our best best is to use xdg-open from freedesktop.org cross-desktop
1106 // compatibility suite xdg-utils
1107 // (see http://portland.freedesktop.org/wiki/) -- this is installed on
1108 // most modern distributions and may be tweaked by them to handle
1109 // distribution specifics. Only if that fails, try to find the right
1110 // browser ourselves.
1111 wxString path, xdg_open;
1112 if ( wxGetEnv("PATH", &path) &&
1113 wxFindFileInPath(&xdg_open, path, "xdg-open") )
1114 {
1115 if ( wxExecute(xdg_open + " " + url) )
1116 return true;
1117 }
1118
17ede0b1
RR
1119 wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment();
1120
1121 // GNOME and KDE desktops have some applications which should be always installed
1122 // together with their main parts, which give us the
1123 if (desktop == wxT("GNOME"))
889fda0c
RR
1124 {
1125 wxArrayString errors;
1126 wxArrayString output;
17ede0b1
RR
1127
1128 // gconf will tell us the path of the application to use as browser
1129 long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"),
1130 output, errors, wxEXEC_NODISABLE );
889fda0c
RR
1131 if (res >= 0 && errors.GetCount() == 0)
1132 {
1133 wxString cmd = output[0];
1134 cmd << _T(' ') << url;
1135 if (wxExecute(cmd))
1136 return true;
1137 }
1138 }
17ede0b1
RR
1139 else if (desktop == wxT("KDE"))
1140 {
1141 // kfmclient directly opens the given URL
1142 if (wxExecute(wxT("kfmclient openURL ") + url))
1143 return true;
1144 }
889fda0c
RR
1145#endif
1146
13a1e96f
DS
1147 bool ok = false;
1148 wxString cmd;
1149
1b1b5318 1150#if wxUSE_MIMETYPE
13a1e96f 1151 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html"));
7999124f 1152 if ( ft )
657a7545 1153 {
7999124f
VZ
1154 wxString mt;
1155 ft->GetMimeType(&mt);
498a1eeb 1156
13a1e96f 1157 ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
7999124f 1158 delete ft;
498a1eeb 1159 }
1b1b5318 1160#endif // wxUSE_MIMETYPE
13a1e96f
DS
1161
1162 if ( !ok || cmd.empty() )
2830b4a4 1163 {
13a1e96f
DS
1164 // fallback to checking for the BROWSER environment variable
1165 cmd = wxGetenv(wxT("BROWSER"));
1166 if ( !cmd.empty() )
1167 cmd << _T(' ') << url;
2830b4a4 1168 }
13a1e96f
DS
1169
1170 ok = ( !cmd.empty() && wxExecute(cmd) );
1171 if (ok)
1172 return ok;
1173
1174 // no file type for HTML extension
5519074c 1175 wxLogError(_("No default application configured for HTML files."));
13a1e96f 1176
7999124f 1177#endif // !wxUSE_MIMETYPE && !__WXMSW__
532d575b 1178
5519074c 1179 wxLogSysError(_("Failed to open URL \"%s\" in default browser."),
7999124f 1180 url.c_str());
657a7545 1181
7999124f 1182 return false;
498a1eeb
RN
1183}
1184
f75e0c15
VZ
1185bool wxLaunchDefaultBrowser(const wxString& url, int flags)
1186{
1187 if ( flags & wxBROWSER_NOBUSYCURSOR )
1188 return DoLaunchDefaultBrowser(url, flags);
1189
1190 wxBusyCursor bc;
1191 return DoLaunchDefaultBrowser(url, flags);
1192}
1193
e90c1d2a 1194// ----------------------------------------------------------------------------
7c072018 1195// Menu accelerators related functions
e90c1d2a
VZ
1196// ----------------------------------------------------------------------------
1197
7c072018 1198wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out)
e90c1d2a 1199{
9a6384ca 1200#if wxUSE_MENUS
52af3158 1201 wxString s = wxMenuItem::GetLabelText(in);
9a6384ca
WS
1202#else
1203 wxString str(in);
1204 wxString s = wxStripMenuCodes(str);
1205#endif // wxUSE_MENUS
7c072018
VZ
1206 if ( out )
1207 {
1208 // go smash their buffer if it's not big enough - I love char * params
1209 memcpy(out, s.c_str(), s.length() * sizeof(wxChar));
1210 }
1211 else
1212 {
f526f752
MB
1213 out = new wxChar[s.length() + 1];
1214 wxStrcpy(out, s.c_str());
7c072018
VZ
1215 }
1216
1217 return out;
e90c1d2a
VZ
1218}
1219
74639764 1220wxString wxStripMenuCodes(const wxString& in, int flags)
e90c1d2a 1221{
74639764
VZ
1222 wxASSERT_MSG( flags, _T("this is useless to call without any flags") );
1223
7c072018 1224 wxString out;
79f585d9 1225
7c072018
VZ
1226 size_t len = in.length();
1227 out.reserve(len);
79f585d9 1228
7c072018
VZ
1229 for ( size_t n = 0; n < len; n++ )
1230 {
1231 wxChar ch = in[n];
74639764 1232 if ( (flags & wxStrip_Mnemonics) && ch == _T('&') )
cd6ce4a9 1233 {
7c072018
VZ
1234 // skip it, it is used to introduce the accel char (or to quote
1235 // itself in which case it should still be skipped): note that it
1236 // can't be the last character of the string
1237 if ( ++n == len )
79f585d9 1238 {
7c072018
VZ
1239 wxLogDebug(_T("Invalid menu string '%s'"), in.c_str());
1240 }
1241 else
1242 {
1243 // use the next char instead
1244 ch = in[n];
79f585d9 1245 }
cd6ce4a9 1246 }
74639764 1247 else if ( (flags & wxStrip_Accel) && ch == _T('\t') )
79f585d9 1248 {
7c072018
VZ
1249 // everything after TAB is accel string, exit the loop
1250 break;
79f585d9 1251 }
7c072018
VZ
1252
1253 out += ch;
225fe9d6
VZ
1254 }
1255
7c072018 1256 return out;
cd6ce4a9
VZ
1257}
1258
cbc66a27 1259// ----------------------------------------------------------------------------
7c072018 1260// Window search functions
cbc66a27
VZ
1261// ----------------------------------------------------------------------------
1262
7c072018
VZ
1263/*
1264 * If parent is non-NULL, look through children for a label or title
1265 * matching the specified string. If NULL, look through all top-level windows.
1266 *
1267 */
e2a6f233 1268
7c072018
VZ
1269wxWindow *
1270wxFindWindowByLabel (const wxString& title, wxWindow * parent)
134677bd 1271{
7c072018
VZ
1272 return wxWindow::FindWindowByLabel( title, parent );
1273}
b829bf55 1274
b829bf55 1275
7c072018
VZ
1276/*
1277 * If parent is non-NULL, look through children for a name
1278 * matching the specified string. If NULL, look through all top-level windows.
1279 *
1280 */
134677bd 1281
7c072018
VZ
1282wxWindow *
1283wxFindWindowByName (const wxString& name, wxWindow * parent)
2c18f21d 1284{
7c072018 1285 return wxWindow::FindWindowByName( name, parent );
2c18f21d
VS
1286}
1287
cb719f2e 1288// Returns menu item id or wxNOT_FOUND if none.
7c072018 1289int
8d22935d
VZ
1290wxFindMenuItemId(wxFrame *frame,
1291 const wxString& menuString,
1292 const wxString& itemString)
e2a6f233 1293{
7c072018 1294#if wxUSE_MENUS
9a6384ca
WS
1295 wxMenuBar *menuBar = frame->GetMenuBar ();
1296 if ( menuBar )
1297 return menuBar->FindMenuItem (menuString, itemString);
8d22935d
VZ
1298#else // !wxUSE_MENUS
1299 wxUnusedVar(frame);
1300 wxUnusedVar(menuString);
1301 wxUnusedVar(itemString);
1302#endif // wxUSE_MENUS/!wxUSE_MENUS
0fb67cd1 1303
9a6384ca 1304 return wxNOT_FOUND;
e2a6f233
JS
1305}
1306
7c072018
VZ
1307// Try to find the deepest child that contains 'pt'.
1308// We go backwards, to try to allow for controls that are spacially
1309// within other controls, but are still siblings (e.g. buttons within
1310// static boxes). Static boxes are likely to be created _before_ controls
1311// that sit inside them.
1312wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt)
e2a6f233 1313{
7c072018
VZ
1314 if (!win->IsShown())
1315 return NULL;
0fb67cd1 1316
7c072018
VZ
1317 // Hack for wxNotebook case: at least in wxGTK, all pages
1318 // claim to be shown, so we must only deal with the selected one.
1319#if wxUSE_NOTEBOOK
1320 if (win->IsKindOf(CLASSINFO(wxNotebook)))
e2a6f233 1321 {
7c072018
VZ
1322 wxNotebook* nb = (wxNotebook*) win;
1323 int sel = nb->GetSelection();
1324 if (sel >= 0)
1325 {
1326 wxWindow* child = nb->GetPage(sel);
1327 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1328 if (foundWin)
1329 return foundWin;
1330 }
e2a6f233 1331 }
7c072018 1332#endif
0fb67cd1 1333
df5168c4 1334 wxWindowList::compatibility_iterator node = win->GetChildren().GetLast();
7c072018
VZ
1335 while (node)
1336 {
1337 wxWindow* child = node->GetData();
1338 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1339 if (foundWin)
1340 return foundWin;
1341 node = node->GetPrevious();
1342 }
1343
1344 wxPoint pos = win->GetPosition();
1345 wxSize sz = win->GetSize();
7aa7d2d4 1346 if ( !win->IsTopLevel() && win->GetParent() )
7c072018
VZ
1347 {
1348 pos = win->GetParent()->ClientToScreen(pos);
1349 }
1350
1351 wxRect rect(pos, sz);
22a35096 1352 if (rect.Contains(pt))
7c072018 1353 return win;
622eb786
VZ
1354
1355 return NULL;
0fb67cd1
VZ
1356}
1357
7c072018 1358wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt)
0fb67cd1 1359{
7c072018
VZ
1360 // Go backwards through the list since windows
1361 // on top are likely to have been appended most
1362 // recently.
df5168c4 1363 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast();
7c072018
VZ
1364 while (node)
1365 {
1366 wxWindow* win = node->GetData();
1367 wxWindow* found = wxFindWindowAtPoint(win, pt);
1368 if (found)
1369 return found;
1370 node = node->GetPrevious();
1371 }
1372 return NULL;
1373}
0fb67cd1 1374
7c072018
VZ
1375// ----------------------------------------------------------------------------
1376// GUI helpers
1377// ----------------------------------------------------------------------------
0fb67cd1 1378
7c072018
VZ
1379/*
1380 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
1381 * since otherwise the generic code may be pulled in unnecessarily.
1382 */
0fb67cd1 1383
7c072018 1384#if wxUSE_MSGDLG
0fb67cd1 1385
7c072018
VZ
1386int wxMessageBox(const wxString& message, const wxString& caption, long style,
1387 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
0fb67cd1 1388{
53a6ac21
DS
1389 long decorated_style = style;
1390
1391 if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 )
1392 {
1393 decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ;
1394 }
1395
1396 wxMessageDialog dialog(parent, message, caption, decorated_style);
0fb67cd1 1397
7c072018
VZ
1398 int ans = dialog.ShowModal();
1399 switch ( ans )
1400 {
1401 case wxID_OK:
1402 return wxOK;
1403 case wxID_YES:
1404 return wxYES;
1405 case wxID_NO:
1406 return wxNO;
1407 case wxID_CANCEL:
1408 return wxCANCEL;
1409 }
0fb67cd1 1410
7c072018 1411 wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") );
0fb67cd1 1412
7c072018 1413 return wxCANCEL;
e2a6f233
JS
1414}
1415
8cf304f8
VZ
1416void wxInfoMessageBox(wxWindow* parent)
1417{
1418 // don't translate these strings, they're for diagnostics purposes only
1419 wxString msg;
1420 msg.Printf(_T("wxWidgets Library (%s port)\n")
1421 _T("Version %d.%d.%d%s%s, compiled at %s %s\n")
1422 _T("Runtime version of toolkit used is %d.%d.%s\n")
dbe44db1 1423 _T("Copyright (c) 1995-2008 wxWidgets team"),
8cf304f8
VZ
1424 wxPlatformInfo::Get().GetPortIdName().c_str(),
1425 wxMAJOR_VERSION,
1426 wxMINOR_VERSION,
1427 wxRELEASE_NUMBER,
1428#if wxUSE_UNICODE
1429 L" (Unicode)",
1430#else
1431 wxEmptyString,
1432#endif
1433#ifdef __WXDEBUG__
1434 _T(" Debug build"),
1435#else
1436 wxEmptyString,
1437#endif
1438 __TDATE__,
1439 __TTIME__,
1440 wxPlatformInfo::Get().GetToolkitMajorVersion(),
1441 wxPlatformInfo::Get().GetToolkitMinorVersion(),
1442#ifdef __WXGTK__
6ed3db08
VZ
1443 wxString::Format("\nThe compile-time GTK+ version is %d.%d.%d.",
1444 GTK_MAJOR_VERSION,
1445 GTK_MINOR_VERSION,
1446 GTK_MICRO_VERSION).c_str()
8cf304f8
VZ
1447#else
1448 wxEmptyString
1449#endif
1450 );
1451 wxMessageBox(msg, _T("wxWidgets information"),
1452 wxICON_INFORMATION | wxOK,
1453 parent);
1454}
1455
7c072018 1456#endif // wxUSE_MSGDLG
518b5d2f 1457
7c072018 1458#if wxUSE_TEXTDLG
518b5d2f 1459
7c072018
VZ
1460wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
1461 const wxString& defaultValue, wxWindow *parent,
13d13a9e 1462 wxCoord x, wxCoord y, bool centre )
7c072018
VZ
1463{
1464 wxString str;
13d13a9e
WS
1465 long style = wxTextEntryDialogStyle;
1466
1467 if (centre)
1468 style |= wxCENTRE;
1469 else
1470 style &= ~wxCENTRE;
1471
1472 wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y));
1473
7c072018
VZ
1474 if (dialog.ShowModal() == wxID_OK)
1475 {
1476 str = dialog.GetValue();
1477 }
0fb67cd1 1478
7c072018 1479 return str;
518b5d2f
VZ
1480}
1481
7c072018
VZ
1482wxString wxGetPasswordFromUser(const wxString& message,
1483 const wxString& caption,
1484 const wxString& defaultValue,
b3bb2a74
KH
1485 wxWindow *parent,
1486 wxCoord x, wxCoord y, bool centre )
96c5bd7f 1487{
7c072018 1488 wxString str;
b3bb2a74
KH
1489 long style = wxTextEntryDialogStyle;
1490
1491 if (centre)
1492 style |= wxCENTRE;
1493 else
1494 style &= ~wxCENTRE;
1495
12cfa304
KH
1496 wxPasswordEntryDialog dialog(parent, message, caption, defaultValue,
1497 style, wxPoint(x, y));
7c072018
VZ
1498 if ( dialog.ShowModal() == wxID_OK )
1499 {
1500 str = dialog.GetValue();
1501 }
96c5bd7f 1502
7c072018
VZ
1503 return str;
1504}
96c5bd7f 1505
7c072018 1506#endif // wxUSE_TEXTDLG
96c5bd7f 1507
7c072018 1508#if wxUSE_COLOURDLG
96c5bd7f 1509
f75e0c15
VZ
1510wxColour wxGetColourFromUser(wxWindow *parent,
1511 const wxColour& colInit,
e6ef9ea4
VZ
1512 const wxString& caption,
1513 wxColourData *ptrData)
c51deffc 1514{
e6ef9ea4
VZ
1515 // contains serialized representation of wxColourData used the last time
1516 // the dialog was shown: we want to reuse it the next time in order to show
1517 // the same custom colours to the user (and we can't just have static
1518 // wxColourData itself because it's a GUI object and so should be destroyed
1519 // before GUI shutdown and doing it during static cleanup is too late)
1520 static wxString s_strColourData;
1521
7c072018 1522 wxColourData data;
e6ef9ea4 1523 if ( !ptrData )
7c072018 1524 {
e6ef9ea4
VZ
1525 ptrData = &data;
1526 if ( !s_strColourData.empty() )
1527 {
1528 if ( !data.FromString(s_strColourData) )
1529 {
1530 wxFAIL_MSG( "bug in wxColourData::FromString()?" );
1531 }
1532
1533#ifdef __WXMSW__
1534 // we don't get back the "choose full" flag value from the native
1535 // dialog and so we can't preserve it between runs, so we decide to
1536 // always use it as it seems better than not using it (user can
1537 // just ignore the extra controls in the dialog but having to click
1538 // a button each time to show them would be very annoying
1539 data.SetChooseFull(true);
1540#endif // __WXMSW__
1541 }
1542 }
1543
1544 if ( colInit.IsOk() )
1545 {
1546 ptrData->SetColour(colInit);
7c072018 1547 }
c51deffc 1548
7c072018 1549 wxColour colRet;
e6ef9ea4 1550 wxColourDialog dialog(parent, ptrData);
76b49cf4 1551 if (!caption.empty())
f14d6dd1 1552 dialog.SetTitle(caption);
7c072018
VZ
1553 if ( dialog.ShowModal() == wxID_OK )
1554 {
e6ef9ea4
VZ
1555 *ptrData = dialog.GetColourData();
1556 colRet = ptrData->GetColour();
1557 s_strColourData = ptrData->ToString();
7c072018 1558 }
e6ef9ea4 1559 //else: leave colRet invalid
7c072018
VZ
1560
1561 return colRet;
c51deffc 1562}
bc385ba9 1563
7c072018 1564#endif // wxUSE_COLOURDLG
bc385ba9 1565
7c072018
VZ
1566#if wxUSE_FONTDLG
1567
f14d6dd1 1568wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption)
bc385ba9 1569{
7c072018
VZ
1570 wxFontData data;
1571 if ( fontInit.Ok() )
bc385ba9 1572 {
7c072018
VZ
1573 data.SetInitialFont(fontInit);
1574 }
bc385ba9 1575
7c072018
VZ
1576 wxFont fontRet;
1577 wxFontDialog dialog(parent, data);
76b49cf4 1578 if (!caption.empty())
f14d6dd1 1579 dialog.SetTitle(caption);
7c072018
VZ
1580 if ( dialog.ShowModal() == wxID_OK )
1581 {
1582 fontRet = dialog.GetFontData().GetChosenFont();
1583 }
1584 //else: leave it invalid
bc385ba9 1585
7c072018 1586 return fontRet;
bc385ba9
VZ
1587}
1588
7c072018 1589#endif // wxUSE_FONTDLG
2b5f62a0 1590
7c072018
VZ
1591// ----------------------------------------------------------------------------
1592// wxSafeYield and supporting functions
1593// ----------------------------------------------------------------------------
2b5f62a0 1594
7c072018
VZ
1595void wxEnableTopLevelWindows(bool enable)
1596{
df5168c4 1597 wxWindowList::compatibility_iterator node;
7c072018
VZ
1598 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1599 node->GetData()->Enable(enable);
1600}
2b5f62a0 1601
2ecd1756
VZ
1602wxWindowDisabler::wxWindowDisabler(bool disable)
1603{
1604 m_disabled = disable;
1605 if ( disable )
1606 DoDisable();
1607}
1608
7c072018 1609wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
2ecd1756
VZ
1610{
1611 m_disabled = true;
1612 DoDisable(winToSkip);
1613}
1614
1615void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
7c072018
VZ
1616{
1617 // remember the top level windows which were already disabled, so that we
1618 // don't reenable them later
1619 m_winDisabled = NULL;
1620
df5168c4 1621 wxWindowList::compatibility_iterator node;
7c072018 1622 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
2b5f62a0 1623 {
7c072018
VZ
1624 wxWindow *winTop = node->GetData();
1625 if ( winTop == winToSkip )
1626 continue;
2b5f62a0 1627
7c072018
VZ
1628 // we don't need to disable the hidden or already disabled windows
1629 if ( winTop->IsEnabled() && winTop->IsShown() )
2b5f62a0 1630 {
7c072018 1631 winTop->Disable();
2b5f62a0
VZ
1632 }
1633 else
1634 {
7c072018
VZ
1635 if ( !m_winDisabled )
1636 {
1637 m_winDisabled = new wxWindowList;
1638 }
1639
1640 m_winDisabled->Append(winTop);
2b5f62a0
VZ
1641 }
1642 }
2b5f62a0
VZ
1643}
1644
7c072018 1645wxWindowDisabler::~wxWindowDisabler()
cd6ce4a9 1646{
2ecd1756
VZ
1647 if ( !m_disabled )
1648 return;
1649
df5168c4 1650 wxWindowList::compatibility_iterator node;
7c072018 1651 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
cd6ce4a9 1652 {
7c072018
VZ
1653 wxWindow *winTop = node->GetData();
1654 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
cd6ce4a9 1655 {
7c072018 1656 winTop->Enable();
cd6ce4a9 1657 }
7c072018 1658 //else: had been already disabled, don't reenable
cd6ce4a9 1659 }
f6bcfd97 1660
7c072018 1661 delete m_winDisabled;
f6bcfd97
BP
1662}
1663
7c072018
VZ
1664// Yield to other apps/messages and disable user input to all windows except
1665// the given one
1666bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
f6bcfd97 1667{
7c072018 1668 wxWindowDisabler wd(win);
21709999 1669
7c072018
VZ
1670 bool rc;
1671 if (onlyIfNeeded)
1672 rc = wxYieldIfNeeded();
1673 else
1674 rc = wxYield();
8461e4c2 1675
7c072018 1676 return rc;
8461e4c2
VZ
1677}
1678
7c072018
VZ
1679// Don't synthesize KeyUp events holding down a key and producing KeyDown
1680// events with autorepeat. On by default and always on in wxMSW. wxGTK version
1681// in utilsgtk.cpp.
1682#ifndef __WXGTK__
1683bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
8461e4c2 1684{
cb719f2e 1685 return true; // detectable auto-repeat is the only mode MSW supports
8461e4c2 1686}
7c072018
VZ
1687#endif // !wxGTK
1688
1689#endif // wxUSE_GUI