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