]> git.saurik.com Git - wxWidgets.git/blame - src/common/utilscmn.cpp
use guard classes automatically restoring the old state in their dtor instead of...
[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
08873d36
VZ
193void wxUsleep(unsigned long milliseconds)
194{
195 wxMilliSleep(milliseconds);
196}
197
7c072018
VZ
198const wxChar *wxGetInstallPrefix()
199{
200 wxString prefix;
201
202 if ( wxGetEnv(wxT("WXPREFIX"), &prefix) )
203 return prefix.c_str();
204
205#ifdef wxINSTALL_PREFIX
206 return wxT(wxINSTALL_PREFIX);
207#else
525d8583 208 return wxEmptyString;
7c072018
VZ
209#endif
210}
211
212wxString wxGetDataDir()
213{
10f206ad
RL
214 wxString dir = wxGetInstallPrefix();
215 dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx");
7c072018
VZ
216 return dir;
217}
e90c1d2a 218
8bb6b2c0 219bool wxIsPlatformLittleEndian()
2739d4f0 220{
8bb6b2c0
VZ
221 // Are we little or big endian? This method is from Harbison & Steele.
222 union
223 {
224 long l;
225 char c[sizeof(long)];
226 } u;
227 u.l = 1;
228
229 return u.c[0] == 1;
2739d4f0 230}
1e6feb95 231
8bb6b2c0 232
fad92e2f
FM
233// ----------------------------------------------------------------------------
234// wxPlatform
235// ----------------------------------------------------------------------------
236
230c9077
JS
237/*
238 * Class to make it easier to specify platform-dependent values
239 */
240
241wxArrayInt* wxPlatform::sm_customPlatforms = NULL;
242
4bfec179 243void wxPlatform::Copy(const wxPlatform& platform)
230c9077 244{
4bfec179
JS
245 m_longValue = platform.m_longValue;
246 m_doubleValue = platform.m_doubleValue;
247 m_stringValue = platform.m_stringValue;
248}
249
250wxPlatform wxPlatform::If(int platform, long value)
251{
252 if (Is(platform))
253 return wxPlatform(value);
254 else
255 return wxPlatform();
256}
257
258wxPlatform wxPlatform::IfNot(int platform, long value)
259{
260 if (!Is(platform))
261 return wxPlatform(value);
262 else
263 return wxPlatform();
264}
265
266wxPlatform& wxPlatform::ElseIf(int platform, long value)
267{
268 if (Is(platform))
230c9077
JS
269 m_longValue = value;
270 return *this;
271}
272
4bfec179 273wxPlatform& wxPlatform::ElseIfNot(int platform, long value)
230c9077 274{
4bfec179 275 if (!Is(platform))
230c9077
JS
276 m_longValue = value;
277 return *this;
278}
279
4bfec179 280wxPlatform wxPlatform::If(int platform, double value)
230c9077 281{
4bfec179
JS
282 if (Is(platform))
283 return wxPlatform(value);
284 else
285 return wxPlatform();
286}
287
288wxPlatform wxPlatform::IfNot(int platform, double value)
289{
290 if (!Is(platform))
291 return wxPlatform(value);
292 else
293 return wxPlatform();
294}
295
296wxPlatform& wxPlatform::ElseIf(int platform, double value)
297{
298 if (Is(platform))
230c9077
JS
299 m_doubleValue = value;
300 return *this;
301}
302
4bfec179 303wxPlatform& wxPlatform::ElseIfNot(int platform, double value)
230c9077 304{
4bfec179 305 if (!Is(platform))
230c9077
JS
306 m_doubleValue = value;
307 return *this;
308}
309
4bfec179
JS
310wxPlatform wxPlatform::If(int platform, const wxString& value)
311{
312 if (Is(platform))
313 return wxPlatform(value);
314 else
315 return wxPlatform();
316}
317
318wxPlatform wxPlatform::IfNot(int platform, const wxString& value)
319{
320 if (!Is(platform))
321 return wxPlatform(value);
322 else
323 return wxPlatform();
324}
325
326wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value)
230c9077 327{
4bfec179 328 if (Is(platform))
230c9077
JS
329 m_stringValue = value;
330 return *this;
331}
332
4bfec179 333wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value)
230c9077 334{
4bfec179 335 if (!Is(platform))
230c9077
JS
336 m_stringValue = value;
337 return *this;
338}
339
4bfec179 340wxPlatform& wxPlatform::Else(long value)
230c9077
JS
341{
342 m_longValue = value;
343 return *this;
344}
345
4bfec179 346wxPlatform& wxPlatform::Else(double value)
230c9077
JS
347{
348 m_doubleValue = value;
349 return *this;
350}
351
4bfec179 352wxPlatform& wxPlatform::Else(const wxString& value)
230c9077
JS
353{
354 m_stringValue = value;
355 return *this;
356}
357
358void wxPlatform::AddPlatform(int platform)
359{
360 if (!sm_customPlatforms)
361 sm_customPlatforms = new wxArrayInt;
362 sm_customPlatforms->Add(platform);
363}
364
365void wxPlatform::ClearPlatforms()
366{
367 delete sm_customPlatforms;
368 sm_customPlatforms = NULL;
369}
370
371/// Function for testing current platform
372
4bfec179 373bool wxPlatform::Is(int platform)
230c9077
JS
374{
375#ifdef __WXMSW__
216c3543 376 if (platform == wxOS_WINDOWS)
230c9077
JS
377 return true;
378#endif
379#ifdef __WXWINCE__
216c3543 380 if (platform == wxOS_WINDOWS_CE)
230c9077
JS
381 return true;
382#endif
a6e8c584
WS
383
384#if 0
385
386// FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols
387
230c9077
JS
388#if defined(__WXWINCE__) && defined(__POCKETPC__)
389 if (platform == wxWinPocketPC)
390 return true;
391#endif
392#if defined(__WXWINCE__) && defined(__SMARTPHONE__)
6aa68c25 393 if (platform == wxWinSmartPhone)
230c9077
JS
394 return true;
395#endif
a6e8c584
WS
396
397#endif
398
230c9077 399#ifdef __WXGTK__
216c3543 400 if (platform == wxPORT_GTK)
230c9077
JS
401 return true;
402#endif
403#ifdef __WXMAC__
216c3543 404 if (platform == wxPORT_MAC)
230c9077
JS
405 return true;
406#endif
407#ifdef __WXX11__
216c3543 408 if (platform == wxPORT_X11)
230c9077
JS
409 return true;
410#endif
411#ifdef __UNIX__
216c3543 412 if (platform == wxOS_UNIX)
230c9077
JS
413 return true;
414#endif
415#ifdef __WXMGL__
216c3543 416 if (platform == wxPORT_MGL)
230c9077
JS
417 return true;
418#endif
8ab09e65
SN
419#ifdef __OS2__
420 if (platform == wxOS_OS2)
421 return true;
422#endif
423#ifdef __WXPM__
424 if (platform == wxPORT_PM)
230c9077
JS
425 return true;
426#endif
55d452c6 427#ifdef __WXCOCOA__
216c3543 428 if (platform == wxPORT_MAC)
230c9077
JS
429 return true;
430#endif
431
432 if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND)
433 return true;
434
435 return false;
436}
437
e90c1d2a 438// ----------------------------------------------------------------------------
7c072018 439// network and user id functions
e90c1d2a 440// ----------------------------------------------------------------------------
c801d85f 441
7c072018
VZ
442// Get Full RFC822 style email address
443bool wxGetEmailAddress(wxChar *address, int maxSize)
c801d85f 444{
7c072018
VZ
445 wxString email = wxGetEmailAddress();
446 if ( !email )
cb719f2e 447 return false;
c801d85f 448
9d4943cd 449 wxStrlcpy(address, email.t_str(), maxSize);
7c072018 450
cb719f2e 451 return true;
c801d85f
KB
452}
453
7c072018 454wxString wxGetEmailAddress()
47bc1060 455{
7c072018 456 wxString email;
974e8d94 457
7c072018 458 wxString host = wxGetFullHostName();
4055ed82 459 if ( !host.empty() )
1e6feb95 460 {
7c072018 461 wxString user = wxGetUserId();
4055ed82 462 if ( !user.empty() )
1e6feb95 463 {
7c072018 464 email << user << wxT('@') << host;
974e8d94 465 }
974e8d94
VZ
466 }
467
7c072018 468 return email;
974e8d94
VZ
469}
470
7c072018 471wxString wxGetUserId()
c801d85f 472{
7c072018 473 static const int maxLoginLen = 256; // FIXME arbitrary number
c801d85f 474
7c072018 475 wxString buf;
4c3ebca9 476 bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen);
c801d85f 477
7c072018
VZ
478 if ( !ok )
479 buf.Empty();
c801d85f 480
7c072018 481 return buf;
c801d85f
KB
482}
483
7c072018 484wxString wxGetUserName()
c801d85f 485{
7c072018 486 static const int maxUserNameLen = 1024; // FIXME arbitrary number
1e6feb95 487
7c072018 488 wxString buf;
4c3ebca9 489 bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen);
7c072018
VZ
490
491 if ( !ok )
492 buf.Empty();
493
494 return buf;
59a12e90
JS
495}
496
7c072018 497wxString wxGetHostName()
59a12e90 498{
7c072018 499 static const size_t hostnameSize = 257;
c67d6888 500
7c072018 501 wxString buf;
4c3ebca9 502 bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
59a12e90 503
7c072018
VZ
504 if ( !ok )
505 buf.Empty();
59a12e90 506
7c072018 507 return buf;
59a12e90
JS
508}
509
7c072018 510wxString wxGetFullHostName()
59a12e90 511{
7c072018 512 static const size_t hostnameSize = 257;
c801d85f 513
7c072018 514 wxString buf;
4c3ebca9 515 bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
7c072018
VZ
516
517 if ( !ok )
518 buf.Empty();
c801d85f 519
7c072018
VZ
520 return buf;
521}
c801d85f 522
7c072018
VZ
523wxString wxGetHomeDir()
524{
525 wxString home;
526 wxGetHomeDir(&home);
c801d85f 527
7c072018
VZ
528 return home;
529}
c801d85f 530
c801d85f
KB
531#if 0
532
7c072018 533wxString wxGetCurrentDir()
c801d85f 534{
7c072018
VZ
535 wxString dir;
536 size_t len = 1024;
537 bool ok;
538 do
539 {
540 ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL;
541 dir.UngetWriteBuf();
c801d85f 542
7c072018
VZ
543 if ( !ok )
544 {
545 if ( errno != ERANGE )
546 {
547 wxLogSysError(_T("Failed to get current directory"));
c801d85f 548
7c072018
VZ
549 return wxEmptyString;
550 }
3f4a0c5b 551 else
7c072018
VZ
552 {
553 // buffer was too small, retry with a larger one
554 len *= 2;
555 }
3f4a0c5b 556 }
7c072018
VZ
557 //else: ok
558 } while ( !ok );
c801d85f 559
7c072018 560 return dir;
c801d85f
KB
561}
562
7c072018 563#endif // 0
e90c1d2a
VZ
564
565// ----------------------------------------------------------------------------
7c072018 566// wxExecute
e90c1d2a 567// ----------------------------------------------------------------------------
ead7ce10 568
7c072018
VZ
569// wxDoExecuteWithCapture() helper: reads an entire stream into one array
570//
cb719f2e 571// returns true if ok, false if error
7c072018
VZ
572#if wxUSE_STREAMS
573static bool ReadAll(wxInputStream *is, wxArrayString& output)
dfad0599 574{
cb719f2e 575 wxCHECK_MSG( is, false, _T("NULL stream in wxExecute()?") );
dfad0599 576
7c072018
VZ
577 // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
578 is->Reset();
1e6feb95 579
7c072018 580 wxTextInputStream tis(*is);
1e6feb95 581
8bdc8a9c 582 for ( ;; )
d2f50933 583 {
7c072018 584 wxString line = tis.ReadLine();
8bdc8a9c
VZ
585
586 // check for EOF before other errors as it's not really an error
7c072018 587 if ( is->Eof() )
8bdc8a9c
VZ
588 {
589 // add the last, possibly incomplete, line
590 if ( !line.empty() )
591 output.Add(line);
7c072018 592 break;
8bdc8a9c 593 }
7c072018 594
8bdc8a9c 595 // any other error is fatal
7c072018 596 if ( !*is )
8bdc8a9c
VZ
597 return false;
598
599 output.Add(line);
d2f50933
VZ
600 }
601
8bdc8a9c 602 return true;
dfad0599 603}
7c072018 604#endif // wxUSE_STREAMS
d2f50933 605
7c072018
VZ
606// this is a private function because it hasn't a clean interface: the first
607// array is passed by reference, the second by pointer - instead we have 2
608// public versions of wxExecute() below
609static long wxDoExecuteWithCapture(const wxString& command,
610 wxArrayString& output,
4d172154
VZ
611 wxArrayString* error,
612 int flags)
d2f50933 613{
7c072018
VZ
614 // create a wxProcess which will capture the output
615 wxProcess *process = new wxProcess;
616 process->Redirect();
dfad0599 617
4d172154 618 long rc = wxExecute(command, wxEXEC_SYNC | flags, process);
1e6feb95 619
7c072018
VZ
620#if wxUSE_STREAMS
621 if ( rc != -1 )
bf31fa26 622 {
7c072018
VZ
623 if ( !ReadAll(process->GetInputStream(), output) )
624 rc = -1;
91b4c08d 625
7c072018
VZ
626 if ( error )
627 {
628 if ( !ReadAll(process->GetErrorStream(), *error) )
629 rc = -1;
630 }
91b4c08d 631
7c072018 632 }
e70ba80d
WS
633#else
634 wxUnusedVar(output);
635 wxUnusedVar(error);
636#endif // wxUSE_STREAMS/!wxUSE_STREAMS
91b4c08d 637
7c072018 638 delete process;
1e6feb95 639
7c072018 640 return rc;
7c072018 641}
bf31fa26 642
4d172154 643long wxExecute(const wxString& command, wxArrayString& output, int flags)
bf31fa26 644{
4d172154 645 return wxDoExecuteWithCapture(command, output, NULL, flags);
7c072018 646}
bf31fa26 647
7c072018
VZ
648long wxExecute(const wxString& command,
649 wxArrayString& output,
4d172154
VZ
650 wxArrayString& error,
651 int flags)
7c072018 652{
4d172154 653 return wxDoExecuteWithCapture(command, output, &error, flags);
bf31fa26
VZ
654}
655
c5f0d1f9 656// ----------------------------------------------------------------------------
fad92e2f 657// Id functions
c5f0d1f9
DE
658// ----------------------------------------------------------------------------
659
c5f0d1f9
DE
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 712#define SWAP(a, b, size) \
fad92e2f
FM
713 do \
714 { \
715 register size_t __size = (size); \
716 register char *__a = (a), *__b = (b); \
11fe6505 717 do \
fad92e2f
FM
718 { \
719 char __tmp = *__a; \
11fe6505 720 *__a++ = *__b; \
fad92e2f
FM
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
fad92e2f 925#endif // wxUSE_BASE
fe5f448f
RR
926
927
c5f0d1f9
DE
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");
62a6f21a
VZ
965#ifdef __WXWINCE__
966 sei.nShow = SW_SHOWNORMAL; // SW_SHOWDEFAULT not defined under CE (#10216)
967#else
58ac79d3 968 sei.nShow = SW_SHOWDEFAULT;
62a6f21a 969#endif
58ac79d3
VZ
970
971 // avoid Windows message box in case of error for consistency with
972 // wxLaunchDefaultBrowser() even if don't show the error ourselves in this
973 // function
974 sei.fMask = SEE_MASK_FLAG_NO_UI;
975
976 if ( ::ShellExecuteEx(&sei) )
f06832c1 977 return true;
1dea1566
RR
978#endif
979
f06832c1 980 return false;
1dea1566
RR
981}
982
498a1eeb
RN
983// ----------------------------------------------------------------------------
984// Launch default browser
985// ----------------------------------------------------------------------------
986
4263bab0
DE
987#ifdef __WXCOCOA__
988// Private method in Objective-C++ source file.
989bool wxCocoaLaunchDefaultBrowser(const wxString& url, int flags);
990#endif
991
f75e0c15 992static bool DoLaunchDefaultBrowser(const wxString& urlOrig, int flags)
498a1eeb 993{
42d0df00
VZ
994 wxUnusedVar(flags);
995
7999124f 996 // set the scheme of url to http if it does not have one
889fda0c 997 // RR: This doesn't work if the url is just a local path
7999124f 998 wxString url(urlOrig);
6f6dd276
VZ
999 wxURI uri(url);
1000 if ( !uri.HasScheme() )
d545f803
RR
1001 {
1002 if (wxFileExists(urlOrig))
1003 url.Prepend( wxT("file://") );
1004 else
1005 url.Prepend(wxT("http://"));
1006 }
889fda0c 1007
532d575b 1008
7999124f 1009#if defined(__WXMSW__)
5ccb95f6
WS
1010
1011#if wxUSE_IPC
42d0df00
VZ
1012 if ( flags & wxBROWSER_NEW_WINDOW )
1013 {
1014 // ShellExecuteEx() opens the URL in an existing window by default so
1015 // we can't use it if we need a new window
6f6dd276
VZ
1016 wxRegKey key(wxRegKey::HKCR, uri.GetScheme() + _T("\\shell\\open"));
1017 if ( !key.Exists() )
1018 {
1019 // try default browser, it must be registered at least for http URLs
1020 key.SetName(wxRegKey::HKCR, _T("http\\shell\\open"));
1021 }
1022
42d0df00
VZ
1023 if ( key.Exists() )
1024 {
1025 wxRegKey keyDDE(key, wxT("DDEExec"));
1026 if ( keyDDE.Exists() )
1027 {
42d0df00
VZ
1028 // we only know the syntax of WWW_OpenURL DDE request for IE,
1029 // optimistically assume that all other browsers are compatible
1030 // with it
19abad60
VZ
1031 static const wxChar *TOPIC_OPEN_URL = wxT("WWW_OpenURL");
1032 wxString ddeCmd;
f524b093 1033 wxRegKey keyTopic(keyDDE, wxT("topic"));
53b849ea
VZ
1034 bool ok = keyTopic.Exists() &&
1035 keyTopic.QueryDefaultValue() == TOPIC_OPEN_URL;
42d0df00
VZ
1036 if ( ok )
1037 {
588c80de 1038 ddeCmd = keyDDE.QueryDefaultValue();
42d0df00
VZ
1039 ok = !ddeCmd.empty();
1040 }
1041
1042 if ( ok )
1043 {
1044 // for WWW_OpenURL, the index of the window to open the URL
1045 // in is -1 (meaning "current") by default, replace it with
1046 // 0 which means "new" (see KB article 160957)
1047 ok = ddeCmd.Replace(wxT("-1"), wxT("0"),
7929902d 1048 false /* only first occurrence */) == 1;
42d0df00
VZ
1049 }
1050
1051 if ( ok )
1052 {
1053 // and also replace the parameters: the topic should
1054 // contain a placeholder for the URL
1055 ok = ddeCmd.Replace(wxT("%1"), url, false) == 1;
1056 }
1057
1058 if ( ok )
1059 {
1060 // try to send it the DDE request now but ignore the errors
1061 wxLogNull noLog;
1062
1063 const wxString ddeServer = wxRegKey(keyDDE, wxT("application"));
19abad60 1064 if ( wxExecuteDDE(ddeServer, TOPIC_OPEN_URL, ddeCmd) )
42d0df00
VZ
1065 return true;
1066
1067 // this is not necessarily an error: maybe browser is
1068 // simply not running, but no matter, in any case we're
1069 // going to launch it using ShellExecuteEx() below now and
1070 // we shouldn't try to open a new window if we open a new
1071 // browser anyhow
1072 }
1073 }
1074 }
1075 }
5ccb95f6 1076#endif // wxUSE_IPC
42d0df00 1077
7999124f
VZ
1078 WinStruct<SHELLEXECUTEINFO> sei;
1079 sei.lpFile = url.c_str();
1080 sei.lpVerb = _T("open");
1081 sei.nShow = SW_SHOWNORMAL;
f524b093 1082 sei.fMask = SEE_MASK_FLAG_NO_UI; // we give error message ourselves
498a1eeb 1083
2190f6aa 1084 if ( ::ShellExecuteEx(&sei) )
7999124f 1085 return true;
4263bab0
DE
1086#elif defined(__WXCOCOA__)
1087 // NOTE: We need to call the real implementation from src/cocoa/utils.mm
1088 // because the code must use Objective-C features.
1089 return wxCocoaLaunchDefaultBrowser(url, flags);
c933e267 1090#elif defined(__WXMAC__) && !defined(__WXOSX_IPHONE__)
5d713a75
SC
1091 wxCFRef< CFURLRef > curl( CFURLCreateWithString( kCFAllocatorDefault,
1092 wxCFStringRef( url ), NULL ) );
1093 OSStatus err = LSOpenCFURLRef( curl , NULL );
f14d6dd1 1094
13a1e96f
DS
1095 if (err == noErr)
1096 {
f14d6dd1
JS
1097 return true;
1098 }
1099 else
1100 {
5d713a75 1101 wxLogDebug(wxT("Browser Launch error %d"), (int) err);
f14d6dd1
JS
1102 return false;
1103 }
f728025e 1104#else
889fda0c
RR
1105 // (non-Mac, non-MSW)
1106
1107#ifdef __UNIX__
17ede0b1 1108
ae46a7fd
VS
1109 // Our best best is to use xdg-open from freedesktop.org cross-desktop
1110 // compatibility suite xdg-utils
1111 // (see http://portland.freedesktop.org/wiki/) -- this is installed on
1112 // most modern distributions and may be tweaked by them to handle
1113 // distribution specifics. Only if that fails, try to find the right
1114 // browser ourselves.
1115 wxString path, xdg_open;
1116 if ( wxGetEnv("PATH", &path) &&
1117 wxFindFileInPath(&xdg_open, path, "xdg-open") )
1118 {
1119 if ( wxExecute(xdg_open + " " + url) )
1120 return true;
1121 }
1122
17ede0b1
RR
1123 wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment();
1124
1125 // GNOME and KDE desktops have some applications which should be always installed
1126 // together with their main parts, which give us the
1127 if (desktop == wxT("GNOME"))
889fda0c
RR
1128 {
1129 wxArrayString errors;
1130 wxArrayString output;
17ede0b1
RR
1131
1132 // gconf will tell us the path of the application to use as browser
1133 long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"),
1134 output, errors, wxEXEC_NODISABLE );
889fda0c
RR
1135 if (res >= 0 && errors.GetCount() == 0)
1136 {
1137 wxString cmd = output[0];
1138 cmd << _T(' ') << url;
1139 if (wxExecute(cmd))
1140 return true;
1141 }
1142 }
17ede0b1
RR
1143 else if (desktop == wxT("KDE"))
1144 {
1145 // kfmclient directly opens the given URL
1146 if (wxExecute(wxT("kfmclient openURL ") + url))
1147 return true;
1148 }
889fda0c
RR
1149#endif
1150
13a1e96f
DS
1151 bool ok = false;
1152 wxString cmd;
1153
1b1b5318 1154#if wxUSE_MIMETYPE
13a1e96f 1155 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html"));
7999124f 1156 if ( ft )
657a7545 1157 {
7999124f
VZ
1158 wxString mt;
1159 ft->GetMimeType(&mt);
498a1eeb 1160
13a1e96f 1161 ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
7999124f 1162 delete ft;
498a1eeb 1163 }
1b1b5318 1164#endif // wxUSE_MIMETYPE
13a1e96f
DS
1165
1166 if ( !ok || cmd.empty() )
2830b4a4 1167 {
13a1e96f
DS
1168 // fallback to checking for the BROWSER environment variable
1169 cmd = wxGetenv(wxT("BROWSER"));
1170 if ( !cmd.empty() )
1171 cmd << _T(' ') << url;
2830b4a4 1172 }
13a1e96f
DS
1173
1174 ok = ( !cmd.empty() && wxExecute(cmd) );
1175 if (ok)
1176 return ok;
1177
1178 // no file type for HTML extension
5519074c 1179 wxLogError(_("No default application configured for HTML files."));
13a1e96f 1180
7999124f 1181#endif // !wxUSE_MIMETYPE && !__WXMSW__
532d575b 1182
5519074c 1183 wxLogSysError(_("Failed to open URL \"%s\" in default browser."),
7999124f 1184 url.c_str());
657a7545 1185
7999124f 1186 return false;
498a1eeb
RN
1187}
1188
f75e0c15
VZ
1189bool wxLaunchDefaultBrowser(const wxString& url, int flags)
1190{
1191 if ( flags & wxBROWSER_NOBUSYCURSOR )
1192 return DoLaunchDefaultBrowser(url, flags);
1193
1194 wxBusyCursor bc;
1195 return DoLaunchDefaultBrowser(url, flags);
1196}
1197
e90c1d2a 1198// ----------------------------------------------------------------------------
7c072018 1199// Menu accelerators related functions
e90c1d2a
VZ
1200// ----------------------------------------------------------------------------
1201
7c072018 1202wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out)
e90c1d2a 1203{
9a6384ca 1204#if wxUSE_MENUS
52af3158 1205 wxString s = wxMenuItem::GetLabelText(in);
9a6384ca
WS
1206#else
1207 wxString str(in);
1208 wxString s = wxStripMenuCodes(str);
1209#endif // wxUSE_MENUS
7c072018
VZ
1210 if ( out )
1211 {
1212 // go smash their buffer if it's not big enough - I love char * params
1213 memcpy(out, s.c_str(), s.length() * sizeof(wxChar));
1214 }
1215 else
1216 {
f526f752
MB
1217 out = new wxChar[s.length() + 1];
1218 wxStrcpy(out, s.c_str());
7c072018
VZ
1219 }
1220
1221 return out;
e90c1d2a
VZ
1222}
1223
74639764 1224wxString wxStripMenuCodes(const wxString& in, int flags)
e90c1d2a 1225{
74639764
VZ
1226 wxASSERT_MSG( flags, _T("this is useless to call without any flags") );
1227
7c072018 1228 wxString out;
79f585d9 1229
7c072018
VZ
1230 size_t len = in.length();
1231 out.reserve(len);
79f585d9 1232
7c072018
VZ
1233 for ( size_t n = 0; n < len; n++ )
1234 {
1235 wxChar ch = in[n];
74639764 1236 if ( (flags & wxStrip_Mnemonics) && ch == _T('&') )
cd6ce4a9 1237 {
7c072018
VZ
1238 // skip it, it is used to introduce the accel char (or to quote
1239 // itself in which case it should still be skipped): note that it
1240 // can't be the last character of the string
1241 if ( ++n == len )
79f585d9 1242 {
7c072018
VZ
1243 wxLogDebug(_T("Invalid menu string '%s'"), in.c_str());
1244 }
1245 else
1246 {
1247 // use the next char instead
1248 ch = in[n];
79f585d9 1249 }
cd6ce4a9 1250 }
74639764 1251 else if ( (flags & wxStrip_Accel) && ch == _T('\t') )
79f585d9 1252 {
7c072018
VZ
1253 // everything after TAB is accel string, exit the loop
1254 break;
79f585d9 1255 }
7c072018
VZ
1256
1257 out += ch;
225fe9d6
VZ
1258 }
1259
7c072018 1260 return out;
cd6ce4a9
VZ
1261}
1262
cbc66a27 1263// ----------------------------------------------------------------------------
7c072018 1264// Window search functions
cbc66a27
VZ
1265// ----------------------------------------------------------------------------
1266
7c072018
VZ
1267/*
1268 * If parent is non-NULL, look through children for a label or title
1269 * matching the specified string. If NULL, look through all top-level windows.
1270 *
1271 */
e2a6f233 1272
7c072018
VZ
1273wxWindow *
1274wxFindWindowByLabel (const wxString& title, wxWindow * parent)
134677bd 1275{
7c072018
VZ
1276 return wxWindow::FindWindowByLabel( title, parent );
1277}
b829bf55 1278
b829bf55 1279
7c072018
VZ
1280/*
1281 * If parent is non-NULL, look through children for a name
1282 * matching the specified string. If NULL, look through all top-level windows.
1283 *
1284 */
134677bd 1285
7c072018
VZ
1286wxWindow *
1287wxFindWindowByName (const wxString& name, wxWindow * parent)
2c18f21d 1288{
7c072018 1289 return wxWindow::FindWindowByName( name, parent );
2c18f21d
VS
1290}
1291
cb719f2e 1292// Returns menu item id or wxNOT_FOUND if none.
7c072018 1293int
8d22935d
VZ
1294wxFindMenuItemId(wxFrame *frame,
1295 const wxString& menuString,
1296 const wxString& itemString)
e2a6f233 1297{
7c072018 1298#if wxUSE_MENUS
9a6384ca
WS
1299 wxMenuBar *menuBar = frame->GetMenuBar ();
1300 if ( menuBar )
1301 return menuBar->FindMenuItem (menuString, itemString);
8d22935d
VZ
1302#else // !wxUSE_MENUS
1303 wxUnusedVar(frame);
1304 wxUnusedVar(menuString);
1305 wxUnusedVar(itemString);
1306#endif // wxUSE_MENUS/!wxUSE_MENUS
0fb67cd1 1307
9a6384ca 1308 return wxNOT_FOUND;
e2a6f233
JS
1309}
1310
7c072018
VZ
1311// Try to find the deepest child that contains 'pt'.
1312// We go backwards, to try to allow for controls that are spacially
1313// within other controls, but are still siblings (e.g. buttons within
1314// static boxes). Static boxes are likely to be created _before_ controls
1315// that sit inside them.
1316wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt)
e2a6f233 1317{
7c072018
VZ
1318 if (!win->IsShown())
1319 return NULL;
0fb67cd1 1320
7c072018
VZ
1321 // Hack for wxNotebook case: at least in wxGTK, all pages
1322 // claim to be shown, so we must only deal with the selected one.
1323#if wxUSE_NOTEBOOK
1324 if (win->IsKindOf(CLASSINFO(wxNotebook)))
e2a6f233 1325 {
7c072018
VZ
1326 wxNotebook* nb = (wxNotebook*) win;
1327 int sel = nb->GetSelection();
1328 if (sel >= 0)
1329 {
1330 wxWindow* child = nb->GetPage(sel);
1331 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1332 if (foundWin)
1333 return foundWin;
1334 }
e2a6f233 1335 }
7c072018 1336#endif
0fb67cd1 1337
df5168c4 1338 wxWindowList::compatibility_iterator node = win->GetChildren().GetLast();
7c072018
VZ
1339 while (node)
1340 {
1341 wxWindow* child = node->GetData();
1342 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1343 if (foundWin)
1344 return foundWin;
1345 node = node->GetPrevious();
1346 }
1347
1348 wxPoint pos = win->GetPosition();
1349 wxSize sz = win->GetSize();
7aa7d2d4 1350 if ( !win->IsTopLevel() && win->GetParent() )
7c072018
VZ
1351 {
1352 pos = win->GetParent()->ClientToScreen(pos);
1353 }
1354
1355 wxRect rect(pos, sz);
22a35096 1356 if (rect.Contains(pt))
7c072018 1357 return win;
622eb786
VZ
1358
1359 return NULL;
0fb67cd1
VZ
1360}
1361
7c072018 1362wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt)
0fb67cd1 1363{
7c072018
VZ
1364 // Go backwards through the list since windows
1365 // on top are likely to have been appended most
1366 // recently.
df5168c4 1367 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast();
7c072018
VZ
1368 while (node)
1369 {
1370 wxWindow* win = node->GetData();
1371 wxWindow* found = wxFindWindowAtPoint(win, pt);
1372 if (found)
1373 return found;
1374 node = node->GetPrevious();
1375 }
1376 return NULL;
1377}
0fb67cd1 1378
7c072018
VZ
1379// ----------------------------------------------------------------------------
1380// GUI helpers
1381// ----------------------------------------------------------------------------
0fb67cd1 1382
7c072018
VZ
1383/*
1384 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
1385 * since otherwise the generic code may be pulled in unnecessarily.
1386 */
0fb67cd1 1387
7c072018 1388#if wxUSE_MSGDLG
0fb67cd1 1389
7c072018
VZ
1390int wxMessageBox(const wxString& message, const wxString& caption, long style,
1391 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
0fb67cd1 1392{
53a6ac21
DS
1393 long decorated_style = style;
1394
1395 if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 )
1396 {
1397 decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ;
1398 }
1399
1400 wxMessageDialog dialog(parent, message, caption, decorated_style);
0fb67cd1 1401
7c072018
VZ
1402 int ans = dialog.ShowModal();
1403 switch ( ans )
1404 {
1405 case wxID_OK:
1406 return wxOK;
1407 case wxID_YES:
1408 return wxYES;
1409 case wxID_NO:
1410 return wxNO;
1411 case wxID_CANCEL:
1412 return wxCANCEL;
1413 }
0fb67cd1 1414
7c072018 1415 wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") );
0fb67cd1 1416
7c072018 1417 return wxCANCEL;
e2a6f233
JS
1418}
1419
8cf304f8
VZ
1420void wxInfoMessageBox(wxWindow* parent)
1421{
1422 // don't translate these strings, they're for diagnostics purposes only
1423 wxString msg;
1424 msg.Printf(_T("wxWidgets Library (%s port)\n")
1425 _T("Version %d.%d.%d%s%s, compiled at %s %s\n")
1426 _T("Runtime version of toolkit used is %d.%d.%s\n")
6edd8250 1427 _T("Copyright (c) 1995-2009 wxWidgets team"),
8cf304f8
VZ
1428 wxPlatformInfo::Get().GetPortIdName().c_str(),
1429 wxMAJOR_VERSION,
1430 wxMINOR_VERSION,
1431 wxRELEASE_NUMBER,
1432#if wxUSE_UNICODE
1433 L" (Unicode)",
1434#else
1435 wxEmptyString,
1436#endif
1437#ifdef __WXDEBUG__
1438 _T(" Debug build"),
1439#else
1440 wxEmptyString,
1441#endif
1442 __TDATE__,
1443 __TTIME__,
1444 wxPlatformInfo::Get().GetToolkitMajorVersion(),
1445 wxPlatformInfo::Get().GetToolkitMinorVersion(),
1446#ifdef __WXGTK__
6ed3db08
VZ
1447 wxString::Format("\nThe compile-time GTK+ version is %d.%d.%d.",
1448 GTK_MAJOR_VERSION,
1449 GTK_MINOR_VERSION,
1450 GTK_MICRO_VERSION).c_str()
8cf304f8
VZ
1451#else
1452 wxEmptyString
1453#endif
1454 );
1455 wxMessageBox(msg, _T("wxWidgets information"),
1456 wxICON_INFORMATION | wxOK,
1457 parent);
1458}
1459
7c072018 1460#endif // wxUSE_MSGDLG
518b5d2f 1461
7c072018 1462#if wxUSE_TEXTDLG
518b5d2f 1463
7c072018
VZ
1464wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
1465 const wxString& defaultValue, wxWindow *parent,
13d13a9e 1466 wxCoord x, wxCoord y, bool centre )
7c072018
VZ
1467{
1468 wxString str;
13d13a9e
WS
1469 long style = wxTextEntryDialogStyle;
1470
1471 if (centre)
1472 style |= wxCENTRE;
1473 else
1474 style &= ~wxCENTRE;
1475
1476 wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y));
1477
7c072018
VZ
1478 if (dialog.ShowModal() == wxID_OK)
1479 {
1480 str = dialog.GetValue();
1481 }
0fb67cd1 1482
7c072018 1483 return str;
518b5d2f
VZ
1484}
1485
7c072018
VZ
1486wxString wxGetPasswordFromUser(const wxString& message,
1487 const wxString& caption,
1488 const wxString& defaultValue,
b3bb2a74
KH
1489 wxWindow *parent,
1490 wxCoord x, wxCoord y, bool centre )
96c5bd7f 1491{
7c072018 1492 wxString str;
b3bb2a74
KH
1493 long style = wxTextEntryDialogStyle;
1494
1495 if (centre)
1496 style |= wxCENTRE;
1497 else
1498 style &= ~wxCENTRE;
1499
12cfa304
KH
1500 wxPasswordEntryDialog dialog(parent, message, caption, defaultValue,
1501 style, wxPoint(x, y));
7c072018
VZ
1502 if ( dialog.ShowModal() == wxID_OK )
1503 {
1504 str = dialog.GetValue();
1505 }
96c5bd7f 1506
7c072018
VZ
1507 return str;
1508}
96c5bd7f 1509
7c072018 1510#endif // wxUSE_TEXTDLG
96c5bd7f 1511
7c072018 1512#if wxUSE_COLOURDLG
96c5bd7f 1513
f75e0c15
VZ
1514wxColour wxGetColourFromUser(wxWindow *parent,
1515 const wxColour& colInit,
e6ef9ea4
VZ
1516 const wxString& caption,
1517 wxColourData *ptrData)
c51deffc 1518{
e6ef9ea4
VZ
1519 // contains serialized representation of wxColourData used the last time
1520 // the dialog was shown: we want to reuse it the next time in order to show
1521 // the same custom colours to the user (and we can't just have static
1522 // wxColourData itself because it's a GUI object and so should be destroyed
1523 // before GUI shutdown and doing it during static cleanup is too late)
1524 static wxString s_strColourData;
1525
7c072018 1526 wxColourData data;
e6ef9ea4 1527 if ( !ptrData )
7c072018 1528 {
e6ef9ea4
VZ
1529 ptrData = &data;
1530 if ( !s_strColourData.empty() )
1531 {
1532 if ( !data.FromString(s_strColourData) )
1533 {
1534 wxFAIL_MSG( "bug in wxColourData::FromString()?" );
1535 }
1536
1537#ifdef __WXMSW__
1538 // we don't get back the "choose full" flag value from the native
1539 // dialog and so we can't preserve it between runs, so we decide to
1540 // always use it as it seems better than not using it (user can
1541 // just ignore the extra controls in the dialog but having to click
1542 // a button each time to show them would be very annoying
1543 data.SetChooseFull(true);
1544#endif // __WXMSW__
1545 }
1546 }
1547
1548 if ( colInit.IsOk() )
1549 {
1550 ptrData->SetColour(colInit);
7c072018 1551 }
c51deffc 1552
7c072018 1553 wxColour colRet;
e6ef9ea4 1554 wxColourDialog dialog(parent, ptrData);
76b49cf4 1555 if (!caption.empty())
f14d6dd1 1556 dialog.SetTitle(caption);
7c072018
VZ
1557 if ( dialog.ShowModal() == wxID_OK )
1558 {
e6ef9ea4
VZ
1559 *ptrData = dialog.GetColourData();
1560 colRet = ptrData->GetColour();
1561 s_strColourData = ptrData->ToString();
7c072018 1562 }
e6ef9ea4 1563 //else: leave colRet invalid
7c072018
VZ
1564
1565 return colRet;
c51deffc 1566}
bc385ba9 1567
7c072018 1568#endif // wxUSE_COLOURDLG
bc385ba9 1569
7c072018
VZ
1570#if wxUSE_FONTDLG
1571
f14d6dd1 1572wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption)
bc385ba9 1573{
7c072018
VZ
1574 wxFontData data;
1575 if ( fontInit.Ok() )
bc385ba9 1576 {
7c072018
VZ
1577 data.SetInitialFont(fontInit);
1578 }
bc385ba9 1579
7c072018
VZ
1580 wxFont fontRet;
1581 wxFontDialog dialog(parent, data);
76b49cf4 1582 if (!caption.empty())
f14d6dd1 1583 dialog.SetTitle(caption);
7c072018
VZ
1584 if ( dialog.ShowModal() == wxID_OK )
1585 {
1586 fontRet = dialog.GetFontData().GetChosenFont();
1587 }
1588 //else: leave it invalid
bc385ba9 1589
7c072018 1590 return fontRet;
bc385ba9
VZ
1591}
1592
7c072018 1593#endif // wxUSE_FONTDLG
2b5f62a0 1594
7c072018
VZ
1595// ----------------------------------------------------------------------------
1596// wxSafeYield and supporting functions
1597// ----------------------------------------------------------------------------
2b5f62a0 1598
7c072018
VZ
1599void wxEnableTopLevelWindows(bool enable)
1600{
df5168c4 1601 wxWindowList::compatibility_iterator node;
7c072018
VZ
1602 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1603 node->GetData()->Enable(enable);
1604}
2b5f62a0 1605
2ecd1756
VZ
1606wxWindowDisabler::wxWindowDisabler(bool disable)
1607{
1608 m_disabled = disable;
1609 if ( disable )
1610 DoDisable();
1611}
1612
7c072018 1613wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
2ecd1756
VZ
1614{
1615 m_disabled = true;
1616 DoDisable(winToSkip);
1617}
1618
1619void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
7c072018
VZ
1620{
1621 // remember the top level windows which were already disabled, so that we
1622 // don't reenable them later
1623 m_winDisabled = NULL;
1624
df5168c4 1625 wxWindowList::compatibility_iterator node;
7c072018 1626 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
2b5f62a0 1627 {
7c072018
VZ
1628 wxWindow *winTop = node->GetData();
1629 if ( winTop == winToSkip )
1630 continue;
2b5f62a0 1631
7c072018
VZ
1632 // we don't need to disable the hidden or already disabled windows
1633 if ( winTop->IsEnabled() && winTop->IsShown() )
2b5f62a0 1634 {
7c072018 1635 winTop->Disable();
2b5f62a0
VZ
1636 }
1637 else
1638 {
7c072018
VZ
1639 if ( !m_winDisabled )
1640 {
1641 m_winDisabled = new wxWindowList;
1642 }
1643
1644 m_winDisabled->Append(winTop);
2b5f62a0
VZ
1645 }
1646 }
2b5f62a0
VZ
1647}
1648
7c072018 1649wxWindowDisabler::~wxWindowDisabler()
cd6ce4a9 1650{
2ecd1756
VZ
1651 if ( !m_disabled )
1652 return;
1653
df5168c4 1654 wxWindowList::compatibility_iterator node;
7c072018 1655 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
cd6ce4a9 1656 {
7c072018
VZ
1657 wxWindow *winTop = node->GetData();
1658 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
cd6ce4a9 1659 {
7c072018 1660 winTop->Enable();
cd6ce4a9 1661 }
7c072018 1662 //else: had been already disabled, don't reenable
cd6ce4a9 1663 }
f6bcfd97 1664
7c072018 1665 delete m_winDisabled;
f6bcfd97
BP
1666}
1667
7c072018
VZ
1668// Yield to other apps/messages and disable user input to all windows except
1669// the given one
1670bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
f6bcfd97 1671{
7c072018 1672 wxWindowDisabler wd(win);
21709999 1673
7c072018
VZ
1674 bool rc;
1675 if (onlyIfNeeded)
1676 rc = wxYieldIfNeeded();
1677 else
1678 rc = wxYield();
8461e4c2 1679
7c072018 1680 return rc;
8461e4c2
VZ
1681}
1682
fad92e2f
FM
1683// ----------------------------------------------------------------------------
1684// wxApp::Yield() wrappers for backwards compatibility
1685// ----------------------------------------------------------------------------
1686
1687bool wxYield()
8461e4c2 1688{
fad92e2f
FM
1689 return wxTheApp && wxTheApp->Yield();
1690}
1691
1692bool wxYieldIfNeeded()
1693{
1694 return wxTheApp && wxTheApp->Yield(true);
8461e4c2 1695}
7c072018
VZ
1696
1697#endif // wxUSE_GUI