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