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