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