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