don't tie up cpu in idle loop when showing assert dialog
[wxWidgets.git] / src / gtk / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/app.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __VMS
11 // vms_jackets.h should for proper working be included before anything else
12 # include <vms_jackets.h>
13 #undef ConnectionNumber
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #include "wx/app.h"
20
21 #ifndef WX_PRECOMP
22 #include "wx/intl.h"
23 #include "wx/log.h"
24 #include "wx/utils.h"
25 #include "wx/memory.h"
26 #include "wx/font.h"
27 #endif
28
29 #include "wx/file.h"
30 #include "wx/filename.h"
31 #include "wx/thread.h"
32
33 #ifdef __WXGPE__
34 #include <gpe/init.h>
35 #endif
36
37 #ifdef __WXUNIVERSAL__
38 #include "wx/univ/theme.h"
39 #include "wx/univ/renderer.h"
40 #endif
41
42 #include <unistd.h>
43
44 #ifdef HAVE_POLL
45 #if defined(__VMS)
46 #include <poll.h>
47 #else
48 // bug in the OpenBSD headers: at least in 3.1 there is no extern "C"
49 // in neither poll.h nor sys/poll.h which results in link errors later
50 #ifdef __OPENBSD__
51 extern "C"
52 {
53 #endif
54
55 #include <sys/poll.h>
56
57 #ifdef __OPENBSD__
58 };
59 #endif
60 #endif // platform
61 #else // !HAVE_POLL
62 // we implement poll() ourselves using select() which is supposed exist in
63 // all modern Unices
64 #include <sys/types.h>
65 #include <sys/time.h>
66 #include <unistd.h>
67 #ifdef HAVE_SYS_SELECT_H
68 #include <sys/select.h>
69 #endif
70 #endif // HAVE_POLL/!HAVE_POLL
71
72 #include "wx/unix/private.h"
73 #include "wx/gtk/win_gtk.h"
74 #include "wx/gtk/private.h"
75
76 #include <gdk/gdkx.h>
77
78 //-----------------------------------------------------------------------------
79 // link GnomeVFS
80 //-----------------------------------------------------------------------------
81
82 #if wxUSE_LIBGNOMEVFS
83 #include "wx/html/forcelnk.h"
84 FORCE_LINK(gnome_vfs)
85 #endif
86
87 //-----------------------------------------------------------------------------
88 // global data
89 //-----------------------------------------------------------------------------
90
91 bool g_mainThreadLocked = false;
92
93 static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
94
95 //-----------------------------------------------------------------------------
96 // idle system
97 //-----------------------------------------------------------------------------
98
99 void wxapp_install_idle_handler();
100
101 #if wxUSE_THREADS
102 static wxMutex gs_idleTagsMutex;
103 #endif
104
105 //-----------------------------------------------------------------------------
106 // wxYield
107 //-----------------------------------------------------------------------------
108
109 // not static because used by textctrl.cpp
110 //
111 // MT-FIXME
112 bool wxIsInsideYield = false;
113
114 bool wxApp::Yield(bool onlyIfNeeded)
115 {
116 if ( wxIsInsideYield )
117 {
118 if ( !onlyIfNeeded )
119 {
120 wxFAIL_MSG( wxT("wxYield called recursively" ) );
121 }
122
123 return false;
124 }
125
126 #if wxUSE_THREADS
127 if ( !wxThread::IsMain() )
128 {
129 // can't call gtk_main_iteration() from other threads like this
130 return true;
131 }
132 #endif // wxUSE_THREADS
133
134 wxIsInsideYield = true;
135
136 // We need to remove idle callbacks or the loop will
137 // never finish.
138 wxTheApp->RemoveIdleTag();
139
140 #if wxUSE_LOG
141 // disable log flushing from here because a call to wxYield() shouldn't
142 // normally result in message boxes popping up &c
143 wxLog::Suspend();
144 #endif
145
146 while (gtk_events_pending())
147 gtk_main_iteration();
148
149 // It's necessary to call ProcessIdle() to update the frames sizes which
150 // might have been changed (it also will update other things set from
151 // OnUpdateUI() which is a nice (and desired) side effect). But we
152 // call ProcessIdle() only once since this is not meant for longish
153 // background jobs (controlled by wxIdleEvent::RequestMore() and the
154 // return value of Processidle().
155 ProcessIdle();
156
157 #if wxUSE_LOG
158 // let the logs be flashed again
159 wxLog::Resume();
160 #endif
161
162 wxIsInsideYield = false;
163
164 return true;
165 }
166
167 //-----------------------------------------------------------------------------
168 // wxWakeUpIdle
169 //-----------------------------------------------------------------------------
170
171 // RR/KH: No wxMutexGui calls are needed here according to the GTK faq,
172 // http://www.gtk.org/faq/#AEN500 - this caused problems for wxPostEvent.
173
174 void wxApp::WakeUpIdle()
175 {
176 wxapp_install_idle_handler();
177 }
178
179 //-----------------------------------------------------------------------------
180 // local functions
181 //-----------------------------------------------------------------------------
182
183 // the callback functions must be extern "C" to comply with GTK+ declarations
184 extern "C"
185 {
186
187 static gint wxapp_idle_callback( gpointer WXUNUSED(data) )
188 {
189 if (!wxTheApp)
190 return false;
191
192 #ifdef __WXDEBUG__
193 // don't generate the idle events while the assert modal dialog is shown,
194 // this completely confuses the apps which don't expect to be reentered
195 // from some safely-looking functions
196 if ( wxTheApp->IsInAssert() )
197 return false;
198 #endif // __WXDEBUG__
199
200 // When getting called from GDK's time-out handler
201 // we are no longer within GDK's grab on the GUI
202 // thread so we must lock it here ourselves.
203 gdk_threads_enter();
204
205 // Indicate that we are now in idle mode and event handlers
206 // will have to reinstall the idle handler again.
207 {
208 #if wxUSE_THREADS
209 wxMutexLocker lock(gs_idleTagsMutex);
210 #endif
211 g_isIdle = true;
212 wxTheApp->m_idleTag = 0;
213 }
214
215 bool moreIdles;
216
217 // Send idle event to all who request them as long as
218 // no events have popped up in the event queue.
219 while ( (moreIdles = wxTheApp->ProcessIdle()) && gtk_events_pending() == 0)
220 ;
221
222 // Release lock again
223 gdk_threads_leave();
224
225 // Return FALSE if no more idle events are to be sent
226 return moreIdles;
227 }
228
229 #if wxUSE_THREADS
230
231 #ifdef HAVE_POLL
232 #define wxPoll poll
233 #define wxPollFd pollfd
234 #else // !HAVE_POLL
235
236 typedef GPollFD wxPollFd;
237
238 int wxPoll(wxPollFd *ufds, unsigned int nfds, int timeout)
239 {
240 // convert timeout from ms to struct timeval (s/us)
241 timeval tv_timeout;
242 tv_timeout.tv_sec = timeout/1000;
243 tv_timeout.tv_usec = (timeout%1000)*1000;
244
245 // remember the highest fd used here
246 int fdMax = -1;
247
248 // and fill the sets for select()
249 fd_set readfds;
250 fd_set writefds;
251 fd_set exceptfds;
252 wxFD_ZERO(&readfds);
253 wxFD_ZERO(&writefds);
254 wxFD_ZERO(&exceptfds);
255
256 unsigned int i;
257 for ( i = 0; i < nfds; i++ )
258 {
259 wxASSERT_MSG( ufds[i].fd < wxFD_SETSIZE, _T("fd out of range") );
260
261 if ( ufds[i].events & G_IO_IN )
262 wxFD_SET(ufds[i].fd, &readfds);
263
264 if ( ufds[i].events & G_IO_PRI )
265 wxFD_SET(ufds[i].fd, &exceptfds);
266
267 if ( ufds[i].events & G_IO_OUT )
268 wxFD_SET(ufds[i].fd, &writefds);
269
270 if ( ufds[i].fd > fdMax )
271 fdMax = ufds[i].fd;
272 }
273
274 fdMax++;
275 int res = select(fdMax, &readfds, &writefds, &exceptfds, &tv_timeout);
276
277 // translate the results back
278 for ( i = 0; i < nfds; i++ )
279 {
280 ufds[i].revents = 0;
281
282 if ( wxFD_ISSET(ufds[i].fd, &readfds ) )
283 ufds[i].revents |= G_IO_IN;
284
285 if ( wxFD_ISSET(ufds[i].fd, &exceptfds ) )
286 ufds[i].revents |= G_IO_PRI;
287
288 if ( wxFD_ISSET(ufds[i].fd, &writefds ) )
289 ufds[i].revents |= G_IO_OUT;
290 }
291
292 return res;
293 }
294
295 #endif // HAVE_POLL/!HAVE_POLL
296
297 static gint wxapp_poll_func( GPollFD *ufds, guint nfds, gint timeout )
298 {
299 gdk_threads_enter();
300
301 wxMutexGuiLeave();
302 g_mainThreadLocked = true;
303
304 // we rely on the fact that glib GPollFD struct is really just pollfd but
305 // I wonder how wise is this in the long term (VZ)
306 gint res = wxPoll( (wxPollFd *) ufds, nfds, timeout );
307
308 wxMutexGuiEnter();
309 g_mainThreadLocked = false;
310
311 gdk_threads_leave();
312
313 return res;
314 }
315
316 #endif // wxUSE_THREADS
317
318 } // extern "C"
319
320 void wxapp_install_idle_handler()
321 {
322 #if wxUSE_THREADS
323 wxMutexLocker lock(gs_idleTagsMutex);
324 #endif
325
326 // Don't install the handler if it's already installed. This test *MUST*
327 // be done when gs_idleTagsMutex is locked!
328 if (!g_isIdle)
329 return;
330
331 // GD: this assert is raised when using the thread sample (which works)
332 // so the test is probably not so easy. Can widget callbacks be
333 // triggered from child threads and, if so, for which widgets?
334 // wxASSERT_MSG( wxThread::IsMain() || gs_WakeUpIdle, wxT("attempt to install idle handler from widget callback in child thread (should be exclusively from wxWakeUpIdle)") );
335
336 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
337
338 g_isIdle = false;
339
340 // This routine gets called by all event handlers
341 // indicating that the idle is over. It may also
342 // get called from other thread for sending events
343 // to the main thread (and processing these in
344 // idle time). Very low priority.
345 wxTheApp->m_idleTag = g_idle_add_full(G_PRIORITY_LOW, wxapp_idle_callback, NULL, NULL);
346 }
347
348 //-----------------------------------------------------------------------------
349 // Access to the root window global
350 //-----------------------------------------------------------------------------
351
352 GtkWidget* wxGetRootWindow()
353 {
354 if (gs_RootWindow == NULL)
355 {
356 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
357 gtk_widget_realize( gs_RootWindow );
358 }
359 return gs_RootWindow;
360 }
361
362 //-----------------------------------------------------------------------------
363 // wxApp
364 //-----------------------------------------------------------------------------
365
366 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
367
368 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
369 EVT_IDLE(wxAppBase::OnIdle)
370 END_EVENT_TABLE()
371
372 wxApp::wxApp()
373 {
374 #ifdef __WXDEBUG__
375 m_isInAssert = false;
376 #endif // __WXDEBUG__
377
378 m_idleTag = 0;
379 g_isIdle = true;
380 wxapp_install_idle_handler();
381
382 #if wxUSE_THREADS
383 g_main_context_set_poll_func( NULL, wxapp_poll_func );
384 #endif
385
386 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
387 m_glVisualInfo = (void *) NULL;
388 m_glFBCInfo = (void *) NULL;
389 }
390
391 wxApp::~wxApp()
392 {
393 if (m_idleTag)
394 g_source_remove( m_idleTag );
395 }
396
397 bool wxApp::OnInitGui()
398 {
399 if ( !wxAppBase::OnInitGui() )
400 return false;
401
402 // if this is a wxGLApp (derived from wxApp), and we've already
403 // chosen a specific visual, then derive the GdkVisual from that
404 if (m_glVisualInfo != NULL)
405 {
406 // seems gtk_widget_set_default_visual no longer exists?
407 GdkVisual* vis = gtk_widget_get_default_visual();
408
409 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
410 gtk_widget_set_default_colormap( colormap );
411 }
412
413 // On some machines, the default visual is just 256 colours, so
414 // we make sure we get the best. This can sometimes be wasteful.
415
416 else
417 if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual))
418 {
419 /* seems gtk_widget_set_default_visual no longer exists? */
420 GdkVisual* vis = gtk_widget_get_default_visual();
421
422 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
423 gtk_widget_set_default_colormap( colormap );
424 }
425
426 return true;
427 }
428
429 GdkVisual *wxApp::GetGdkVisual()
430 {
431 GdkVisual *visual = NULL;
432
433 if (m_glVisualInfo)
434 visual = gdkx_visual_get( ((XVisualInfo *) m_glVisualInfo)->visualid );
435 else
436 visual = gdk_drawable_get_visual( wxGetRootWindow()->window );
437
438 wxASSERT( visual );
439
440 return visual;
441 }
442
443 bool wxApp::Initialize(int& argc, wxChar **argv)
444 {
445 bool init_result;
446
447 #if wxUSE_THREADS
448 if (!g_thread_supported())
449 g_thread_init(NULL);
450 #endif // wxUSE_THREADS
451
452 gtk_set_locale();
453
454 // We should have the wxUSE_WCHAR_T test on the _outside_
455 #if wxUSE_WCHAR_T
456 // gtk+ 2.0 supports Unicode through UTF-8 strings
457 wxConvCurrent = &wxConvUTF8;
458 #else // !wxUSE_WCHAR_T
459 if (!wxOKlibc())
460 wxConvCurrent = (wxMBConv*) NULL;
461 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
462
463 // decide which conversion to use for the file names
464
465 // (1) this variable exists for the sole purpose of specifying the encoding
466 // of the filenames for GTK+ programs, so use it if it is set
467 wxString encName(wxGetenv(_T("G_FILENAME_ENCODING")));
468 encName = encName.BeforeFirst(_T(','));
469 if (encName == _T("@locale"))
470 encName.clear();
471 encName.MakeUpper();
472 #if wxUSE_INTL
473 if (encName.empty())
474 {
475 // (2) if a non default locale is set, assume that the user wants his
476 // filenames in this locale too
477 encName = wxLocale::GetSystemEncodingName().Upper();
478 // (3) finally use UTF-8 by default
479 if (encName.empty() || encName == _T("US-ASCII"))
480 encName = _T("UTF-8");
481 wxSetEnv(_T("G_FILENAME_ENCODING"), encName);
482 }
483 #else
484 if (encName.empty())
485 encName = _T("UTF-8");
486 #endif // wxUSE_INTL
487 static wxConvBrokenFileNames fileconv(encName);
488 wxConvFileName = &fileconv;
489
490 #if wxUSE_UNICODE
491 // gtk_init() wants UTF-8, not wchar_t, so convert
492 int i;
493 char **argvGTK = new char *[argc + 1];
494 for ( i = 0; i < argc; i++ )
495 {
496 argvGTK[i] = wxStrdupA(wxConvUTF8.cWX2MB(argv[i]));
497 }
498
499 argvGTK[argc] = NULL;
500
501 int argcGTK = argc;
502
503 #ifdef __WXGPE__
504 init_result = true; // is there a _check() version of this?
505 gpe_application_init( &argcGTK, &argvGTK );
506 #else
507 init_result = gtk_init_check( &argcGTK, &argvGTK );
508 #endif
509
510 if ( argcGTK != argc )
511 {
512 // we have to drop the parameters which were consumed by GTK+
513 for ( i = 0; i < argcGTK; i++ )
514 {
515 while ( strcmp(wxConvUTF8.cWX2MB(argv[i]), argvGTK[i]) != 0 )
516 {
517 memmove(argv + i, argv + i + 1, argc - i);
518 }
519 }
520
521 argc = argcGTK;
522 }
523 //else: gtk_init() didn't modify our parameters
524
525 // free our copy
526 for ( i = 0; i < argcGTK; i++ )
527 {
528 free(argvGTK[i]);
529 }
530
531 delete [] argvGTK;
532 #else // !wxUSE_UNICODE
533 // gtk_init() shouldn't actually change argv itself (just its contents) so
534 // it's ok to pass pointer to it
535 init_result = gtk_init_check( &argc, &argv );
536 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
537
538 if (!init_result) {
539 wxLogError(wxT("Unable to initialize gtk, is DISPLAY set properly?"));
540 return false;
541 }
542
543 // we can not enter threads before gtk_init is done
544 gdk_threads_enter();
545
546 if ( !wxAppBase::Initialize(argc, argv) )
547 {
548 gdk_threads_leave();
549
550 return false;
551 }
552
553 wxSetDetectableAutoRepeat( true );
554
555 #if wxUSE_INTL
556 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
557 #endif
558
559 return true;
560 }
561
562 void wxApp::CleanUp()
563 {
564 gdk_threads_leave();
565
566 wxAppBase::CleanUp();
567 }
568
569 #ifdef __WXDEBUG__
570
571 void wxApp::OnAssertFailure(const wxChar *file,
572 int line,
573 const wxChar* func,
574 const wxChar* cond,
575 const wxChar *msg)
576 {
577 m_isInAssert = true;
578
579 wxAppBase::OnAssertFailure(file, line, func, cond, msg);
580
581 m_isInAssert = false;
582 }
583
584 #endif // __WXDEBUG__
585
586 void wxApp::RemoveIdleTag()
587 {
588 #if wxUSE_THREADS
589 wxMutexLocker lock(gs_idleTagsMutex);
590 #endif
591 if (!g_isIdle)
592 {
593 g_source_remove( wxTheApp->m_idleTag );
594 wxTheApp->m_idleTag = 0;
595 g_isIdle = true;
596 }
597 }