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