]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/app.cpp
1. wxSingleChoiceDialog looks Ok under Windows
[wxWidgets.git] / src / gtk1 / 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
f3855ef0 32#include "wx/thread.h"
91b8de8d 33#endif
afb74891 34
c801d85f
KB
35#include "unistd.h"
36
91b8de8d
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;
c801d85f
KB
48wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
49
7214297d 50#if wxUSE_THREADS
4d3a259a
GL
51extern wxList *wxPendingEvents;
52extern wxCriticalSection *wxPendingEventsLocker;
7214297d 53#endif
a3622daa 54extern wxResourceCache *wxTheResourceCache;
acfd422a 55extern bool g_isIdle;
c801d85f 56
01111366
RR
57unsigned char g_palette[64*3] =
58{
59 0x0, 0x0, 0x0,
60 0xff, 0xff, 0xff,
61 0xff, 0x0, 0x0,
62 0xff, 0xff, 0x0,
63 0x0, 0xff, 0x0,
64 0x0, 0x0, 0xff,
65 0x0, 0xff, 0xff,
66 0x99, 0x99, 0x99,
67 0xff, 0x88, 0x0,
68 0x88, 0x0, 0x0,
69 0x0, 0x88, 0x88,
70 0x88, 0x88, 0x0,
71 0xff, 0xcc, 0x97,
72 0xbb, 0xbb, 0xbb,
73 0x9f, 0x6b, 0x42,
74 0x55, 0x55, 0x55,
75 0xdd, 0xdd, 0xdd,
76 0x77, 0x77, 0x77,
77 0x33, 0x33, 0x33,
78 0xcc, 0x0, 0x0,
79 0xff, 0x44, 0x0,
80 0xff, 0xcc, 0x0,
81 0xcc, 0xcc, 0x0,
82 0x60, 0x60, 0x0,
83 0x0, 0x43, 0x0,
84 0x0, 0x7f, 0x0,
85 0x0, 0xcc, 0x0,
86 0x0, 0x44, 0x44,
87 0x0, 0x0, 0x44,
88 0x0, 0x0, 0x88,
89 0xef, 0xb1, 0x7b,
90 0xdf, 0x98, 0x5f,
91 0xbf, 0x87, 0x56,
92 0x7f, 0x57, 0x26,
93 0x5f, 0x39, 0xc,
94 0x3f, 0x1c, 0x0,
95 0x21, 0x0, 0x0,
96 0x0, 0x43, 0x87,
97 0x2d, 0x70, 0xaf,
98 0x5a, 0x9e, 0xd7,
99 0x87, 0xcc, 0xff,
100 0xff, 0xe0, 0xba,
101 0x21, 0x43, 0xf,
102 0x3d, 0x5d, 0x25,
103 0x59, 0x78, 0x3a,
104 0x75, 0x93, 0x4f,
105 0x91, 0xae, 0x64,
106 0xad, 0xc8, 0x7a,
e0253070 107 0xf0, 0xa8, 0xef,
01111366
RR
108 0xd0, 0x88, 0xd0,
109 0xaf, 0x66, 0xaf,
110 0x8e, 0x44, 0x8e,
111 0x6d, 0x22, 0x6d,
e0253070 112 0x4b, 0x0, 0x4b,
01111366
RR
113 0xff, 0xc0, 0xbc,
114 0xff, 0x93, 0x91,
115 0xff, 0x66, 0x67,
116 0xd8, 0xf2, 0xbf,
117 0xff, 0xc9, 0x68,
118 0xff, 0x96, 0x67,
119 0xa5, 0x60, 0xff,
120 0x51, 0xff, 0x99,
121 0x3f, 0xa5, 0x63,
122 0x98, 0x90, 0x67
123};
124
c801d85f
KB
125//-----------------------------------------------------------------------------
126// local functions
127//-----------------------------------------------------------------------------
128
129extern void wxFlushResources(void);
130
131//-----------------------------------------------------------------------------
132// global functions
133//-----------------------------------------------------------------------------
134
60acb947 135void wxExit()
c801d85f 136{
ec758a20 137 gtk_main_quit();
ff7b1510 138}
c801d85f 139
acfd422a 140/* forward declaration */
53a8af59
KB
141gint wxapp_idle_callback( gpointer WXUNUSED(data) );
142
60acb947 143bool wxYield()
c801d85f 144{
7b90a8f2
RR
145 /* it's necessary to call ProcessIdle() to update the frames sizes which
146 might have been changed (it also will update other things set from
147 OnUpdateUI() which is a nice (and desired) side effect) */
1601ab7a
RR
148 while (wxTheApp->ProcessIdle()) { }
149
150#if 0
e146b8c8 151 for ( wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
5f12ae5c
VZ
152 node;
153 node = node->GetNext() )
154 {
e146b8c8 155 wxWindow *win = node->GetData();
5f12ae5c
VZ
156 win->OnInternalIdle();
157 }
1601ab7a 158#endif
5f12ae5c 159
acfd422a
RR
160 if (wxTheApp->m_idleTag)
161 {
162 /* We need to temporarily remove idle callbacks or the loop will
163 never finish. */
164 gtk_idle_remove( wxTheApp->m_idleTag );
165 wxTheApp->m_idleTag = 0;
166
167 while (gtk_events_pending())
168 gtk_main_iteration();
169
170 /* re-add idle handler */
171 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
172 }
173 else
174 {
175 while (gtk_events_pending())
176 gtk_main_iteration();
177 }
178
179 return TRUE;
180}
181
182gint wxapp_idle_callback( gpointer WXUNUSED(data) )
183{
184 if (!wxTheApp) return TRUE;
185
86fdd27b 186#if (GTK_MINOR_VERSION > 0)
7b90a8f2
RR
187 /* when getting called from GDK's idle handler we
188 are no longer within GDK's grab on the GUI
189 thread so we must lock it here ourselves */
190 GDK_THREADS_ENTER ();
86fdd27b 191#endif
7b90a8f2 192
acfd422a
RR
193 /* sent idle event to all who request them */
194 while (wxTheApp->ProcessIdle()) { }
195
196 /* we don't want any more idle events until the next event is
197 sent to wxGTK */
53a8af59 198 gtk_idle_remove( wxTheApp->m_idleTag );
acfd422a
RR
199 wxTheApp->m_idleTag = 0;
200
201 /* indicate that we are now in idle mode - even so deeply
202 in idle mode that we don't get any idle events anymore.
203 this is like wxMSW where an idle event is sent only
204 once each time after the event queue has been completely
205 emptied */
206 g_isIdle = TRUE;
207
86fdd27b 208#if (GTK_MINOR_VERSION > 0)
7b90a8f2
RR
209 /* release lock again */
210 GDK_THREADS_LEAVE ();
86fdd27b 211#endif
acfd422a
RR
212
213 return TRUE;
214}
8801832d 215
acfd422a
RR
216void wxapp_install_idle_handler()
217{
861ccde4 218 wxASSERT_MSG( wxTheApp->m_idleTag == 0, _T("attempt to install idle handler twice") );
7b90a8f2 219
acfd422a
RR
220 /* this routine gets called by all event handlers
221 indicating that the idle is over. */
5f12ae5c 222
53a8af59 223 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
acfd422a
RR
224
225 g_isIdle = FALSE;
ff7b1510 226}
c801d85f 227
6b3eb77a 228#if wxUSE_THREADS
7b90a8f2
RR
229static gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
230{
231 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
232 wxTheApp->m_wakeUpTimerTag = 0;
233
86fdd27b 234#if (GTK_MINOR_VERSION > 0)
7b90a8f2
RR
235 /* when getting called from GDK's time-out handler
236 we are no longer within GDK's grab on the GUI
237 thread so we must lock it here ourselves */
238 GDK_THREADS_ENTER ();
86fdd27b 239#endif
7b90a8f2
RR
240
241 /* unblock other threads wishing to do some GUI things */
242 wxMutexGuiLeave();
243
244 /* wake up other threads */
245 wxUsleep( 1 );
246
247 /* block other thread again */
248 wxMutexGuiEnter();
249
86fdd27b 250#if (GTK_MINOR_VERSION > 0)
7b90a8f2
RR
251 /* release lock again */
252 GDK_THREADS_LEAVE ();
86fdd27b 253#endif
7b90a8f2 254
db2d879a 255 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 20, wxapp_wakeup_timerout_callback, (gpointer) NULL );
7b90a8f2
RR
256
257 return TRUE;
258}
6b3eb77a 259#endif
7b90a8f2 260
c801d85f
KB
261//-----------------------------------------------------------------------------
262// wxApp
263//-----------------------------------------------------------------------------
264
265IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
266
53010e52
RR
267BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
268 EVT_IDLE(wxApp::OnIdle)
269END_EVENT_TABLE()
270
c801d85f
KB
271wxApp::wxApp()
272{
0d2a2b60 273 wxTheApp = this;
60acb947 274
ec758a20
RR
275 m_topWindow = (wxWindow *) NULL;
276 m_exitOnFrameDelete = TRUE;
60acb947 277
0d2a2b60 278 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
7b90a8f2 279
6b3eb77a 280#if wxUSE_THREADS
db2d879a 281 m_wakeUpTimerTag = gtk_timeout_add( 20, wxapp_wakeup_timerout_callback, (gpointer) NULL );
6b3eb77a 282#endif
60acb947 283
f6fcbb63 284 m_colorCube = (unsigned char*) NULL;
ff7b1510 285}
c801d85f 286
60acb947 287wxApp::~wxApp()
c801d85f 288{
acfd422a 289 if (m_idleTag) gtk_idle_remove( m_idleTag );
60acb947 290
6b3eb77a 291#if wxUSE_THREADS
7b90a8f2 292 if (m_wakeUpTimerTag) gtk_timeout_remove( m_wakeUpTimerTag );
6b3eb77a 293#endif
7b90a8f2 294
f6fcbb63 295 if (m_colorCube) free(m_colorCube);
ff7b1510 296}
c801d85f 297
0d2a2b60 298bool wxApp::OnInitGui()
c801d85f 299{
7b280524
RR
300 /* on some SGIs, the default visual is just 256 colours, so we
301 make sure we get the best. this can sometimes be wasteful,
302 of course, but what do these guys pay $30.000 for? */
303 GdkVisual* visual = gdk_visual_get_best();
304 gtk_widget_set_default_visual( visual );
f6fcbb63 305
7b280524 306 /* Nothing to do for 15, 16, 24, 32 bit displays */
f6fcbb63 307 if (visual->depth > 8) return TRUE;
60acb947 308
0d2a2b60
RR
309 /* this initiates the standard palette as defined by GdkImlib
310 in the GNOME libraries. it ensures that all GNOME applications
311 use the same 64 colormap entries on 8-bit displays so you
312 can use several rather graphics-heavy applications at the
313 same time.
8801832d 314 NOTE: this doesn't really seem to work this way... */
bbe0af5b 315
0d2a2b60
RR
316 /*
317 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
bbe0af5b 318
0d2a2b60
RR
319 for (int i = 0; i < 64; i++)
320 {
321 GdkColor col;
322 col.red = g_palette[i*3 + 0] << 8;
323 col.green = g_palette[i*3 + 1] << 8;
324 col.blue = g_palette[i*3 + 2] << 8;
325 col.pixel = 0;
326
327 gdk_color_alloc( cmap, &col );
328 }
60acb947 329
0d2a2b60
RR
330 gtk_widget_set_default_colormap( cmap );
331 */
60acb947 332
f6fcbb63 333 /* initialize color cube for 8-bit color reduction dithering */
60acb947 334
f6fcbb63 335 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 336
f6fcbb63
RR
337 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
338
f03fc89f
VZ
339 for (int r = 0; r < 32; r++)
340 {
8801832d
VZ
341 for (int g = 0; g < 32; g++)
342 {
343 for (int b = 0; b < 32; b++)
344 {
345 int rr = (r << 3) | (r >> 2);
346 int gg = (g << 3) | (g >> 2);
347 int bb = (b << 3) | (b >> 2);
60acb947 348
f03fc89f
VZ
349 int index = -1;
350
f6fcbb63 351 GdkColor *colors = cmap->colors;
ca26177c 352 if (colors)
f03fc89f
VZ
353 {
354 int max = 3 * 65536;
355
356 for (int i = 0; i < cmap->size; i++)
357 {
358 int rdiff = ((rr << 8) - colors[i].red);
359 int gdiff = ((gg << 8) - colors[i].green);
360 int bdiff = ((bb << 8) - colors[i].blue);
361 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
362 if (sum < max)
363 {
364 index = i; max = sum;
365 }
366 }
f6fcbb63 367 }
ca26177c
RR
368 else
369 {
58c7cd12 370#if (GTK_MINOR_VERSION > 0)
ca26177c
RR
371 /* assume 8-bit true or static colors. this really
372 exists. */
373 GdkVisual* vis = gdk_colormap_get_visual( cmap );
374 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
375 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
376 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
58c7cd12
RR
377#else
378 wxFAIL_MSG( _T("Unsupported graphics hardware") );
379#endif
ca26177c 380 }
8801832d
VZ
381 m_colorCube[ (r*1024) + (g*32) + b ] = index;
382 }
383 }
f6fcbb63 384 }
c801d85f 385
bbe0af5b
RR
386 return TRUE;
387}
388
60acb947 389bool wxApp::ProcessIdle()
53010e52 390{
ec758a20
RR
391 wxIdleEvent event;
392 event.SetEventObject( this );
393 ProcessEvent( event );
0cf2cb36 394
ec758a20 395 return event.MoreRequested();
ff7b1510 396}
53010e52
RR
397
398void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 399{
ec758a20 400 static bool inOnIdle = FALSE;
53010e52 401
d524867f 402 /* Avoid recursion (via ProcessEvent default case) */
ec758a20
RR
403 if (inOnIdle)
404 return;
53010e52 405
ec758a20 406 inOnIdle = TRUE;
53010e52 407
d345e841 408#if wxUSE_THREADS
7214297d
GL
409 /* Resend in the main thread events which have been prepared in other
410 threads */
411 ProcessPendingEvents();
d345e841 412#endif
7214297d 413
d524867f 414 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 415 DeletePendingObjects();
53010e52 416
d524867f 417 /* flush the logged messages if any */
88ac883a 418#if wxUSE_LOG
d524867f
RR
419 wxLog *log = wxLog::GetActiveTarget();
420 if (log != NULL && log->HasPendingMessages())
421 log->Flush();
88ac883a 422#endif // wxUSE_LOG
53010e52 423
d524867f 424 /* Send OnIdle events to all windows */
ec758a20 425 bool needMore = SendIdleEvents();
53010e52 426
ec758a20
RR
427 if (needMore)
428 event.RequestMore(TRUE);
53010e52 429
ec758a20 430 inOnIdle = FALSE;
ff7b1510 431}
53010e52 432
60acb947 433bool wxApp::SendIdleEvents()
53010e52
RR
434{
435 bool needMore = FALSE;
e0253070 436
e146b8c8 437 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
438 while (node)
439 {
e146b8c8 440 wxWindow* win = node->GetData();
f3855ef0 441 if (SendIdleEvents(win))
53010e52 442 needMore = TRUE;
e146b8c8 443 node = node->GetNext();
ec758a20 444 }
e146b8c8 445
53010e52 446 return needMore;
ff7b1510 447}
53010e52
RR
448
449bool wxApp::SendIdleEvents( wxWindow* win )
450{
451 bool needMore = FALSE;
452
8bbe427f
VZ
453 wxIdleEvent event;
454 event.SetEventObject(win);
60acb947 455
9390a202 456 win->OnInternalIdle();
60acb947 457
8bbe427f 458 win->ProcessEvent(event);
53010e52
RR
459
460 if (event.MoreRequested())
461 needMore = TRUE;
462
8bbe427f
VZ
463 wxNode* node = win->GetChildren().First();
464 while (node)
465 {
466 wxWindow* win = (wxWindow*) node->Data();
467 if (SendIdleEvents(win))
53010e52
RR
468 needMore = TRUE;
469
8bbe427f
VZ
470 node = node->Next();
471 }
53010e52 472 return needMore ;
ff7b1510 473}
c801d85f 474
60acb947 475int wxApp::MainLoop()
c801d85f 476{
ec758a20
RR
477 gtk_main();
478 return 0;
ff7b1510 479}
c801d85f 480
60acb947 481void wxApp::ExitMainLoop()
c801d85f 482{
ec758a20 483 gtk_main_quit();
ff7b1510 484}
c801d85f 485
60acb947 486bool wxApp::Initialized()
c801d85f 487{
ec758a20 488 return m_initialized;
ff7b1510 489}
c801d85f 490
60acb947 491bool wxApp::Pending()
c801d85f 492{
acfd422a 493 return (gtk_events_pending() > 0);
ff7b1510 494}
c801d85f 495
60acb947 496void wxApp::Dispatch()
c801d85f 497{
8801832d 498 gtk_main_iteration();
ff7b1510 499}
c801d85f 500
7214297d
GL
501#if wxUSE_THREADS
502void wxApp::ProcessPendingEvents()
503{
4d3a259a
GL
504 wxNode *node = wxPendingEvents->First();
505 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
7214297d
GL
506
507 while (node)
508 {
509 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
510
511 handler->ProcessPendingEvents();
e146b8c8 512
7214297d
GL
513 delete node;
514
4d3a259a 515 node = wxPendingEvents->First();
7214297d
GL
516 }
517}
8801832d 518#endif // wxUSE_THREADS
7214297d 519
60acb947 520void wxApp::DeletePendingObjects()
c801d85f 521{
ec758a20
RR
522 wxNode *node = wxPendingDelete.First();
523 while (node)
524 {
525 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 526
ec758a20 527 delete obj;
c801d85f 528
f03fc89f
VZ
529 if (wxPendingDelete.Find(obj))
530 delete node;
c801d85f 531
ec758a20
RR
532 node = wxPendingDelete.First();
533 }
ff7b1510 534}
c801d85f 535
60acb947 536wxWindow *wxApp::GetTopWindow()
c801d85f 537{
e146b8c8
VZ
538 if (m_topWindow)
539 return m_topWindow;
540 else if (wxTopLevelWindows.GetCount() > 0)
541 return wxTopLevelWindows.GetFirst()->GetData();
542 else
543 return NULL;
ff7b1510 544}
c801d85f
KB
545
546void wxApp::SetTopWindow( wxWindow *win )
547{
ec758a20 548 m_topWindow = win;
ff7b1510 549}
c801d85f 550
60acb947 551bool wxApp::Initialize()
c801d85f 552{
9cc7a35d 553 wxBuffer = new wxChar[BUFSIZ + 512];
0d2a2b60
RR
554
555 wxClassInfo::InitializeClasses();
60acb947 556
0d2a2b60 557 wxSystemSettings::Init();
60acb947 558
4d3a259a
GL
559 // GL: I'm annoyed ... I don't know where to put this and I don't want to
560 // create a module for that as it's part of the core.
561#if wxUSE_THREADS
562 wxPendingEvents = new wxList();
563 wxPendingEventsLocker = new wxCriticalSection();
564#endif
565
36b3b54a 566/*
0d2a2b60
RR
567 wxTheFontNameDirectory = new wxFontNameDirectory;
568 wxTheFontNameDirectory->Initialize();
36b3b54a 569*/
c801d85f 570
0d2a2b60
RR
571 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
572 wxTheColourDatabase->Initialize();
a3622daa 573
0d2a2b60
RR
574 wxInitializeStockLists();
575 wxInitializeStockObjects();
c801d85f 576
06cfab17 577#if wxUSE_WX_RESOURCES
0d2a2b60 578 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
60acb947 579
0d2a2b60 580 wxInitializeResourceSystem();
f5abe911 581#endif
0cf2cb36 582
0d2a2b60 583 wxImage::InitStandardHandlers();
e0253070 584
0d2a2b60
RR
585 wxModule::RegisterModules();
586 if (!wxModule::InitializeModules()) return FALSE;
60acb947 587
0d2a2b60 588 return TRUE;
ff7b1510 589}
c801d85f 590
60acb947 591void wxApp::CleanUp()
c801d85f 592{
0d2a2b60 593 wxModule::CleanUpModules();
0cf2cb36 594
06cfab17 595#if wxUSE_WX_RESOURCES
ec758a20 596 wxFlushResources();
a3622daa 597
60acb947
VZ
598 if (wxTheResourceCache)
599 delete wxTheResourceCache;
bbe0af5b 600 wxTheResourceCache = (wxResourceCache*) NULL;
60acb947 601
f5abe911
RR
602 wxCleanUpResourceSystem();
603#endif
a3622daa 604
60acb947
VZ
605 if (wxTheColourDatabase)
606 delete wxTheColourDatabase;
0d2a2b60 607 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 608
36b3b54a 609/*
0d2a2b60
RR
610 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
611 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
36b3b54a 612*/
60acb947 613
0d2a2b60
RR
614 wxDeleteStockObjects();
615
ec758a20 616 wxDeleteStockLists();
a3622daa 617
ec758a20 618 wxImage::CleanUpHandlers();
0cf2cb36 619
0d2a2b60
RR
620 delete wxTheApp;
621 wxTheApp = (wxApp*) NULL;
622
4d3a259a
GL
623 // GL: I'm annoyed ... I don't know where to put this and I don't want to
624 // create a module for that as it's part of the core.
625#if wxUSE_THREADS
626 delete wxPendingEvents;
627 delete wxPendingEventsLocker;
628#endif
629
3e61c765 630 wxSystemSettings::Done();
60acb947 631
3e61c765
RR
632 delete[] wxBuffer;
633
634 wxClassInfo::CleanUpClasses();
60acb947
VZ
635
636 // check for memory leaks
0d2a2b60
RR
637#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
638 if (wxDebugContext::CountObjectsLeft() > 0)
639 {
9cc7a35d 640 wxLogDebug(_T("There were memory leaks.\n"));
0d2a2b60
RR
641 wxDebugContext::Dump();
642 wxDebugContext::PrintStatistics();
643 }
8801832d 644#endif // Debug
0d2a2b60 645
88ac883a 646#if wxUSE_LOG
60acb947 647 // do this as the very last thing because everything else can log messages
0d2a2b60 648 wxLog::DontCreateOnDemand();
60acb947 649
0d2a2b60 650 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
651 if (oldLog)
652 delete oldLog;
ff7b1510 653}
0cf2cb36 654
c801d85f
KB
655wxLog *wxApp::CreateLogTarget()
656{
0d2a2b60 657 return new wxLogGui;
c801d85f 658}
88ac883a 659#endif // wxUSE_LOG
c801d85f
KB
660
661//-----------------------------------------------------------------------------
662// wxEntry
663//-----------------------------------------------------------------------------
664
665int wxEntry( int argc, char *argv[] )
666{
0d2a2b60 667 gtk_set_locale();
c801d85f 668
dcf924a3 669 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
002f4218 670
0d2a2b60 671 gtk_init( &argc, &argv );
0cf2cb36 672
f0492f7d
RR
673 wxSetDetectableAutoRepeat( TRUE );
674
60acb947
VZ
675 if (!wxApp::Initialize())
676 return -1;
0cf2cb36 677
ec758a20 678 if (!wxTheApp)
c801d85f 679 {
60acb947 680 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
9cc7a35d 681 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
0cf2cb36 682
ec758a20 683 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 684
ec758a20 685 wxObject *test_app = app_ini();
0cf2cb36 686
ec758a20
RR
687 wxTheApp = (wxApp*) test_app;
688 }
0cf2cb36 689
9cc7a35d 690 wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
c801d85f 691
ec758a20
RR
692 wxTheApp->argc = argc;
693 wxTheApp->argv = argv;
0cf2cb36 694
8801832d 695 wxString name(wxFileNameFromPath(argv[0]));
ec758a20
RR
696 wxStripExtension( name );
697 wxTheApp->SetAppName( name );
e0253070 698
0151c3eb
VZ
699 int retValue = 0;
700
701 if ( !wxTheApp->OnInitGui() )
702 retValue = -1;
c801d85f 703
8801832d
VZ
704 // Here frames insert themselves automatically into wxTopLevelWindows by
705 // getting created in OnInit().
0151c3eb
VZ
706 if ( retValue == 0 )
707 {
708 if ( !wxTheApp->OnInit() )
709 retValue = -1;
710 }
0cf2cb36 711
0151c3eb
VZ
712 if ( retValue == 0 )
713 {
cfb50f14
RR
714 /* delete pending toplevel windows (typically a single
715 dialog) so that, if there isn't any left, we don't
716 call OnRun() */
717 wxTheApp->DeletePendingObjects();
718
0151c3eb 719 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 720
0151c3eb 721 if (wxTheApp->Initialized())
cfb50f14 722 {
0151c3eb 723 retValue = wxTheApp->OnRun();
0cf2cb36 724
cfb50f14
RR
725 wxWindow *topWindow = wxTheApp->GetTopWindow();
726 if (topWindow)
0151c3eb 727 {
cfb50f14
RR
728 /* Forcibly delete the window. */
729 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
730 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
731 {
732 topWindow->Close( TRUE );
733 wxTheApp->DeletePendingObjects();
734 }
735 else
736 {
737 delete topWindow;
738 wxTheApp->SetTopWindow( (wxWindow*) NULL );
739 }
740 }
741 wxTheApp->OnExit();
0d2a2b60 742 }
0151c3eb 743 }
0cf2cb36 744
88ac883a 745#if wxUSE_LOG
60acb947 746 // flush the logged messages if any
0d2a2b60
RR
747 wxLog *log = wxLog::GetActiveTarget();
748 if (log != NULL && log->HasPendingMessages())
749 log->Flush();
750
60acb947
VZ
751 // continuing to use user defined log target is unsafe from now on because
752 // some resources may be already unavailable, so replace it by something
753 // more safe
754 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
755 if ( oldlog )
756 delete oldlog;
88ac883a 757#endif // wxUSE_LOG
60acb947 758
0d2a2b60 759 wxApp::CleanUp();
184b5d99 760
ec758a20 761 return retValue;
ff7b1510 762}
1a56f55c 763