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