]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/app.cpp
wxGTK's wxListBox now returns a meaningful value for DoGetBestSize
[wxWidgets.git] / src / gtk / app.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: app.cpp
3// Purpose:
4// Author: Robert Roebling
32e9da8b 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
8bbe427f 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
afb74891 11 #pragma implementation "app.h"
c801d85f
KB
12#endif
13
14#include "wx/app.h"
15#include "wx/gdicmn.h"
16#include "wx/utils.h"
c801d85f
KB
17#include "wx/intl.h"
18#include "wx/log.h"
46dc76ba 19#include "wx/memory.h"
a3622daa
VZ
20#include "wx/font.h"
21#include "wx/settings.h"
0d2a2b60 22#include "wx/dialog.h"
afb74891 23
06cfab17 24#if wxUSE_WX_RESOURCES
afb74891 25 #include "wx/resource.h"
f5abe911 26#endif
afb74891 27
031b2a7b 28#include "wx/module.h"
4bc67cc5 29#include "wx/image.h"
afb74891 30
df028524
VS
31#ifdef __WXUNIVERSAL__
32 #include "wx/univ/theme.h"
33 #include "wx/univ/renderer.h"
34#endif
35
91b8de8d 36#if wxUSE_THREADS
a37a5a73 37 #include "wx/thread.h"
91b8de8d 38#endif
afb74891 39
20e05ffb 40#include <unistd.h>
e8106239 41#include "wx/gtk/win_gtk.h"
c801d85f 42
20e05ffb 43#include <gtk/gtk.h>
24178e4a 44
83624f79 45
c801d85f
KB
46//-----------------------------------------------------------------------------
47// global data
48//-----------------------------------------------------------------------------
49
c67daf87 50wxApp *wxTheApp = (wxApp *) NULL;
32d4bfd1 51wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
c801d85f 52
acfd422a 53extern bool g_isIdle;
c801d85f 54
96997d65
RR
55bool g_mainThreadLocked = FALSE;
56gint g_pendingTag = 0;
3ac8d3bc 57
c2fa61e8 58static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
d76fe38b 59
c801d85f
KB
60//-----------------------------------------------------------------------------
61// local functions
62//-----------------------------------------------------------------------------
63
bf9e3e73 64/* forward declaration */
c4fda16b 65gint wxapp_idle_callback( gpointer WXUNUSED(data) );
96997d65 66gint wxapp_pending_callback( gpointer WXUNUSED(data) );
c4fda16b
RR
67void wxapp_install_idle_handler();
68
69#if wxUSE_THREADS
70gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) );
71#endif
bf9e3e73 72
c801d85f 73//-----------------------------------------------------------------------------
bf9e3e73 74// wxExit
c801d85f
KB
75//-----------------------------------------------------------------------------
76
60acb947 77void wxExit()
c801d85f 78{
ec758a20 79 gtk_main_quit();
ff7b1510 80}
c801d85f 81
bf9e3e73
RR
82//-----------------------------------------------------------------------------
83// wxYield
84//-----------------------------------------------------------------------------
53a8af59 85
cb2713bf
JS
86static bool gs_inYield = FALSE;
87
60acb947 88bool wxYield()
c801d85f 89{
6dc5fd71
VZ
90#if wxUSE_THREADS
91 if ( !wxThread::IsMain() )
92 {
93 // can't call gtk_main_iteration() from other threads like this
94 return TRUE;
95 }
96#endif // wxUSE_THREADS
97
c2fa61e8 98#ifdef __WXDEBUG__
cb2713bf 99 if (gs_inYield)
99ba739f 100 wxFAIL_MSG( wxT("wxYield called recursively" ) );
99ba739f 101#endif
c2fa61e8 102
cb2713bf 103 gs_inYield = TRUE;
e90c1d2a 104
99ba739f 105 if (!g_isIdle)
acfd422a 106 {
99ba739f
RR
107 // We need to remove idle callbacks or the loop will
108 // never finish.
acfd422a
RR
109 gtk_idle_remove( wxTheApp->m_idleTag );
110 wxTheApp->m_idleTag = 0;
99ba739f 111 g_isIdle = TRUE;
956dbab1 112 }
acfd422a 113
2ed3265e
VZ
114 // disable log flushing from here because a call to wxYield() shouldn't
115 // normally result in message boxes popping up &c
116 wxLog::Suspend();
117
406a6f6b
VZ
118 while (gtk_events_pending())
119 gtk_main_iteration();
120
7741c4e1
RR
121 /* it's necessary to call ProcessIdle() to update the frames sizes which
122 might have been changed (it also will update other things set from
123 OnUpdateUI() which is a nice (and desired) side effect) */
96997d65 124 while (wxTheApp->ProcessIdle()) { }
2ed3265e
VZ
125
126 // let the logs be flashed again
127 wxLog::Resume();
7741c4e1 128
cb2713bf 129 gs_inYield = FALSE;
99ba739f 130
acfd422a
RR
131 return TRUE;
132}
133
cb2713bf
JS
134//-----------------------------------------------------------------------------
135// wxYieldIfNeeded
136// Like wxYield, but fails silently if the yield is recursive.
137//-----------------------------------------------------------------------------
138
139bool wxYieldIfNeeded()
140{
141 if (gs_inYield)
142 return FALSE;
c2fa61e8
RD
143
144 return wxYield();
cb2713bf
JS
145}
146
bf9e3e73
RR
147//-----------------------------------------------------------------------------
148// wxWakeUpIdle
149//-----------------------------------------------------------------------------
150
151void wxWakeUpIdle()
152{
924ef850
RR
153#if wxUSE_THREADS
154 if (!wxThread::IsMain())
ce6d2511 155 wxMutexGuiEnter();
924ef850
RR
156#endif
157
2286341c 158 if (g_isIdle)
bf9e3e73 159 wxapp_install_idle_handler();
2286341c 160
924ef850
RR
161#if wxUSE_THREADS
162 if (!wxThread::IsMain())
ce6d2511 163 wxMutexGuiLeave();
924ef850 164#endif
bf9e3e73
RR
165}
166
167//-----------------------------------------------------------------------------
168// local functions
169//-----------------------------------------------------------------------------
170
96997d65 171gint wxapp_pending_callback( gpointer WXUNUSED(data) )
acfd422a
RR
172{
173 if (!wxTheApp) return TRUE;
c2fa61e8 174
96997d65
RR
175 // when getting called from GDK's time-out handler
176 // we are no longer within GDK's grab on the GUI
177 // thread so we must lock it here ourselves
178 gdk_threads_enter();
179
180 // Sent idle event to all who request them
181 wxTheApp->ProcessPendingEvents();
e90c1d2a 182
96997d65
RR
183 g_pendingTag = 0;
184
1b2dab34
RR
185 /* flush the logged messages if any */
186#if wxUSE_LOG
187 wxLog::FlushActive();
188#endif // wxUSE_LOG
189
96997d65
RR
190 // Release lock again
191 gdk_threads_leave();
192
193 // Return FALSE to indicate that no more idle events are
194 // to be sent (single shot instead of continuous stream)
195 return FALSE;
196}
197
198gint wxapp_idle_callback( gpointer WXUNUSED(data) )
199{
a5f1fd3e
VZ
200 if (!wxTheApp)
201 return TRUE;
202
203#ifdef __WXDEBUG__
6d477bb4
VZ
204 // don't generate the idle events while the assert modal dialog is shown,
205 // this completely confuses the apps which don't expect to be reentered
206 // from some safely-looking functions
a5f1fd3e
VZ
207 if ( wxTheApp->IsInAssert() )
208 {
6d477bb4 209 return TRUE;
a5f1fd3e
VZ
210 }
211#endif // __WXDEBUG__
c2fa61e8 212
924ef850
RR
213 // when getting called from GDK's time-out handler
214 // we are no longer within GDK's grab on the GUI
215 // thread so we must lock it here ourselves
216 gdk_threads_enter();
094637f6 217
96997d65 218 /* Indicate that we are now in idle mode - even so deeply
acfd422a
RR
219 in idle mode that we don't get any idle events anymore.
220 this is like wxMSW where an idle event is sent only
221 once each time after the event queue has been completely
222 emptied */
223 g_isIdle = TRUE;
96997d65 224 wxTheApp->m_idleTag = 0;
094637f6 225
6d477bb4
VZ
226 // Sent idle event to all who request them as long as they do
227 while (wxTheApp->ProcessIdle())
228 ;
c9e35272 229
96997d65 230 // Release lock again
924ef850 231 gdk_threads_leave();
acfd422a 232
96997d65
RR
233 // Return FALSE to indicate that no more idle events are
234 // to be sent (single shot instead of continuous stream)
235 return FALSE;
acfd422a 236}
8801832d 237
acfd422a
RR
238void wxapp_install_idle_handler()
239{
223d09f6 240 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
7b90a8f2 241
99ba739f
RR
242 g_isIdle = FALSE;
243
96997d65
RR
244 if (g_pendingTag == 0)
245 g_pendingTag = gtk_idle_add_priority( 900, wxapp_pending_callback, (gpointer) NULL );
c2fa61e8 246
7941ba11
RR
247 /* This routine gets called by all event handlers
248 indicating that the idle is over. It may also
249 get called from other thread for sending events
250 to the main thread (and processing these in
b6fa52db 251 idle time). Very low priority. */
7941ba11 252
f6bcfd97 253 wxTheApp->m_idleTag = gtk_idle_add_priority( 1000, wxapp_idle_callback, (gpointer) NULL );
ff7b1510 254}
c801d85f 255
6b3eb77a 256#if wxUSE_THREADS
b453e1b2 257
96997d65
RR
258static int g_threadUninstallLevel = 0;
259
b453e1b2 260void wxapp_install_thread_wakeup()
7b90a8f2 261{
96997d65 262 g_threadUninstallLevel++;
c2fa61e8 263
96997d65
RR
264 if (g_threadUninstallLevel != 1) return;
265
b453e1b2 266 if (wxTheApp->m_wakeUpTimerTag) return;
e90c1d2a 267
07f5b19a 268 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 50, wxapp_wakeup_timerout_callback, (gpointer) NULL );
b453e1b2
RR
269}
270
271void wxapp_uninstall_thread_wakeup()
272{
96997d65 273 g_threadUninstallLevel--;
c2fa61e8 274
96997d65
RR
275 if (g_threadUninstallLevel != 0) return;
276
b453e1b2 277 if (!wxTheApp->m_wakeUpTimerTag) return;
e90c1d2a 278
7b90a8f2
RR
279 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
280 wxTheApp->m_wakeUpTimerTag = 0;
b453e1b2
RR
281}
282
c4fda16b 283gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
b453e1b2 284{
094637f6 285 // when getting called from GDK's time-out handler
8dbf4589
RR
286 // we are no longer within GDK's grab on the GUI
287 // thread so we must lock it here ourselves
924ef850
RR
288 gdk_threads_enter();
289
290 wxapp_uninstall_thread_wakeup();
094637f6 291
8dbf4589 292 // unblock other threads wishing to do some GUI things
7b90a8f2 293 wxMutexGuiLeave();
2286341c 294
3ac8d3bc 295 g_mainThreadLocked = TRUE;
094637f6 296
8dbf4589 297 // wake up other threads
7b90a8f2 298 wxUsleep( 1 );
094637f6 299
8dbf4589 300 // block other thread again
7b90a8f2 301 wxMutexGuiEnter();
094637f6 302
3ac8d3bc
RR
303 g_mainThreadLocked = FALSE;
304
b453e1b2 305 wxapp_install_thread_wakeup();
094637f6 306
924ef850
RR
307 // release lock again
308 gdk_threads_leave();
2286341c 309
7b90a8f2
RR
310 return TRUE;
311}
8e193f38 312
c19c1ca9 313#endif // wxUSE_THREADS
7b90a8f2 314
c801d85f
KB
315//-----------------------------------------------------------------------------
316// wxApp
317//-----------------------------------------------------------------------------
318
319IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
320
53010e52
RR
321BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
322 EVT_IDLE(wxApp::OnIdle)
323END_EVENT_TABLE()
324
c801d85f
KB
325wxApp::wxApp()
326{
a5f1fd3e
VZ
327 m_initialized = FALSE;
328#ifdef __WXDEBUG__
329 m_isInAssert = FALSE;
330#endif // __WXDEBUG__
331
df5ddbca
RR
332 m_idleTag = 0;
333 wxapp_install_idle_handler();
094637f6 334
6b3eb77a 335#if wxUSE_THREADS
b453e1b2
RR
336 m_wakeUpTimerTag = 0;
337 wxapp_install_thread_wakeup();
6b3eb77a 338#endif
60acb947 339
f6fcbb63 340 m_colorCube = (unsigned char*) NULL;
a6f5aa49
VZ
341
342 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
343 m_glVisualInfo = (void *) NULL;
ff7b1510 344}
c801d85f 345
60acb947 346wxApp::~wxApp()
c801d85f 347{
acfd422a 348 if (m_idleTag) gtk_idle_remove( m_idleTag );
60acb947 349
6b3eb77a 350#if wxUSE_THREADS
b453e1b2 351 wxapp_uninstall_thread_wakeup();
6b3eb77a 352#endif
094637f6 353
f6fcbb63 354 if (m_colorCube) free(m_colorCube);
ff7b1510 355}
c801d85f 356
0d2a2b60 357bool wxApp::OnInitGui()
c801d85f 358{
1e6feb95
VZ
359 if ( !wxAppBase::OnInitGui() )
360 return FALSE;
361
b134516c
RR
362 GdkVisual *visual = gdk_visual_get_system();
363
a6f5aa49
VZ
364 // if this is a wxGLApp (derived from wxApp), and we've already
365 // chosen a specific visual, then derive the GdkVisual from that
366 if (m_glVisualInfo != NULL) {
367#ifdef __WXGTK20__
368 /* seems gtk_widget_set_default_visual no longer exists? */
369 GdkVisual* vis = gtk_widget_get_default_visual();
370#else
371 GdkVisual* vis = gdkx_visual_get(
372 ((XVisualInfo *) m_glVisualInfo) ->visualid );
373 gtk_widget_set_default_visual( vis );
374#endif
375
376 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
377 gtk_widget_set_default_colormap( colormap );
378
379 visual = vis;
380 }
381
094637f6 382 /* on some machines, the default visual is just 256 colours, so
b134516c 383 we make sure we get the best. this can sometimes be wasteful,
7b280524 384 of course, but what do these guys pay $30.000 for? */
2286341c 385
a6f5aa49 386 else if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
8480b297 387 (m_useBestVisual))
b134516c 388 {
2d4dc3a4
OK
389#ifdef __WXGTK20__
390 /* seems gtk_widget_set_default_visual no longer exists? */
391 GdkVisual* vis = gtk_widget_get_default_visual();
392#else
b134516c
RR
393 GdkVisual* vis = gdk_visual_get_best();
394 gtk_widget_set_default_visual( vis );
2d4dc3a4 395#endif
f6fcbb63 396
b134516c
RR
397 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
398 gtk_widget_set_default_colormap( colormap );
094637f6
VZ
399
400 visual = vis;
b134516c 401 }
d76fe38b 402
7b280524 403 /* Nothing to do for 15, 16, 24, 32 bit displays */
f6fcbb63 404 if (visual->depth > 8) return TRUE;
60acb947 405
f6fcbb63 406 /* initialize color cube for 8-bit color reduction dithering */
60acb947 407
f6fcbb63 408 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 409
f6fcbb63
RR
410 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
411
f03fc89f
VZ
412 for (int r = 0; r < 32; r++)
413 {
8801832d
VZ
414 for (int g = 0; g < 32; g++)
415 {
416 for (int b = 0; b < 32; b++)
417 {
418 int rr = (r << 3) | (r >> 2);
419 int gg = (g << 3) | (g >> 2);
420 int bb = (b << 3) | (b >> 2);
60acb947 421
f03fc89f
VZ
422 int index = -1;
423
f6fcbb63 424 GdkColor *colors = cmap->colors;
ca26177c 425 if (colors)
f03fc89f
VZ
426 {
427 int max = 3 * 65536;
428
429 for (int i = 0; i < cmap->size; i++)
430 {
431 int rdiff = ((rr << 8) - colors[i].red);
432 int gdiff = ((gg << 8) - colors[i].green);
433 int bdiff = ((bb << 8) - colors[i].blue);
434 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
435 if (sum < max)
094637f6 436 {
f03fc89f
VZ
437 index = i; max = sum;
438 }
439 }
f6fcbb63 440 }
094637f6
VZ
441 else
442 {
58c7cd12 443#if (GTK_MINOR_VERSION > 0)
094637f6
VZ
444 /* assume 8-bit true or static colors. this really
445 exists. */
446 GdkVisual* vis = gdk_colormap_get_visual( cmap );
447 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
448 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
449 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
58c7cd12 450#else
223d09f6 451 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
58c7cd12 452#endif
094637f6 453 }
8801832d
VZ
454 m_colorCube[ (r*1024) + (g*32) + b ] = index;
455 }
456 }
f6fcbb63 457 }
c801d85f 458
bbe0af5b
RR
459 return TRUE;
460}
461
60acb947 462bool wxApp::ProcessIdle()
53010e52 463{
ec758a20
RR
464 wxIdleEvent event;
465 event.SetEventObject( this );
466 ProcessEvent( event );
0cf2cb36 467
ec758a20 468 return event.MoreRequested();
ff7b1510 469}
53010e52
RR
470
471void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 472{
956dbab1 473 static bool s_inOnIdle = FALSE;
2286341c 474
d524867f 475 /* Avoid recursion (via ProcessEvent default case) */
956dbab1 476 if (s_inOnIdle)
ec758a20 477 return;
2286341c 478
956dbab1 479 s_inOnIdle = TRUE;
53010e52 480
7214297d
GL
481 /* Resend in the main thread events which have been prepared in other
482 threads */
483 ProcessPendingEvents();
484
d524867f 485 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 486 DeletePendingObjects();
53010e52 487
d524867f 488 /* Send OnIdle events to all windows */
ec758a20 489 bool needMore = SendIdleEvents();
53010e52 490
ec758a20
RR
491 if (needMore)
492 event.RequestMore(TRUE);
53010e52 493
956dbab1 494 s_inOnIdle = FALSE;
ff7b1510 495}
53010e52 496
60acb947 497bool wxApp::SendIdleEvents()
53010e52
RR
498{
499 bool needMore = FALSE;
e0253070 500
e146b8c8 501 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
502 while (node)
503 {
e146b8c8 504 wxWindow* win = node->GetData();
f3855ef0 505 if (SendIdleEvents(win))
53010e52 506 needMore = TRUE;
e146b8c8 507 node = node->GetNext();
ec758a20 508 }
e146b8c8 509
53010e52 510 return needMore;
ff7b1510 511}
53010e52
RR
512
513bool wxApp::SendIdleEvents( wxWindow* win )
514{
515 bool needMore = FALSE;
516
8bbe427f
VZ
517 wxIdleEvent event;
518 event.SetEventObject(win);
60acb947 519
f6bcfd97 520 win->GetEventHandler()->ProcessEvent(event);
53010e52 521
e70f5e13 522 win->OnInternalIdle();
e90c1d2a 523
53010e52
RR
524 if (event.MoreRequested())
525 needMore = TRUE;
526
8bbe427f
VZ
527 wxNode* node = win->GetChildren().First();
528 while (node)
529 {
530 wxWindow* win = (wxWindow*) node->Data();
531 if (SendIdleEvents(win))
53010e52
RR
532 needMore = TRUE;
533
8bbe427f
VZ
534 node = node->Next();
535 }
53010e52 536 return needMore ;
ff7b1510 537}
c801d85f 538
60acb947 539int wxApp::MainLoop()
c801d85f 540{
ec758a20
RR
541 gtk_main();
542 return 0;
ff7b1510 543}
c801d85f 544
60acb947 545void wxApp::ExitMainLoop()
c801d85f 546{
7ec2881a
RR
547 if (gtk_main_level() > 0)
548 gtk_main_quit();
ff7b1510 549}
c801d85f 550
60acb947 551bool wxApp::Initialized()
c801d85f 552{
ec758a20 553 return m_initialized;
ff7b1510 554}
c801d85f 555
60acb947 556bool wxApp::Pending()
c801d85f 557{
acfd422a 558 return (gtk_events_pending() > 0);
ff7b1510 559}
c801d85f 560
60acb947 561void wxApp::Dispatch()
c801d85f 562{
8801832d 563 gtk_main_iteration();
ff7b1510 564}
c801d85f 565
60acb947 566void wxApp::DeletePendingObjects()
c801d85f 567{
ec758a20
RR
568 wxNode *node = wxPendingDelete.First();
569 while (node)
570 {
571 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 572
ec758a20 573 delete obj;
c801d85f 574
f03fc89f
VZ
575 if (wxPendingDelete.Find(obj))
576 delete node;
c801d85f 577
ec758a20
RR
578 node = wxPendingDelete.First();
579 }
ff7b1510 580}
c801d85f 581
60acb947 582bool wxApp::Initialize()
c801d85f 583{
9cc7a35d 584 wxBuffer = new wxChar[BUFSIZ + 512];
0d2a2b60
RR
585
586 wxClassInfo::InitializeClasses();
60acb947 587
0d2a2b60 588 wxSystemSettings::Init();
a92b8709 589
5c3e299e 590#if wxUSE_INTL
a92b8709 591 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
5c3e299e 592#endif
60acb947 593
4d3a259a
GL
594 // GL: I'm annoyed ... I don't know where to put this and I don't want to
595 // create a module for that as it's part of the core.
596#if wxUSE_THREADS
597 wxPendingEvents = new wxList();
598 wxPendingEventsLocker = new wxCriticalSection();
599#endif
600
0d2a2b60
RR
601 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
602 wxTheColourDatabase->Initialize();
a3622daa 603
0d2a2b60
RR
604 wxInitializeStockLists();
605 wxInitializeStockObjects();
c801d85f 606
4a0c68a7
RR
607#if wxUSE_WX_RESOURCES
608 wxInitializeResourceSystem();
609#endif
610
0d2a2b60
RR
611 wxModule::RegisterModules();
612 if (!wxModule::InitializeModules()) return FALSE;
60acb947 613
0d2a2b60 614 return TRUE;
ff7b1510 615}
c801d85f 616
60acb947 617void wxApp::CleanUp()
c801d85f 618{
0d2a2b60 619 wxModule::CleanUpModules();
0cf2cb36 620
4a0c68a7
RR
621#if wxUSE_WX_RESOURCES
622 wxCleanUpResourceSystem();
623#endif
624
60acb947
VZ
625 if (wxTheColourDatabase)
626 delete wxTheColourDatabase;
2286341c 627
0d2a2b60 628 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 629
0d2a2b60
RR
630 wxDeleteStockObjects();
631
ec758a20 632 wxDeleteStockLists();
a3622daa 633
0d2a2b60
RR
634 delete wxTheApp;
635 wxTheApp = (wxApp*) NULL;
636
4d3a259a
GL
637 // GL: I'm annoyed ... I don't know where to put this and I don't want to
638 // create a module for that as it's part of the core.
639#if wxUSE_THREADS
640 delete wxPendingEvents;
641 delete wxPendingEventsLocker;
642#endif
643
3e61c765 644 wxSystemSettings::Done();
60acb947 645
3e61c765
RR
646 delete[] wxBuffer;
647
648 wxClassInfo::CleanUpClasses();
60acb947
VZ
649
650 // check for memory leaks
0d2a2b60 651#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
6981d3ec 652 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
0d2a2b60 653 {
223d09f6 654 wxLogDebug(wxT("There were memory leaks.\n"));
0d2a2b60
RR
655 wxDebugContext::Dump();
656 wxDebugContext::PrintStatistics();
657 }
8801832d 658#endif // Debug
0d2a2b60 659
88ac883a 660#if wxUSE_LOG
60acb947 661 // do this as the very last thing because everything else can log messages
0d2a2b60 662 wxLog::DontCreateOnDemand();
60acb947 663
0d2a2b60 664 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
665 if (oldLog)
666 delete oldLog;
88ac883a 667#endif // wxUSE_LOG
c19c1ca9 668}
c801d85f 669
c2fa61e8
RD
670//-----------------------------------------------------------------------------
671// Access to the root window global
672//-----------------------------------------------------------------------------
673
674GtkWidget* wxGetRootWindow()
675{
676 if (gs_RootWindow == NULL) {
677 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
678 gtk_widget_realize( gs_RootWindow );
679 }
680 return gs_RootWindow;
681}
682
c801d85f
KB
683//-----------------------------------------------------------------------------
684// wxEntry
685//-----------------------------------------------------------------------------
686
954de0f1
RD
687
688int wxEntryStart( int argc, char *argv[] )
c801d85f 689{
924ef850 690#if wxUSE_THREADS
8f75cb6c 691 /* GTK 1.2 up to version 1.2.3 has broken threads */
27df579a 692 if ((gtk_major_version == 1) &&
8f75cb6c 693 (gtk_minor_version == 2) &&
2286341c 694 (gtk_micro_version < 4))
96997d65 695 {
fb65642c 696 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
8f75cb6c
RR
697 }
698 else
699 {
700 g_thread_init(NULL);
701 }
924ef850 702#endif
2286341c 703
0d2a2b60 704 gtk_set_locale();
c801d85f 705
f9862abd
JS
706 // We should have the wxUSE_WCHAR_T test on the _outside_
707#if wxUSE_WCHAR_T
2d4dc3a4
OK
708#if defined(__WXGTK20__)
709 // gtk+ 2.0 supports Unicode through UTF-8 strings
710 wxConvCurrent = &wxConvUTF8;
f9862abd 711#else
dcf924a3 712 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
f9862abd 713#endif
fd9811b1
RR
714#else
715 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
716#endif
002f4218 717
924ef850
RR
718 gdk_threads_enter();
719
0d2a2b60 720 gtk_init( &argc, &argv );
0cf2cb36 721
f0492f7d 722 wxSetDetectableAutoRepeat( TRUE );
094637f6 723
60acb947 724 if (!wxApp::Initialize())
924ef850
RR
725 {
726 gdk_threads_leave();
60acb947 727 return -1;
924ef850 728 }
0cf2cb36 729
954de0f1
RD
730 return 0;
731}
732
c2fa61e8 733
954de0f1
RD
734int wxEntryInitGui()
735{
736 int retValue = 0;
737
738 if ( !wxTheApp->OnInitGui() )
739 retValue = -1;
740
c2fa61e8 741 wxGetRootWindow();
954de0f1
RD
742
743 return retValue;
744}
745
746
747void wxEntryCleanup()
748{
749#if wxUSE_LOG
750 // flush the logged messages if any
751 wxLog *log = wxLog::GetActiveTarget();
752 if (log != NULL && log->HasPendingMessages())
753 log->Flush();
754
755 // continuing to use user defined log target is unsafe from now on because
756 // some resources may be already unavailable, so replace it by something
757 // more safe
758 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
759 if ( oldlog )
760 delete oldlog;
761#endif // wxUSE_LOG
762
763 wxApp::CleanUp();
764
765 gdk_threads_leave();
766}
767
768
769
770int wxEntry( int argc, char *argv[] )
771{
2db0bbde
JS
772#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
773 // This seems to be necessary since there are 'rogue'
774 // objects present at this point (perhaps global objects?)
775 // Setting a checkpoint will ignore them as far as the
776 // memory checking facility is concerned.
777 // Of course you may argue that memory allocated in globals should be
778 // checked, but this is a reasonable compromise.
779 wxDebugContext::SetCheckpoint();
780#endif
a37a5a73 781 int err = wxEntryStart(argc, argv);
954de0f1
RD
782 if (err)
783 return err;
784
ec758a20 785 if (!wxTheApp)
c801d85f 786 {
60acb947 787 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
223d09f6 788 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
0cf2cb36 789
ec758a20 790 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 791
ec758a20 792 wxObject *test_app = app_ini();
0cf2cb36 793
ec758a20
RR
794 wxTheApp = (wxApp*) test_app;
795 }
0cf2cb36 796
223d09f6 797 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
c801d85f 798
ec758a20 799 wxTheApp->argc = argc;
6de92826
OK
800#if wxUSE_UNICODE
801 wxTheApp->argv = new wxChar*[argc+1];
802 int mb_argc = 0;
2286341c 803 while (mb_argc < argc)
924ef850
RR
804 {
805 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
806 mb_argc++;
6de92826
OK
807 }
808 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
809#else
ec758a20 810 wxTheApp->argv = argv;
6de92826 811#endif
0cf2cb36 812
8801832d 813 wxString name(wxFileNameFromPath(argv[0]));
ec758a20
RR
814 wxStripExtension( name );
815 wxTheApp->SetAppName( name );
e0253070 816
954de0f1
RD
817 int retValue;
818 retValue = wxEntryInitGui();
68df5777 819
8801832d
VZ
820 // Here frames insert themselves automatically into wxTopLevelWindows by
821 // getting created in OnInit().
0151c3eb
VZ
822 if ( retValue == 0 )
823 {
824 if ( !wxTheApp->OnInit() )
825 retValue = -1;
826 }
0cf2cb36 827
0151c3eb
VZ
828 if ( retValue == 0 )
829 {
cfb50f14 830 /* delete pending toplevel windows (typically a single
094637f6
VZ
831 dialog) so that, if there isn't any left, we don't
832 call OnRun() */
cfb50f14 833 wxTheApp->DeletePendingObjects();
094637f6 834
0151c3eb 835 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 836
0151c3eb 837 if (wxTheApp->Initialized())
094637f6 838 {
2286341c 839 wxTheApp->OnRun();
0cf2cb36 840
cfb50f14
RR
841 wxWindow *topWindow = wxTheApp->GetTopWindow();
842 if (topWindow)
0151c3eb 843 {
cfb50f14
RR
844 /* Forcibly delete the window. */
845 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
846 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
847 {
848 topWindow->Close( TRUE );
849 wxTheApp->DeletePendingObjects();
850 }
851 else
852 {
853 delete topWindow;
854 wxTheApp->SetTopWindow( (wxWindow*) NULL );
855 }
094637f6 856 }
2286341c
VZ
857
858 retValue = wxTheApp->OnExit();
0d2a2b60 859 }
0151c3eb 860 }
0cf2cb36 861
954de0f1 862 wxEntryCleanup();
924ef850 863
ec758a20 864 return retValue;
ff7b1510 865}
1a56f55c 866
df028524
VS
867#ifndef __WXUNIVERSAL__
868
094637f6
VZ
869#include "wx/gtk/info.xpm"
870#include "wx/gtk/error.xpm"
871#include "wx/gtk/question.xpm"
872#include "wx/gtk/warning.xpm"
873
df028524 874wxIcon wxApp::GetStdIcon(int which) const
ebea0891 875{
094637f6
VZ
876 switch(which)
877 {
878 case wxICON_INFORMATION:
879 return wxIcon(info_xpm);
880
881 case wxICON_QUESTION:
882 return wxIcon(question_xpm);
883
884 case wxICON_EXCLAMATION:
885 return wxIcon(warning_xpm);
886
887 default:
223d09f6 888 wxFAIL_MSG(wxT("requested non existent standard icon"));
094637f6
VZ
889 // still fall through
890
891 case wxICON_HAND:
892 return wxIcon(error_xpm);
893 }
ebea0891 894}
df028524
VS
895#else
896wxIcon wxApp::GetStdIcon(int which) const
897{
898 return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
899}
900#endif // !__WXUNIVERSAL__
901
a5f1fd3e
VZ
902
903#ifdef __WXDEBUG__
904
905void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
906{
907 m_isInAssert = TRUE;
908
909 wxAppBase::OnAssert(file, line, msg);
910
911 m_isInAssert = FALSE;
912}
913
914#endif // __WXDEBUG__
915