]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/app.cpp
corrected wxMenuBar::Insert , ::Append for a correct title even when the menubar...
[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
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
c801d85f
KB
321//-----------------------------------------------------------------------------
322// wxApp
323//-----------------------------------------------------------------------------
324
325IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
326
53010e52
RR
327BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
328 EVT_IDLE(wxApp::OnIdle)
329END_EVENT_TABLE()
330
c801d85f
KB
331wxApp::wxApp()
332{
a5f1fd3e
VZ
333 m_initialized = FALSE;
334#ifdef __WXDEBUG__
335 m_isInAssert = FALSE;
336#endif // __WXDEBUG__
337
df5ddbca
RR
338 m_idleTag = 0;
339 wxapp_install_idle_handler();
094637f6 340
6b3eb77a 341#if wxUSE_THREADS
b453e1b2
RR
342 m_wakeUpTimerTag = 0;
343 wxapp_install_thread_wakeup();
6b3eb77a 344#endif
60acb947 345
f6fcbb63 346 m_colorCube = (unsigned char*) NULL;
a6f5aa49
VZ
347
348 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
349 m_glVisualInfo = (void *) NULL;
ff7b1510 350}
c801d85f 351
60acb947 352wxApp::~wxApp()
c801d85f 353{
acfd422a 354 if (m_idleTag) gtk_idle_remove( m_idleTag );
60acb947 355
6b3eb77a 356#if wxUSE_THREADS
b453e1b2 357 wxapp_uninstall_thread_wakeup();
6b3eb77a 358#endif
094637f6 359
f6fcbb63 360 if (m_colorCube) free(m_colorCube);
ff7b1510 361}
c801d85f 362
0d2a2b60 363bool wxApp::OnInitGui()
c801d85f 364{
1e6feb95
VZ
365 if ( !wxAppBase::OnInitGui() )
366 return FALSE;
367
b134516c
RR
368 GdkVisual *visual = gdk_visual_get_system();
369
a6f5aa49
VZ
370 // if this is a wxGLApp (derived from wxApp), and we've already
371 // chosen a specific visual, then derive the GdkVisual from that
372 if (m_glVisualInfo != NULL) {
373#ifdef __WXGTK20__
374 /* seems gtk_widget_set_default_visual no longer exists? */
375 GdkVisual* vis = gtk_widget_get_default_visual();
376#else
377 GdkVisual* vis = gdkx_visual_get(
378 ((XVisualInfo *) m_glVisualInfo) ->visualid );
379 gtk_widget_set_default_visual( vis );
380#endif
381
382 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
383 gtk_widget_set_default_colormap( colormap );
384
385 visual = vis;
386 }
387
094637f6 388 /* on some machines, the default visual is just 256 colours, so
b134516c 389 we make sure we get the best. this can sometimes be wasteful,
7b280524 390 of course, but what do these guys pay $30.000 for? */
2286341c 391
a6f5aa49 392 else if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
8480b297 393 (m_useBestVisual))
b134516c 394 {
2d4dc3a4
OK
395#ifdef __WXGTK20__
396 /* seems gtk_widget_set_default_visual no longer exists? */
397 GdkVisual* vis = gtk_widget_get_default_visual();
398#else
b134516c
RR
399 GdkVisual* vis = gdk_visual_get_best();
400 gtk_widget_set_default_visual( vis );
2d4dc3a4 401#endif
f6fcbb63 402
b134516c
RR
403 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
404 gtk_widget_set_default_colormap( colormap );
094637f6
VZ
405
406 visual = vis;
b134516c 407 }
d76fe38b 408
7b280524 409 /* Nothing to do for 15, 16, 24, 32 bit displays */
f6fcbb63 410 if (visual->depth > 8) return TRUE;
60acb947 411
f6fcbb63 412 /* initialize color cube for 8-bit color reduction dithering */
60acb947 413
f6fcbb63 414 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 415
f6fcbb63
RR
416 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
417
f03fc89f
VZ
418 for (int r = 0; r < 32; r++)
419 {
8801832d
VZ
420 for (int g = 0; g < 32; g++)
421 {
422 for (int b = 0; b < 32; b++)
423 {
424 int rr = (r << 3) | (r >> 2);
425 int gg = (g << 3) | (g >> 2);
426 int bb = (b << 3) | (b >> 2);
60acb947 427
f03fc89f
VZ
428 int index = -1;
429
f6fcbb63 430 GdkColor *colors = cmap->colors;
ca26177c 431 if (colors)
f03fc89f
VZ
432 {
433 int max = 3 * 65536;
434
435 for (int i = 0; i < cmap->size; i++)
436 {
437 int rdiff = ((rr << 8) - colors[i].red);
438 int gdiff = ((gg << 8) - colors[i].green);
439 int bdiff = ((bb << 8) - colors[i].blue);
440 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
441 if (sum < max)
094637f6 442 {
f03fc89f
VZ
443 index = i; max = sum;
444 }
445 }
f6fcbb63 446 }
094637f6
VZ
447 else
448 {
58c7cd12 449#if (GTK_MINOR_VERSION > 0)
094637f6
VZ
450 /* assume 8-bit true or static colors. this really
451 exists. */
452 GdkVisual* vis = gdk_colormap_get_visual( cmap );
453 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
454 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
455 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
58c7cd12 456#else
223d09f6 457 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
58c7cd12 458#endif
094637f6 459 }
8801832d
VZ
460 m_colorCube[ (r*1024) + (g*32) + b ] = index;
461 }
462 }
f6fcbb63 463 }
c801d85f 464
bbe0af5b
RR
465 return TRUE;
466}
467
60acb947 468bool wxApp::ProcessIdle()
53010e52 469{
ec758a20
RR
470 wxIdleEvent event;
471 event.SetEventObject( this );
472 ProcessEvent( event );
0cf2cb36 473
ec758a20 474 return event.MoreRequested();
ff7b1510 475}
53010e52
RR
476
477void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 478{
956dbab1 479 static bool s_inOnIdle = FALSE;
2286341c 480
d524867f 481 /* Avoid recursion (via ProcessEvent default case) */
956dbab1 482 if (s_inOnIdle)
ec758a20 483 return;
2286341c 484
956dbab1 485 s_inOnIdle = TRUE;
53010e52 486
7214297d
GL
487 /* Resend in the main thread events which have been prepared in other
488 threads */
489 ProcessPendingEvents();
490
d524867f 491 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 492 DeletePendingObjects();
53010e52 493
d524867f 494 /* Send OnIdle events to all windows */
ec758a20 495 bool needMore = SendIdleEvents();
53010e52 496
ec758a20
RR
497 if (needMore)
498 event.RequestMore(TRUE);
53010e52 499
956dbab1 500 s_inOnIdle = FALSE;
ff7b1510 501}
53010e52 502
60acb947 503bool wxApp::SendIdleEvents()
53010e52
RR
504{
505 bool needMore = FALSE;
e0253070 506
e146b8c8 507 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
508 while (node)
509 {
e146b8c8 510 wxWindow* win = node->GetData();
f3855ef0 511 if (SendIdleEvents(win))
53010e52 512 needMore = TRUE;
e146b8c8 513 node = node->GetNext();
ec758a20 514 }
e146b8c8 515
53010e52 516 return needMore;
ff7b1510 517}
53010e52
RR
518
519bool wxApp::SendIdleEvents( wxWindow* win )
520{
521 bool needMore = FALSE;
522
8bbe427f
VZ
523 wxIdleEvent event;
524 event.SetEventObject(win);
60acb947 525
f6bcfd97 526 win->GetEventHandler()->ProcessEvent(event);
53010e52 527
e70f5e13 528 win->OnInternalIdle();
e90c1d2a 529
53010e52
RR
530 if (event.MoreRequested())
531 needMore = TRUE;
532
8bbe427f
VZ
533 wxNode* node = win->GetChildren().First();
534 while (node)
535 {
536 wxWindow* win = (wxWindow*) node->Data();
537 if (SendIdleEvents(win))
53010e52
RR
538 needMore = TRUE;
539
8bbe427f
VZ
540 node = node->Next();
541 }
53010e52 542 return needMore ;
ff7b1510 543}
c801d85f 544
60acb947 545int wxApp::MainLoop()
c801d85f 546{
ec758a20
RR
547 gtk_main();
548 return 0;
ff7b1510 549}
c801d85f 550
60acb947 551void wxApp::ExitMainLoop()
c801d85f 552{
7ec2881a
RR
553 if (gtk_main_level() > 0)
554 gtk_main_quit();
ff7b1510 555}
c801d85f 556
60acb947 557bool wxApp::Initialized()
c801d85f 558{
ec758a20 559 return m_initialized;
ff7b1510 560}
c801d85f 561
60acb947 562bool wxApp::Pending()
c801d85f 563{
acfd422a 564 return (gtk_events_pending() > 0);
ff7b1510 565}
c801d85f 566
60acb947 567void wxApp::Dispatch()
c801d85f 568{
8801832d 569 gtk_main_iteration();
ff7b1510 570}
c801d85f 571
60acb947 572void wxApp::DeletePendingObjects()
c801d85f 573{
ec758a20
RR
574 wxNode *node = wxPendingDelete.First();
575 while (node)
576 {
577 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 578
ec758a20 579 delete obj;
c801d85f 580
f03fc89f
VZ
581 if (wxPendingDelete.Find(obj))
582 delete node;
c801d85f 583
ec758a20
RR
584 node = wxPendingDelete.First();
585 }
ff7b1510 586}
c801d85f 587
60acb947 588bool wxApp::Initialize()
c801d85f 589{
9cc7a35d 590 wxBuffer = new wxChar[BUFSIZ + 512];
0d2a2b60
RR
591
592 wxClassInfo::InitializeClasses();
60acb947 593
5c3e299e 594#if wxUSE_INTL
a92b8709 595 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
5c3e299e 596#endif
60acb947 597
4d3a259a
GL
598 // GL: I'm annoyed ... I don't know where to put this and I don't want to
599 // create a module for that as it's part of the core.
600#if wxUSE_THREADS
601 wxPendingEvents = new wxList();
602 wxPendingEventsLocker = new wxCriticalSection();
603#endif
604
0d2a2b60
RR
605 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
606 wxTheColourDatabase->Initialize();
a3622daa 607
0d2a2b60
RR
608 wxInitializeStockLists();
609 wxInitializeStockObjects();
c801d85f 610
4a0c68a7
RR
611#if wxUSE_WX_RESOURCES
612 wxInitializeResourceSystem();
613#endif
614
0d2a2b60
RR
615 wxModule::RegisterModules();
616 if (!wxModule::InitializeModules()) return FALSE;
60acb947 617
0d2a2b60 618 return TRUE;
ff7b1510 619}
c801d85f 620
60acb947 621void wxApp::CleanUp()
c801d85f 622{
0d2a2b60 623 wxModule::CleanUpModules();
0cf2cb36 624
4a0c68a7
RR
625#if wxUSE_WX_RESOURCES
626 wxCleanUpResourceSystem();
627#endif
628
60acb947
VZ
629 if (wxTheColourDatabase)
630 delete wxTheColourDatabase;
2286341c 631
0d2a2b60 632 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 633
0d2a2b60
RR
634 wxDeleteStockObjects();
635
ec758a20 636 wxDeleteStockLists();
a3622daa 637
0d2a2b60
RR
638 delete wxTheApp;
639 wxTheApp = (wxApp*) NULL;
640
4d3a259a
GL
641 // GL: I'm annoyed ... I don't know where to put this and I don't want to
642 // create a module for that as it's part of the core.
643#if wxUSE_THREADS
644 delete wxPendingEvents;
645 delete wxPendingEventsLocker;
646#endif
647
3e61c765
RR
648 delete[] wxBuffer;
649
650 wxClassInfo::CleanUpClasses();
60acb947
VZ
651
652 // check for memory leaks
0d2a2b60 653#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
6981d3ec 654 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
0d2a2b60 655 {
223d09f6 656 wxLogDebug(wxT("There were memory leaks.\n"));
0d2a2b60
RR
657 wxDebugContext::Dump();
658 wxDebugContext::PrintStatistics();
659 }
8801832d 660#endif // Debug
0d2a2b60 661
88ac883a 662#if wxUSE_LOG
60acb947 663 // do this as the very last thing because everything else can log messages
0d2a2b60 664 wxLog::DontCreateOnDemand();
60acb947 665
0d2a2b60 666 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
667 if (oldLog)
668 delete oldLog;
88ac883a 669#endif // wxUSE_LOG
c19c1ca9 670}
c801d85f 671
c2fa61e8
RD
672//-----------------------------------------------------------------------------
673// Access to the root window global
674//-----------------------------------------------------------------------------
675
676GtkWidget* wxGetRootWindow()
677{
678 if (gs_RootWindow == NULL) {
679 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
680 gtk_widget_realize( gs_RootWindow );
681 }
682 return gs_RootWindow;
683}
684
c801d85f
KB
685//-----------------------------------------------------------------------------
686// wxEntry
687//-----------------------------------------------------------------------------
688
17154fc8
VZ
689// NB: argc and argv may be changed here, pass by reference!
690int wxEntryStart( int& argc, char *argv[] )
c801d85f 691{
924ef850 692#if wxUSE_THREADS
8f75cb6c 693 /* GTK 1.2 up to version 1.2.3 has broken threads */
27df579a 694 if ((gtk_major_version == 1) &&
8f75cb6c 695 (gtk_minor_version == 2) &&
2286341c 696 (gtk_micro_version < 4))
96997d65 697 {
fb65642c 698 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
8f75cb6c
RR
699 }
700 else
701 {
702 g_thread_init(NULL);
703 }
924ef850 704#endif
2286341c 705
0d2a2b60 706 gtk_set_locale();
c801d85f 707
f9862abd
JS
708 // We should have the wxUSE_WCHAR_T test on the _outside_
709#if wxUSE_WCHAR_T
2d4dc3a4
OK
710#if defined(__WXGTK20__)
711 // gtk+ 2.0 supports Unicode through UTF-8 strings
712 wxConvCurrent = &wxConvUTF8;
f9862abd 713#else
dcf924a3 714 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
f9862abd 715#endif
fd9811b1
RR
716#else
717 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
718#endif
002f4218 719
924ef850
RR
720 gdk_threads_enter();
721
0d2a2b60 722 gtk_init( &argc, &argv );
0cf2cb36 723
f0492f7d 724 wxSetDetectableAutoRepeat( TRUE );
094637f6 725
60acb947 726 if (!wxApp::Initialize())
924ef850
RR
727 {
728 gdk_threads_leave();
60acb947 729 return -1;
924ef850 730 }
0cf2cb36 731
954de0f1
RD
732 return 0;
733}
734
c2fa61e8 735
954de0f1
RD
736int wxEntryInitGui()
737{
738 int retValue = 0;
739
740 if ( !wxTheApp->OnInitGui() )
741 retValue = -1;
742
c2fa61e8 743 wxGetRootWindow();
954de0f1
RD
744
745 return retValue;
746}
747
748
749void wxEntryCleanup()
750{
751#if wxUSE_LOG
752 // flush the logged messages if any
753 wxLog *log = wxLog::GetActiveTarget();
754 if (log != NULL && log->HasPendingMessages())
755 log->Flush();
756
757 // continuing to use user defined log target is unsafe from now on because
758 // some resources may be already unavailable, so replace it by something
759 // more safe
760 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
761 if ( oldlog )
762 delete oldlog;
763#endif // wxUSE_LOG
764
765 wxApp::CleanUp();
766
767 gdk_threads_leave();
768}
769
770
771
772int wxEntry( int argc, char *argv[] )
773{
2db0bbde
JS
774#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
775 // This seems to be necessary since there are 'rogue'
776 // objects present at this point (perhaps global objects?)
777 // Setting a checkpoint will ignore them as far as the
778 // memory checking facility is concerned.
779 // Of course you may argue that memory allocated in globals should be
780 // checked, but this is a reasonable compromise.
781 wxDebugContext::SetCheckpoint();
782#endif
a37a5a73 783 int err = wxEntryStart(argc, argv);
954de0f1
RD
784 if (err)
785 return err;
786
ec758a20 787 if (!wxTheApp)
c801d85f 788 {
60acb947 789 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
223d09f6 790 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
0cf2cb36 791
ec758a20 792 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 793
ec758a20 794 wxObject *test_app = app_ini();
0cf2cb36 795
ec758a20
RR
796 wxTheApp = (wxApp*) test_app;
797 }
0cf2cb36 798
223d09f6 799 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
c801d85f 800
ec758a20 801 wxTheApp->argc = argc;
6de92826
OK
802#if wxUSE_UNICODE
803 wxTheApp->argv = new wxChar*[argc+1];
804 int mb_argc = 0;
2286341c 805 while (mb_argc < argc)
924ef850
RR
806 {
807 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
808 mb_argc++;
6de92826
OK
809 }
810 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
811#else
ec758a20 812 wxTheApp->argv = argv;
6de92826 813#endif
0cf2cb36 814
8801832d 815 wxString name(wxFileNameFromPath(argv[0]));
ec758a20
RR
816 wxStripExtension( name );
817 wxTheApp->SetAppName( name );
e0253070 818
954de0f1
RD
819 int retValue;
820 retValue = wxEntryInitGui();
68df5777 821
8801832d
VZ
822 // Here frames insert themselves automatically into wxTopLevelWindows by
823 // getting created in OnInit().
0151c3eb
VZ
824 if ( retValue == 0 )
825 {
826 if ( !wxTheApp->OnInit() )
827 retValue = -1;
828 }
0cf2cb36 829
0151c3eb
VZ
830 if ( retValue == 0 )
831 {
cfb50f14 832 /* delete pending toplevel windows (typically a single
094637f6
VZ
833 dialog) so that, if there isn't any left, we don't
834 call OnRun() */
cfb50f14 835 wxTheApp->DeletePendingObjects();
094637f6 836
0151c3eb 837 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 838
0151c3eb 839 if (wxTheApp->Initialized())
094637f6 840 {
2286341c 841 wxTheApp->OnRun();
0cf2cb36 842
cfb50f14
RR
843 wxWindow *topWindow = wxTheApp->GetTopWindow();
844 if (topWindow)
0151c3eb 845 {
cfb50f14
RR
846 /* Forcibly delete the window. */
847 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
848 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
849 {
850 topWindow->Close( TRUE );
851 wxTheApp->DeletePendingObjects();
852 }
853 else
854 {
855 delete topWindow;
856 wxTheApp->SetTopWindow( (wxWindow*) NULL );
857 }
094637f6 858 }
2286341c
VZ
859
860 retValue = wxTheApp->OnExit();
0d2a2b60 861 }
0151c3eb 862 }
0cf2cb36 863
954de0f1 864 wxEntryCleanup();
924ef850 865
ec758a20 866 return retValue;
ff7b1510 867}
1a56f55c 868
df028524
VS
869#ifndef __WXUNIVERSAL__
870
094637f6
VZ
871#include "wx/gtk/info.xpm"
872#include "wx/gtk/error.xpm"
873#include "wx/gtk/question.xpm"
874#include "wx/gtk/warning.xpm"
875
df028524 876wxIcon wxApp::GetStdIcon(int which) const
ebea0891 877{
094637f6
VZ
878 switch(which)
879 {
880 case wxICON_INFORMATION:
881 return wxIcon(info_xpm);
882
883 case wxICON_QUESTION:
884 return wxIcon(question_xpm);
885
886 case wxICON_EXCLAMATION:
887 return wxIcon(warning_xpm);
888
889 default:
223d09f6 890 wxFAIL_MSG(wxT("requested non existent standard icon"));
094637f6
VZ
891 // still fall through
892
893 case wxICON_HAND:
894 return wxIcon(error_xpm);
895 }
ebea0891 896}
df028524
VS
897#else
898wxIcon wxApp::GetStdIcon(int which) const
899{
900 return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
901}
902#endif // !__WXUNIVERSAL__
903
a5f1fd3e
VZ
904
905#ifdef __WXDEBUG__
906
907void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
908{
909 m_isInAssert = TRUE;
910
911 wxAppBase::OnAssert(file, line, msg);
912
913 m_isInAssert = FALSE;
914}
915
916#endif // __WXDEBUG__
917