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