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