chain to the polling function GLib was using before we replaced it, eliminating all...
[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 "wx/gtk/win_gtk.h"
43 #include "wx/gtk/private.h"
44
45 #include <gdk/gdkx.h>
46
47 //-----------------------------------------------------------------------------
48 // link GnomeVFS
49 //-----------------------------------------------------------------------------
50
51 #if wxUSE_LIBGNOMEVFS
52 #include "wx/html/forcelnk.h"
53 FORCE_LINK(gnome_vfs)
54 #endif
55
56 //-----------------------------------------------------------------------------
57 // global data
58 //-----------------------------------------------------------------------------
59
60 bool g_mainThreadLocked = false;
61
62 static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
63
64 //-----------------------------------------------------------------------------
65 // idle system
66 //-----------------------------------------------------------------------------
67
68 void wxapp_install_idle_handler();
69
70 #if wxUSE_THREADS
71 static wxMutex gs_idleTagsMutex;
72 #endif
73
74 //-----------------------------------------------------------------------------
75 // wxYield
76 //-----------------------------------------------------------------------------
77
78 // not static because used by textctrl.cpp
79 //
80 // MT-FIXME
81 bool wxIsInsideYield = false;
82
83 bool wxApp::Yield(bool onlyIfNeeded)
84 {
85 if ( wxIsInsideYield )
86 {
87 if ( !onlyIfNeeded )
88 {
89 wxFAIL_MSG( wxT("wxYield called recursively" ) );
90 }
91
92 return false;
93 }
94
95 #if wxUSE_THREADS
96 if ( !wxThread::IsMain() )
97 {
98 // can't call gtk_main_iteration() from other threads like this
99 return true;
100 }
101 #endif // wxUSE_THREADS
102
103 wxIsInsideYield = true;
104
105 // We need to remove idle callbacks or the loop will
106 // never finish.
107 SuspendIdleCallback();
108
109 #if wxUSE_LOG
110 // disable log flushing from here because a call to wxYield() shouldn't
111 // normally result in message boxes popping up &c
112 wxLog::Suspend();
113 #endif
114
115 while (gtk_events_pending())
116 gtk_main_iteration();
117
118 // It's necessary to call ProcessIdle() to update the frames sizes which
119 // might have been changed (it also will update other things set from
120 // OnUpdateUI() which is a nice (and desired) side effect). But we
121 // call ProcessIdle() only once since this is not meant for longish
122 // background jobs (controlled by wxIdleEvent::RequestMore() and the
123 // return value of Processidle().
124 ProcessIdle();
125
126 #if wxUSE_LOG
127 // let the logs be flashed again
128 wxLog::Resume();
129 #endif
130
131 wxIsInsideYield = false;
132
133 return true;
134 }
135
136 //-----------------------------------------------------------------------------
137 // wxWakeUpIdle
138 //-----------------------------------------------------------------------------
139
140 // RR/KH: No wxMutexGui calls are needed here according to the GTK faq,
141 // http://www.gtk.org/faq/#AEN500 - this caused problems for wxPostEvent.
142
143 void wxApp::WakeUpIdle()
144 {
145 wxapp_install_idle_handler();
146 }
147
148 //-----------------------------------------------------------------------------
149 // local functions
150 //-----------------------------------------------------------------------------
151
152 // the callback functions must be extern "C" to comply with GTK+ declarations
153 extern "C"
154 {
155
156 // One-shot emission hook for "event" signal, to install idle handler.
157 // This will be called when the "event" signal is issued on any GtkWidget object.
158 static gboolean
159 event_emission_hook(GSignalInvocationHint*, guint, const GValue*, gpointer)
160 {
161 wxapp_install_idle_handler();
162 // remove hook
163 return false;
164 }
165
166 // add emission hook for "event" signal, to re-install idle handler when needed
167 static inline void wxAddEmissionHook()
168 {
169 GType widgetType = GTK_TYPE_WIDGET;
170 // if GtkWidget type is loaded
171 if (g_type_class_peek(widgetType) != NULL)
172 {
173 guint sig_id = g_signal_lookup("event", widgetType);
174 g_signal_add_emission_hook(sig_id, 0, event_emission_hook, NULL, NULL);
175 }
176 }
177
178 static gint wxapp_idle_callback( gpointer WXUNUSED(data) )
179 {
180 // this does not look possible, but just in case...
181 if (!wxTheApp)
182 return false;
183
184 bool moreIdles = false;
185
186 #ifdef __WXDEBUG__
187 // don't generate the idle events while the assert modal dialog is shown,
188 // this matches the behavior of wxMSW
189 if (!wxTheApp->IsInAssert())
190 #endif // __WXDEBUG__
191 {
192 guint idleID_save;
193 {
194 // Allow another idle source to be added while this one is busy.
195 // Needed if an idle event handler runs a new event loop,
196 // for example by showing a dialog.
197 #if wxUSE_THREADS
198 wxMutexLocker lock(gs_idleTagsMutex);
199 #endif
200 idleID_save = wxTheApp->m_idleTag;
201 wxTheApp->m_idleTag = 0;
202 g_isIdle = true;
203 wxAddEmissionHook();
204 }
205
206 // When getting called from GDK's time-out handler
207 // we are no longer within GDK's grab on the GUI
208 // thread so we must lock it here ourselves.
209 gdk_threads_enter();
210
211 // Send idle event to all who request them as long as
212 // no events have popped up in the event queue.
213 do {
214 moreIdles = wxTheApp->ProcessIdle();
215 } while (moreIdles && gtk_events_pending() == 0);
216
217 // Release lock again
218 gdk_threads_leave();
219
220 {
221 // If another idle source was added, remove it
222 #if wxUSE_THREADS
223 wxMutexLocker lock(gs_idleTagsMutex);
224 #endif
225 if (wxTheApp->m_idleTag != 0)
226 g_source_remove(wxTheApp->m_idleTag);
227 wxTheApp->m_idleTag = idleID_save;
228 g_isIdle = false;
229 }
230 }
231
232 if (!moreIdles)
233 {
234 #if wxUSE_THREADS
235 wxMutexLocker lock(gs_idleTagsMutex);
236 #endif
237 // Indicate that we are now in idle mode and event handlers
238 // will have to reinstall the idle handler again.
239 g_isIdle = true;
240 wxTheApp->m_idleTag = 0;
241
242 wxAddEmissionHook();
243 }
244
245 // Return FALSE if no more idle events are to be sent
246 return moreIdles;
247 }
248 } // extern "C"
249
250 #if wxUSE_THREADS
251
252 static GPollFunc wxgs_poll_func;
253
254 extern "C" {
255 static gint wxapp_poll_func( GPollFD *ufds, guint nfds, gint timeout )
256 {
257 gdk_threads_enter();
258
259 wxMutexGuiLeave();
260 g_mainThreadLocked = true;
261
262 gint res = (*wxgs_poll_func)(ufds, nfds, timeout);
263
264 wxMutexGuiEnter();
265 g_mainThreadLocked = false;
266
267 gdk_threads_leave();
268
269 return res;
270 }
271 }
272
273 #endif // wxUSE_THREADS
274
275 void wxapp_install_idle_handler()
276 {
277 if (wxTheApp == NULL)
278 return;
279
280 #if wxUSE_THREADS
281 wxMutexLocker lock(gs_idleTagsMutex);
282 #endif
283
284 // Don't install the handler if it's already installed. This test *MUST*
285 // be done when gs_idleTagsMutex is locked!
286 if (!g_isIdle)
287 return;
288
289 // GD: this assert is raised when using the thread sample (which works)
290 // so the test is probably not so easy. Can widget callbacks be
291 // triggered from child threads and, if so, for which widgets?
292 // wxASSERT_MSG( wxThread::IsMain() || gs_WakeUpIdle, wxT("attempt to install idle handler from widget callback in child thread (should be exclusively from wxWakeUpIdle)") );
293
294 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
295
296 g_isIdle = false;
297
298 // This routine gets called by all event handlers
299 // indicating that the idle is over. It may also
300 // get called from other thread for sending events
301 // to the main thread (and processing these in
302 // idle time). Very low priority.
303 wxTheApp->m_idleTag = g_idle_add_full(G_PRIORITY_LOW, wxapp_idle_callback, NULL, NULL);
304 }
305
306 //-----------------------------------------------------------------------------
307 // Access to the root window global
308 //-----------------------------------------------------------------------------
309
310 GtkWidget* wxGetRootWindow()
311 {
312 if (gs_RootWindow == NULL)
313 {
314 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
315 gtk_widget_realize( gs_RootWindow );
316 }
317 return gs_RootWindow;
318 }
319
320 //-----------------------------------------------------------------------------
321 // wxApp
322 //-----------------------------------------------------------------------------
323
324 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
325
326 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
327 EVT_IDLE(wxAppBase::OnIdle)
328 END_EVENT_TABLE()
329
330 wxApp::wxApp()
331 {
332 #ifdef __WXDEBUG__
333 m_isInAssert = false;
334 #endif // __WXDEBUG__
335
336 m_idleTag = 0;
337 g_isIdle = true;
338 wxapp_install_idle_handler();
339
340 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
341 m_glVisualInfo = (void *) NULL;
342 m_glFBCInfo = (void *) NULL;
343 }
344
345 wxApp::~wxApp()
346 {
347 if (m_idleTag)
348 g_source_remove( m_idleTag );
349 }
350
351 bool wxApp::OnInitGui()
352 {
353 if ( !wxAppBase::OnInitGui() )
354 return false;
355
356 // if this is a wxGLApp (derived from wxApp), and we've already
357 // chosen a specific visual, then derive the GdkVisual from that
358 if (m_glVisualInfo != NULL)
359 {
360 GdkVisual* vis = gtk_widget_get_default_visual();
361
362 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
363 gtk_widget_set_default_colormap( colormap );
364 }
365 else
366 {
367 // On some machines, the default visual is just 256 colours, so
368 // we make sure we get the best. This can sometimes be wasteful.
369 if (m_useBestVisual)
370 {
371 if (m_forceTrueColour)
372 {
373 GdkVisual* visual = gdk_visual_get_best_with_both( 24, GDK_VISUAL_TRUE_COLOR );
374 if (!visual)
375 {
376 wxLogError(wxT("Unable to initialize TrueColor visual."));
377 return false;
378 }
379 GdkColormap *colormap = gdk_colormap_new( visual, FALSE );
380 gtk_widget_set_default_colormap( colormap );
381 }
382 else
383 {
384 if (gdk_visual_get_best() != gdk_visual_get_system())
385 {
386 GdkVisual* visual = gdk_visual_get_best();
387 GdkColormap *colormap = gdk_colormap_new( visual, FALSE );
388 gtk_widget_set_default_colormap( colormap );
389 }
390 }
391 }
392 }
393
394 return true;
395 }
396
397 GdkVisual *wxApp::GetGdkVisual()
398 {
399 GdkVisual *visual = NULL;
400
401 if (m_glVisualInfo)
402 visual = gdkx_visual_get( ((XVisualInfo *) m_glVisualInfo)->visualid );
403 else
404 visual = gdk_drawable_get_visual( wxGetRootWindow()->window );
405
406 wxASSERT( visual );
407
408 return visual;
409 }
410
411 bool wxApp::Initialize(int& argc, wxChar **argv)
412 {
413 bool init_result;
414
415 #if wxUSE_THREADS
416 if (!g_thread_supported())
417 g_thread_init(NULL);
418
419 wxgs_poll_func = g_main_context_get_poll_func(NULL);
420 g_main_context_set_poll_func(NULL, wxapp_poll_func);
421 #endif // wxUSE_THREADS
422
423 gtk_set_locale();
424
425 // We should have the wxUSE_WCHAR_T test on the _outside_
426 #if wxUSE_WCHAR_T
427 // gtk+ 2.0 supports Unicode through UTF-8 strings
428 wxConvCurrent = &wxConvUTF8;
429 #else // !wxUSE_WCHAR_T
430 if (!wxOKlibc())
431 wxConvCurrent = (wxMBConv*) NULL;
432 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
433
434 // decide which conversion to use for the file names
435
436 // (1) this variable exists for the sole purpose of specifying the encoding
437 // of the filenames for GTK+ programs, so use it if it is set
438 wxString encName(wxGetenv(_T("G_FILENAME_ENCODING")));
439 encName = encName.BeforeFirst(_T(','));
440 if (encName.CmpNoCase(_T("@locale")) == 0)
441 encName.clear();
442 encName.MakeUpper();
443 #if wxUSE_INTL
444 if (encName.empty())
445 {
446 // (2) if a non default locale is set, assume that the user wants his
447 // filenames in this locale too
448 encName = wxLocale::GetSystemEncodingName().Upper();
449 // (3) finally use UTF-8 by default
450 if (encName.empty() || encName == _T("US-ASCII"))
451 encName = _T("UTF-8");
452 wxSetEnv(_T("G_FILENAME_ENCODING"), encName);
453 }
454 #else
455 if (encName.empty())
456 encName = _T("UTF-8");
457 #endif // wxUSE_INTL
458 static wxConvBrokenFileNames fileconv(encName);
459 wxConvFileName = &fileconv;
460
461 #if wxUSE_UNICODE
462 // gtk_init() wants UTF-8, not wchar_t, so convert
463 int i;
464 char **argvGTK = new char *[argc + 1];
465 for ( i = 0; i < argc; i++ )
466 {
467 argvGTK[i] = wxStrdupA(wxConvUTF8.cWX2MB(argv[i]));
468 }
469
470 argvGTK[argc] = NULL;
471
472 int argcGTK = argc;
473
474 #ifdef __WXGPE__
475 init_result = true; // is there a _check() version of this?
476 gpe_application_init( &argcGTK, &argvGTK );
477 #else
478 init_result = gtk_init_check( &argcGTK, &argvGTK );
479 #endif
480
481 if ( argcGTK != argc )
482 {
483 // we have to drop the parameters which were consumed by GTK+
484 for ( i = 0; i < argcGTK; i++ )
485 {
486 while ( strcmp(wxConvUTF8.cWX2MB(argv[i]), argvGTK[i]) != 0 )
487 {
488 memmove(argv + i, argv + i + 1, argc - i);
489 }
490 }
491
492 argc = argcGTK;
493 }
494 //else: gtk_init() didn't modify our parameters
495
496 // free our copy
497 for ( i = 0; i < argcGTK; i++ )
498 {
499 free(argvGTK[i]);
500 }
501
502 delete [] argvGTK;
503 #else // !wxUSE_UNICODE
504 // gtk_init() shouldn't actually change argv itself (just its contents) so
505 // it's ok to pass pointer to it
506 init_result = gtk_init_check( &argc, &argv );
507 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
508
509 if (!init_result) {
510 wxLogError(wxT("Unable to initialize gtk, is DISPLAY set properly?"));
511 return false;
512 }
513
514 // we can not enter threads before gtk_init is done
515 gdk_threads_enter();
516
517 if ( !wxAppBase::Initialize(argc, argv) )
518 {
519 gdk_threads_leave();
520
521 return false;
522 }
523
524 wxSetDetectableAutoRepeat( true );
525
526 #if wxUSE_INTL
527 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
528 #endif
529
530 return true;
531 }
532
533 void wxApp::CleanUp()
534 {
535 gdk_threads_leave();
536
537 wxAppBase::CleanUp();
538 }
539
540 #ifdef __WXDEBUG__
541
542 void wxApp::OnAssertFailure(const wxChar *file,
543 int line,
544 const wxChar* func,
545 const wxChar* cond,
546 const wxChar *msg)
547 {
548
549 // block wx idle events while assert dialog is showing
550 m_isInAssert = true;
551
552 wxAppBase::OnAssertFailure(file, line, func, cond, msg);
553
554 m_isInAssert = false;
555 }
556
557 #endif // __WXDEBUG__
558
559 void wxApp::SuspendIdleCallback()
560 {
561 #if wxUSE_THREADS
562 wxMutexLocker lock(gs_idleTagsMutex);
563 #endif
564 if (m_idleTag != 0)
565 {
566 g_source_remove(m_idleTag);
567 m_idleTag = 0;
568 g_isIdle = true;
569 wxAddEmissionHook();
570 }
571 }