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