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