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