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