]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/app.cpp
force making stats
[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
df744f4d
JJ
14#ifdef __VMS
15#include <vms_jackets.h>
16#endif
17
c801d85f
KB
18#include "wx/app.h"
19#include "wx/gdicmn.h"
20#include "wx/utils.h"
c801d85f
KB
21#include "wx/intl.h"
22#include "wx/log.h"
46dc76ba 23#include "wx/memory.h"
a3622daa
VZ
24#include "wx/font.h"
25#include "wx/settings.h"
0d2a2b60 26#include "wx/dialog.h"
94a6f0f8 27#include "wx/msgdlg.h"
b1ac3b56 28#include "wx/file.h"
afb74891 29
06cfab17 30#if wxUSE_WX_RESOURCES
afb74891 31 #include "wx/resource.h"
f5abe911 32#endif
afb74891 33
031b2a7b 34#include "wx/module.h"
4bc67cc5 35#include "wx/image.h"
afb74891 36
df028524
VS
37#ifdef __WXUNIVERSAL__
38 #include "wx/univ/theme.h"
39 #include "wx/univ/renderer.h"
40#endif
41
91b8de8d 42#if wxUSE_THREADS
a37a5a73 43 #include "wx/thread.h"
91b8de8d 44#endif
afb74891 45
20e05ffb 46#include <unistd.h>
c690ae86
GD
47#if defined(__DARWIN__)
48// FIXME: select must be used instead of poll (GD)
49#elif defined(__VMS)
df744f4d
JJ
50# include <poll.h>
51#else
52# include <sys/poll.h>
53#endif
e8106239 54#include "wx/gtk/win_gtk.h"
c801d85f 55
20e05ffb 56#include <gtk/gtk.h>
24178e4a 57
83624f79 58
c801d85f
KB
59//-----------------------------------------------------------------------------
60// global data
61//-----------------------------------------------------------------------------
62
c67daf87 63wxApp *wxTheApp = (wxApp *) NULL;
32d4bfd1 64wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
c801d85f 65
96997d65
RR
66bool g_mainThreadLocked = FALSE;
67gint g_pendingTag = 0;
3ac8d3bc 68
c2fa61e8 69static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
d76fe38b 70
c801d85f 71//-----------------------------------------------------------------------------
3133cb9f 72// idle system
c801d85f
KB
73//-----------------------------------------------------------------------------
74
3133cb9f 75extern bool g_isIdle;
c4fda16b 76
90350682 77void wxapp_install_idle_handler();
bf9e3e73 78
c801d85f 79//-----------------------------------------------------------------------------
bf9e3e73 80// wxExit
c801d85f
KB
81//-----------------------------------------------------------------------------
82
60acb947 83void wxExit()
c801d85f 84{
ec758a20 85 gtk_main_quit();
ff7b1510 86}
c801d85f 87
bf9e3e73
RR
88//-----------------------------------------------------------------------------
89// wxYield
90//-----------------------------------------------------------------------------
53a8af59 91
1ee339ee
VZ
92// not static because used by textctrl.cpp
93//
94// MT-FIXME
95bool wxIsInsideYield = FALSE;
96
8461e4c2 97bool wxApp::Yield(bool onlyIfNeeded)
c801d85f 98{
1ee339ee 99 if ( wxIsInsideYield )
8461e4c2
VZ
100 {
101 if ( !onlyIfNeeded )
102 {
103 wxFAIL_MSG( wxT("wxYield called recursively" ) );
104 }
105
106 return FALSE;
107 }
108
6dc5fd71
VZ
109#if wxUSE_THREADS
110 if ( !wxThread::IsMain() )
111 {
112 // can't call gtk_main_iteration() from other threads like this
113 return TRUE;
114 }
115#endif // wxUSE_THREADS
116
1ee339ee 117 wxIsInsideYield = TRUE;
e90c1d2a 118
99ba739f 119 if (!g_isIdle)
acfd422a 120 {
99ba739f
RR
121 // We need to remove idle callbacks or the loop will
122 // never finish.
8461e4c2
VZ
123 gtk_idle_remove( m_idleTag );
124 m_idleTag = 0;
99ba739f 125 g_isIdle = TRUE;
956dbab1 126 }
acfd422a 127
2ed3265e
VZ
128 // disable log flushing from here because a call to wxYield() shouldn't
129 // normally result in message boxes popping up &c
130 wxLog::Suspend();
131
406a6f6b
VZ
132 while (gtk_events_pending())
133 gtk_main_iteration();
134
5375a1f5
RR
135 // It's necessary to call ProcessIdle() to update the frames sizes which
136 // might have been changed (it also will update other things set from
be88a6ad 137 // OnUpdateUI() which is a nice (and desired) side effect). But we
5375a1f5
RR
138 // call ProcessIdle() only once since this is not meant for longish
139 // background jobs (controlled by wxIdleEvent::RequestMore() and the
140 // return value of Processidle().
141 ProcessIdle();
2ed3265e
VZ
142
143 // let the logs be flashed again
144 wxLog::Resume();
7741c4e1 145
1ee339ee 146 wxIsInsideYield = FALSE;
99ba739f 147
acfd422a
RR
148 return TRUE;
149}
150
bf9e3e73
RR
151//-----------------------------------------------------------------------------
152// wxWakeUpIdle
153//-----------------------------------------------------------------------------
154
155void wxWakeUpIdle()
156{
924ef850
RR
157#if wxUSE_THREADS
158 if (!wxThread::IsMain())
ce6d2511 159 wxMutexGuiEnter();
924ef850
RR
160#endif
161
2286341c 162 if (g_isIdle)
bf9e3e73 163 wxapp_install_idle_handler();
2286341c 164
924ef850
RR
165#if wxUSE_THREADS
166 if (!wxThread::IsMain())
ce6d2511 167 wxMutexGuiLeave();
924ef850 168#endif
bf9e3e73
RR
169}
170
171//-----------------------------------------------------------------------------
172// local functions
173//-----------------------------------------------------------------------------
174
90350682
VZ
175// the callback functions must be extern "C" to comply with GTK+ declarations
176extern "C"
177{
178
3133cb9f 179static gint wxapp_pending_callback( gpointer WXUNUSED(data) )
acfd422a
RR
180{
181 if (!wxTheApp) return TRUE;
c2fa61e8 182
5375a1f5 183 // When getting called from GDK's time-out handler
96997d65 184 // we are no longer within GDK's grab on the GUI
5375a1f5 185 // thread so we must lock it here ourselves.
96997d65
RR
186 gdk_threads_enter();
187
5375a1f5 188 // Sent idle event to all who request them.
96997d65 189 wxTheApp->ProcessPendingEvents();
e90c1d2a 190
96997d65
RR
191 g_pendingTag = 0;
192
5375a1f5 193 // Flush the logged messages if any.
1b2dab34
RR
194#if wxUSE_LOG
195 wxLog::FlushActive();
196#endif // wxUSE_LOG
197
96997d65
RR
198 // Release lock again
199 gdk_threads_leave();
200
201 // Return FALSE to indicate that no more idle events are
202 // to be sent (single shot instead of continuous stream)
203 return FALSE;
204}
205
3133cb9f 206static gint wxapp_idle_callback( gpointer WXUNUSED(data) )
96997d65 207{
a5f1fd3e
VZ
208 if (!wxTheApp)
209 return TRUE;
210
211#ifdef __WXDEBUG__
6d477bb4
VZ
212 // don't generate the idle events while the assert modal dialog is shown,
213 // this completely confuses the apps which don't expect to be reentered
214 // from some safely-looking functions
a5f1fd3e
VZ
215 if ( wxTheApp->IsInAssert() )
216 {
94a6f0f8
JS
217 // But repaint the assertion message if necessary
218 if (wxTopLevelWindows.GetCount() > 0)
219 {
220 wxWindow* win = (wxWindow*) wxTopLevelWindows.Last()->Data();
221 if (win->IsKindOf(CLASSINFO(wxGenericMessageDialog)))
222 win->OnInternalIdle();
223 }
6d477bb4 224 return TRUE;
a5f1fd3e
VZ
225 }
226#endif // __WXDEBUG__
c2fa61e8 227
5375a1f5 228 // When getting called from GDK's time-out handler
924ef850 229 // we are no longer within GDK's grab on the GUI
5375a1f5 230 // thread so we must lock it here ourselves.
924ef850 231 gdk_threads_enter();
094637f6 232
5375a1f5
RR
233 // Indicate that we are now in idle mode and event handlers
234 // will have to reinstall the idle handler again.
acfd422a 235 g_isIdle = TRUE;
96997d65 236 wxTheApp->m_idleTag = 0;
094637f6 237
3133cb9f 238 // Send idle event to all who request them as long as
5375a1f5
RR
239 // no events have popped up in the event queue.
240 while (wxTheApp->ProcessIdle() && (gtk_events_pending() == 0))
6d477bb4 241 ;
c9e35272 242
96997d65 243 // Release lock again
924ef850 244 gdk_threads_leave();
acfd422a 245
96997d65 246 // Return FALSE to indicate that no more idle events are
5375a1f5 247 // to be sent (single shot instead of continuous stream).
96997d65 248 return FALSE;
acfd422a 249}
8801832d 250
90350682
VZ
251#if wxUSE_THREADS
252
3133cb9f 253static gint wxapp_poll_func( GPollFD *ufds, guint nfds, gint timeout )
acfd422a 254{
3133cb9f 255 gint res;
90350682 256 gdk_threads_enter();
7b90a8f2 257
90350682 258 wxMutexGuiLeave();
90350682 259 g_mainThreadLocked = TRUE;
7941ba11 260
c690ae86
GD
261#ifdef __DARWIN__
262 // FIXME: poll is not available under Darwin/Mac OS X and this needs
263 // to be implemented using select instead (GD)
264 // what about other BSD derived systems?
265 res = -1;
266#else
3133cb9f 267 res = poll( (struct pollfd*) ufds, nfds, timeout );
c690ae86 268#endif
90350682 269
90350682 270 wxMutexGuiEnter();
90350682
VZ
271 g_mainThreadLocked = FALSE;
272
90350682
VZ
273 gdk_threads_leave();
274
3133cb9f 275 return res;
ff7b1510 276}
c801d85f 277
90350682
VZ
278#endif // wxUSE_THREADS
279
280} // extern "C"
281
3133cb9f 282void wxapp_install_idle_handler()
b453e1b2 283{
3133cb9f 284 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
c2fa61e8 285
3133cb9f 286 g_isIdle = FALSE;
96997d65 287
3133cb9f
RR
288 if (g_pendingTag == 0)
289 g_pendingTag = gtk_idle_add_priority( 900, wxapp_pending_callback, (gpointer) NULL );
e90c1d2a 290
3133cb9f
RR
291 // This routine gets called by all event handlers
292 // indicating that the idle is over. It may also
293 // get called from other thread for sending events
294 // to the main thread (and processing these in
295 // idle time). Very low priority.
296 wxTheApp->m_idleTag = gtk_idle_add_priority( 1000, wxapp_idle_callback, (gpointer) NULL );
b453e1b2
RR
297}
298
005f5d18
RR
299//-----------------------------------------------------------------------------
300// Access to the root window global
301//-----------------------------------------------------------------------------
302
303GtkWidget* wxGetRootWindow()
304{
305 if (gs_RootWindow == NULL)
306 {
307 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
308 gtk_widget_realize( gs_RootWindow );
309 }
310 return gs_RootWindow;
311}
312
c801d85f
KB
313//-----------------------------------------------------------------------------
314// wxApp
315//-----------------------------------------------------------------------------
316
317IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
318
53010e52
RR
319BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
320 EVT_IDLE(wxApp::OnIdle)
321END_EVENT_TABLE()
322
c801d85f
KB
323wxApp::wxApp()
324{
a5f1fd3e
VZ
325 m_initialized = FALSE;
326#ifdef __WXDEBUG__
327 m_isInAssert = FALSE;
328#endif // __WXDEBUG__
329
df5ddbca
RR
330 m_idleTag = 0;
331 wxapp_install_idle_handler();
094637f6 332
6b3eb77a 333#if wxUSE_THREADS
3133cb9f 334 g_main_set_poll_func( wxapp_poll_func );
6b3eb77a 335#endif
60acb947 336
f6fcbb63 337 m_colorCube = (unsigned char*) NULL;
be88a6ad 338
a6f5aa49
VZ
339 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
340 m_glVisualInfo = (void *) NULL;
ff7b1510 341}
c801d85f 342
60acb947 343wxApp::~wxApp()
c801d85f 344{
acfd422a 345 if (m_idleTag) gtk_idle_remove( m_idleTag );
60acb947 346
f6fcbb63 347 if (m_colorCube) free(m_colorCube);
ff7b1510 348}
c801d85f 349
0d2a2b60 350bool wxApp::OnInitGui()
c801d85f 351{
1e6feb95
VZ
352 if ( !wxAppBase::OnInitGui() )
353 return FALSE;
354
b134516c
RR
355 GdkVisual *visual = gdk_visual_get_system();
356
a6f5aa49
VZ
357 // if this is a wxGLApp (derived from wxApp), and we've already
358 // chosen a specific visual, then derive the GdkVisual from that
005f5d18
RR
359 if (m_glVisualInfo != NULL)
360 {
a6f5aa49 361#ifdef __WXGTK20__
005f5d18 362 // seems gtk_widget_set_default_visual no longer exists?
a6f5aa49
VZ
363 GdkVisual* vis = gtk_widget_get_default_visual();
364#else
be88a6ad 365 GdkVisual* vis = gdkx_visual_get(
a6f5aa49
VZ
366 ((XVisualInfo *) m_glVisualInfo) ->visualid );
367 gtk_widget_set_default_visual( vis );
368#endif
369
370 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
371 gtk_widget_set_default_colormap( colormap );
372
373 visual = vis;
374 }
be88a6ad 375
005f5d18
RR
376 // On some machines, the default visual is just 256 colours, so
377 // we make sure we get the best. This can sometimes be wasteful.
2286341c 378
005f5d18
RR
379 else
380 if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual))
b134516c 381 {
2d4dc3a4
OK
382#ifdef __WXGTK20__
383 /* seems gtk_widget_set_default_visual no longer exists? */
384 GdkVisual* vis = gtk_widget_get_default_visual();
385#else
b134516c
RR
386 GdkVisual* vis = gdk_visual_get_best();
387 gtk_widget_set_default_visual( vis );
2d4dc3a4 388#endif
f6fcbb63 389
b134516c
RR
390 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
391 gtk_widget_set_default_colormap( colormap );
094637f6
VZ
392
393 visual = vis;
b134516c 394 }
d76fe38b 395
005f5d18 396 // Nothing to do for 15, 16, 24, 32 bit displays
f6fcbb63 397 if (visual->depth > 8) return TRUE;
60acb947 398
005f5d18 399 // initialize color cube for 8-bit color reduction dithering
60acb947 400
f6fcbb63 401 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 402
f6fcbb63
RR
403 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
404
f03fc89f
VZ
405 for (int r = 0; r < 32; r++)
406 {
8801832d
VZ
407 for (int g = 0; g < 32; g++)
408 {
409 for (int b = 0; b < 32; b++)
410 {
411 int rr = (r << 3) | (r >> 2);
412 int gg = (g << 3) | (g >> 2);
413 int bb = (b << 3) | (b >> 2);
60acb947 414
f03fc89f
VZ
415 int index = -1;
416
f6fcbb63 417 GdkColor *colors = cmap->colors;
ca26177c 418 if (colors)
f03fc89f
VZ
419 {
420 int max = 3 * 65536;
421
422 for (int i = 0; i < cmap->size; i++)
423 {
424 int rdiff = ((rr << 8) - colors[i].red);
425 int gdiff = ((gg << 8) - colors[i].green);
426 int bdiff = ((bb << 8) - colors[i].blue);
427 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
428 if (sum < max)
094637f6 429 {
f03fc89f
VZ
430 index = i; max = sum;
431 }
432 }
f6fcbb63 433 }
094637f6
VZ
434 else
435 {
005f5d18 436 // assume 8-bit true or static colors. this really exists
094637f6
VZ
437 GdkVisual* vis = gdk_colormap_get_visual( cmap );
438 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
439 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
440 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
094637f6 441 }
8801832d
VZ
442 m_colorCube[ (r*1024) + (g*32) + b ] = index;
443 }
444 }
f6fcbb63 445 }
c801d85f 446
bbe0af5b
RR
447 return TRUE;
448}
449
005f5d18
RR
450GdkVisual *wxApp::GetGdkVisual()
451{
452 GdkVisual *visual = NULL;
be88a6ad 453
005f5d18 454 if (m_glVisualInfo)
7b775074 455 visual = gdkx_visual_get( ((XVisualInfo *) m_glVisualInfo)->visualid );
005f5d18
RR
456 else
457 visual = gdk_window_get_visual( wxGetRootWindow()->window );
be88a6ad 458
005f5d18 459 wxASSERT( visual );
be88a6ad 460
005f5d18
RR
461 return visual;
462}
463
60acb947 464bool wxApp::ProcessIdle()
53010e52 465{
ec758a20
RR
466 wxIdleEvent event;
467 event.SetEventObject( this );
468 ProcessEvent( event );
0cf2cb36 469
ec758a20 470 return event.MoreRequested();
ff7b1510 471}
53010e52
RR
472
473void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 474{
956dbab1 475 static bool s_inOnIdle = FALSE;
2286341c 476
5375a1f5 477 // Avoid recursion (via ProcessEvent default case)
956dbab1 478 if (s_inOnIdle)
ec758a20 479 return;
2286341c 480
956dbab1 481 s_inOnIdle = TRUE;
53010e52 482
5375a1f5
RR
483 // Resend in the main thread events which have been prepared in other
484 // threads
7214297d
GL
485 ProcessPendingEvents();
486
5375a1f5 487 // 'Garbage' collection of windows deleted with Close()
ec758a20 488 DeletePendingObjects();
53010e52 489
5375a1f5 490 // Send OnIdle events to all windows
ec758a20 491 bool needMore = SendIdleEvents();
53010e52 492
ec758a20
RR
493 if (needMore)
494 event.RequestMore(TRUE);
53010e52 495
956dbab1 496 s_inOnIdle = FALSE;
ff7b1510 497}
53010e52 498
60acb947 499bool wxApp::SendIdleEvents()
53010e52
RR
500{
501 bool needMore = FALSE;
e0253070 502
e146b8c8 503 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
504 while (node)
505 {
e146b8c8 506 wxWindow* win = node->GetData();
f3855ef0 507 if (SendIdleEvents(win))
53010e52 508 needMore = TRUE;
be88a6ad 509
e146b8c8 510 node = node->GetNext();
ec758a20 511 }
e146b8c8 512
010afced
RR
513 node = wxTopLevelWindows.GetFirst();
514 while (node)
515 {
516 wxWindow* win = node->GetData();
517 CallInternalIdle( win );
be88a6ad 518
010afced
RR
519 node = node->GetNext();
520 }
53010e52 521 return needMore;
ff7b1510 522}
53010e52 523
010afced
RR
524bool wxApp::CallInternalIdle( wxWindow* win )
525{
526 win->OnInternalIdle();
527
528 wxNode* node = win->GetChildren().First();
529 while (node)
530 {
531 wxWindow* win = (wxWindow*) node->Data();
532 CallInternalIdle( win );
533
534 node = node->Next();
535 }
be88a6ad 536
010afced
RR
537 return TRUE;
538}
539
53010e52
RR
540bool wxApp::SendIdleEvents( wxWindow* win )
541{
542 bool needMore = FALSE;
543
8bbe427f
VZ
544 wxIdleEvent event;
545 event.SetEventObject(win);
60acb947 546
f6bcfd97 547 win->GetEventHandler()->ProcessEvent(event);
fab591c5 548
53010e52
RR
549 if (event.MoreRequested())
550 needMore = TRUE;
551
8bbe427f
VZ
552 wxNode* node = win->GetChildren().First();
553 while (node)
554 {
555 wxWindow* win = (wxWindow*) node->Data();
556 if (SendIdleEvents(win))
53010e52
RR
557 needMore = TRUE;
558
8bbe427f
VZ
559 node = node->Next();
560 }
be88a6ad 561
0d1dff01 562 return needMore;
ff7b1510 563}
c801d85f 564
60acb947 565int wxApp::MainLoop()
c801d85f 566{
ec758a20
RR
567 gtk_main();
568 return 0;
ff7b1510 569}
c801d85f 570
60acb947 571void wxApp::ExitMainLoop()
c801d85f 572{
7ec2881a
RR
573 if (gtk_main_level() > 0)
574 gtk_main_quit();
ff7b1510 575}
c801d85f 576
60acb947 577bool wxApp::Initialized()
c801d85f 578{
ec758a20 579 return m_initialized;
ff7b1510 580}
c801d85f 581
60acb947 582bool wxApp::Pending()
c801d85f 583{
acfd422a 584 return (gtk_events_pending() > 0);
ff7b1510 585}
c801d85f 586
60acb947 587void wxApp::Dispatch()
c801d85f 588{
8801832d 589 gtk_main_iteration();
ff7b1510 590}
c801d85f 591
60acb947 592void wxApp::DeletePendingObjects()
c801d85f 593{
ec758a20
RR
594 wxNode *node = wxPendingDelete.First();
595 while (node)
596 {
597 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 598
ec758a20 599 delete obj;
c801d85f 600
f03fc89f
VZ
601 if (wxPendingDelete.Find(obj))
602 delete node;
c801d85f 603
ec758a20
RR
604 node = wxPendingDelete.First();
605 }
ff7b1510 606}
c801d85f 607
60acb947 608bool wxApp::Initialize()
c801d85f 609{
0d2a2b60 610 wxClassInfo::InitializeClasses();
60acb947 611
5c3e299e 612#if wxUSE_INTL
a92b8709 613 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
5c3e299e 614#endif
60acb947 615
4d3a259a
GL
616 // GL: I'm annoyed ... I don't know where to put this and I don't want to
617 // create a module for that as it's part of the core.
618#if wxUSE_THREADS
619 wxPendingEvents = new wxList();
620 wxPendingEventsLocker = new wxCriticalSection();
621#endif
622
0d2a2b60
RR
623 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
624 wxTheColourDatabase->Initialize();
a3622daa 625
0d2a2b60
RR
626 wxInitializeStockLists();
627 wxInitializeStockObjects();
c801d85f 628
4a0c68a7
RR
629#if wxUSE_WX_RESOURCES
630 wxInitializeResourceSystem();
631#endif
632
0d2a2b60
RR
633 wxModule::RegisterModules();
634 if (!wxModule::InitializeModules()) return FALSE;
60acb947 635
0d2a2b60 636 return TRUE;
ff7b1510 637}
c801d85f 638
60acb947 639void wxApp::CleanUp()
c801d85f 640{
0d2a2b60 641 wxModule::CleanUpModules();
0cf2cb36 642
4a0c68a7
RR
643#if wxUSE_WX_RESOURCES
644 wxCleanUpResourceSystem();
645#endif
646
a11672a4 647 delete wxTheColourDatabase;
0d2a2b60 648 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 649
0d2a2b60
RR
650 wxDeleteStockObjects();
651
ec758a20 652 wxDeleteStockLists();
a3622daa 653
0d2a2b60
RR
654 delete wxTheApp;
655 wxTheApp = (wxApp*) NULL;
656
a11672a4
RR
657 wxClassInfo::CleanUpClasses();
658
4d3a259a
GL
659#if wxUSE_THREADS
660 delete wxPendingEvents;
661 delete wxPendingEventsLocker;
662#endif
663
60acb947 664 // check for memory leaks
0d2a2b60 665#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
6981d3ec 666 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
0d2a2b60 667 {
223d09f6 668 wxLogDebug(wxT("There were memory leaks.\n"));
0d2a2b60
RR
669 wxDebugContext::Dump();
670 wxDebugContext::PrintStatistics();
671 }
8801832d 672#endif // Debug
0d2a2b60 673
88ac883a 674#if wxUSE_LOG
60acb947 675 // do this as the very last thing because everything else can log messages
0d2a2b60 676 wxLog::DontCreateOnDemand();
60acb947 677
0d2a2b60 678 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
679 if (oldLog)
680 delete oldLog;
88ac883a 681#endif // wxUSE_LOG
c19c1ca9 682}
c801d85f
KB
683
684//-----------------------------------------------------------------------------
685// wxEntry
686//-----------------------------------------------------------------------------
687
17154fc8
VZ
688// NB: argc and argv may be changed here, pass by reference!
689int wxEntryStart( int& argc, char *argv[] )
c801d85f 690{
924ef850 691#if wxUSE_THREADS
005f5d18
RR
692 // GTK 1.2 up to version 1.2.3 has broken threads
693 if ((gtk_major_version == 1) &&
8f75cb6c 694 (gtk_minor_version == 2) &&
2286341c 695 (gtk_micro_version < 4))
96997d65 696 {
fb65642c 697 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
8f75cb6c
RR
698 }
699 else
700 {
701 g_thread_init(NULL);
702 }
924ef850 703#endif
2286341c 704
0d2a2b60 705 gtk_set_locale();
c801d85f 706
f9862abd
JS
707 // We should have the wxUSE_WCHAR_T test on the _outside_
708#if wxUSE_WCHAR_T
2d4dc3a4
OK
709#if defined(__WXGTK20__)
710 // gtk+ 2.0 supports Unicode through UTF-8 strings
711 wxConvCurrent = &wxConvUTF8;
f9862abd 712#else
dcf924a3 713 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
f9862abd 714#endif
fd9811b1
RR
715#else
716 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
717#endif
002f4218 718
924ef850
RR
719 gdk_threads_enter();
720
0d2a2b60 721 gtk_init( &argc, &argv );
0cf2cb36 722
f0492f7d 723 wxSetDetectableAutoRepeat( TRUE );
094637f6 724
60acb947 725 if (!wxApp::Initialize())
924ef850
RR
726 {
727 gdk_threads_leave();
60acb947 728 return -1;
924ef850 729 }
0cf2cb36 730
954de0f1
RD
731 return 0;
732}
733
c2fa61e8 734
954de0f1
RD
735int wxEntryInitGui()
736{
737 int retValue = 0;
738
739 if ( !wxTheApp->OnInitGui() )
740 retValue = -1;
741
c2fa61e8 742 wxGetRootWindow();
954de0f1
RD
743
744 return retValue;
745}
746
747
748void wxEntryCleanup()
749{
750#if wxUSE_LOG
751 // flush the logged messages if any
752 wxLog *log = wxLog::GetActiveTarget();
753 if (log != NULL && log->HasPendingMessages())
754 log->Flush();
755
756 // continuing to use user defined log target is unsafe from now on because
757 // some resources may be already unavailable, so replace it by something
758 // more safe
759 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
760 if ( oldlog )
761 delete oldlog;
762#endif // wxUSE_LOG
763
764 wxApp::CleanUp();
765
766 gdk_threads_leave();
767}
768
769
954de0f1
RD
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 {
047ac72b 830 // Delete pending toplevel windows
cfb50f14 831 wxTheApp->DeletePendingObjects();
094637f6 832
047ac72b
RR
833 // When is the app not initialized ?
834 wxTheApp->m_initialized = TRUE;
0cf2cb36 835
0151c3eb 836 if (wxTheApp->Initialized())
094637f6 837 {
2286341c 838 wxTheApp->OnRun();
0cf2cb36 839
cfb50f14 840 wxWindow *topWindow = wxTheApp->GetTopWindow();
be88a6ad 841
047ac72b
RR
842 // Delete all pending windows if any
843 wxTheApp->DeletePendingObjects();
be88a6ad
RD
844
845 // Reset top window
cfb50f14 846 if (topWindow)
047ac72b 847 wxTheApp->SetTopWindow( (wxWindow*) NULL );
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
a5f1fd3e
VZ
858#ifdef __WXDEBUG__
859
be88a6ad 860void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
a5f1fd3e
VZ
861{
862 m_isInAssert = TRUE;
863
be88a6ad 864 wxAppBase::OnAssert(file, line, cond, msg);
a5f1fd3e
VZ
865
866 m_isInAssert = FALSE;
867}
868
869#endif // __WXDEBUG__
870