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