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