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