]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/app.cpp
removed extra membersections (patch 1702329)
[wxWidgets.git] / src / gtk / app.cpp
... / ...
CommitLineData
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/thread.h"
30
31#ifdef __WXGPE__
32 #include <gpe/init.h>
33#endif
34
35#include "wx/gtk/win_gtk.h"
36#include "wx/gtk/private.h"
37
38#include <gdk/gdkx.h>
39
40//-----------------------------------------------------------------------------
41// link GnomeVFS
42//-----------------------------------------------------------------------------
43
44#if wxUSE_MIMETYPE && wxUSE_LIBGNOMEVFS
45 #include "wx/link.h"
46 wxFORCE_LINK_MODULE(gnome_vfs)
47#endif
48
49//-----------------------------------------------------------------------------
50// global data
51//-----------------------------------------------------------------------------
52
53bool g_mainThreadLocked = false;
54
55static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
56
57//-----------------------------------------------------------------------------
58// wxYield
59//-----------------------------------------------------------------------------
60
61// not static because used by textctrl.cpp
62//
63// MT-FIXME
64bool wxIsInsideYield = false;
65
66bool wxApp::Yield(bool onlyIfNeeded)
67{
68 if ( wxIsInsideYield )
69 {
70 if ( !onlyIfNeeded )
71 {
72 wxFAIL_MSG( wxT("wxYield called recursively" ) );
73 }
74
75 return false;
76 }
77
78#if wxUSE_THREADS
79 if ( !wxThread::IsMain() )
80 {
81 // can't call gtk_main_iteration() from other threads like this
82 return true;
83 }
84#endif // wxUSE_THREADS
85
86 wxIsInsideYield = true;
87
88#if wxUSE_LOG
89 // disable log flushing from here because a call to wxYield() shouldn't
90 // normally result in message boxes popping up &c
91 wxLog::Suspend();
92#endif
93
94 while (EventsPending())
95 gtk_main_iteration();
96
97 // It's necessary to call ProcessIdle() to update the frames sizes which
98 // might have been changed (it also will update other things set from
99 // OnUpdateUI() which is a nice (and desired) side effect). But we
100 // call ProcessIdle() only once since this is not meant for longish
101 // background jobs (controlled by wxIdleEvent::RequestMore() and the
102 // return value of Processidle().
103 ProcessIdle();
104
105#if wxUSE_LOG
106 // let the logs be flashed again
107 wxLog::Resume();
108#endif
109
110 wxIsInsideYield = false;
111
112 return true;
113}
114
115//-----------------------------------------------------------------------------
116// local functions
117//-----------------------------------------------------------------------------
118
119// One-shot signal emission hook, to install idle handler.
120extern "C" {
121static gboolean
122wx_emission_hook(GSignalInvocationHint*, guint, const GValue*, gpointer data)
123{
124 wxApp* app = wxTheApp;
125 if (app != NULL)
126 app->WakeUpIdle();
127 gulong* hook_id = (gulong*)data;
128 // record that hook is not installed
129 *hook_id = 0;
130 // remove hook
131 return false;
132}
133}
134
135// Add signal emission hooks, to re-install idle handler when needed.
136static void wx_add_idle_hooks()
137{
138 // "event" hook
139 {
140 static gulong hook_id = 0;
141 if (hook_id == 0)
142 {
143 static guint sig_id = 0;
144 if (sig_id == 0)
145 sig_id = g_signal_lookup("event", GTK_TYPE_WIDGET);
146 hook_id = g_signal_add_emission_hook(
147 sig_id, 0, wx_emission_hook, &hook_id, NULL);
148 }
149 }
150 // "size_allocate" hook
151 // Needed to match the behavior of the old idle system,
152 // but probably not necessary.
153 {
154 static gulong hook_id = 0;
155 if (hook_id == 0)
156 {
157 static guint sig_id = 0;
158 if (sig_id == 0)
159 sig_id = g_signal_lookup("size_allocate", GTK_TYPE_WIDGET);
160 hook_id = g_signal_add_emission_hook(
161 sig_id, 0, wx_emission_hook, &hook_id, NULL);
162 }
163 }
164}
165
166extern "C" {
167static gboolean wxapp_idle_callback(gpointer)
168{
169 return wxTheApp->DoIdle();
170}
171}
172
173bool wxApp::DoIdle()
174{
175 guint id_save;
176 {
177 // Allow another idle source to be added while this one is busy.
178 // Needed if an idle event handler runs a new event loop,
179 // for example by showing a dialog.
180#if wxUSE_THREADS
181 wxMutexLocker lock(*m_idleMutex);
182#endif
183 id_save = m_idleSourceId;
184 m_idleSourceId = 0;
185 wx_add_idle_hooks();
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 (m_isInAssert)
190 return false;
191#endif
192 }
193
194 gdk_threads_enter();
195 bool needMore;
196 do {
197 needMore = ProcessIdle();
198 } while (needMore && gtk_events_pending() == 0);
199 gdk_threads_leave();
200
201#if wxUSE_THREADS
202 wxMutexLocker lock(*m_idleMutex);
203#endif
204 // if a new idle source was added during ProcessIdle
205 if (m_idleSourceId != 0)
206 {
207 // remove it
208 g_source_remove(m_idleSourceId);
209 m_idleSourceId = 0;
210 }
211 // if more idle processing requested
212 if (needMore)
213 {
214 // keep this source installed
215 m_idleSourceId = id_save;
216 return true;
217 }
218 // add hooks and remove this source
219 wx_add_idle_hooks();
220 return false;
221}
222
223#if wxUSE_THREADS
224
225static GPollFunc wxgs_poll_func;
226
227extern "C" {
228static gint wxapp_poll_func( GPollFD *ufds, guint nfds, gint timeout )
229{
230 gdk_threads_enter();
231
232 wxMutexGuiLeave();
233 g_mainThreadLocked = true;
234
235 gint res = (*wxgs_poll_func)(ufds, nfds, timeout);
236
237 wxMutexGuiEnter();
238 g_mainThreadLocked = false;
239
240 gdk_threads_leave();
241
242 return res;
243}
244}
245
246#endif // wxUSE_THREADS
247
248//-----------------------------------------------------------------------------
249// Access to the root window global
250//-----------------------------------------------------------------------------
251
252GtkWidget* wxGetRootWindow()
253{
254 if (gs_RootWindow == NULL)
255 {
256 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
257 gtk_widget_realize( gs_RootWindow );
258 }
259 return gs_RootWindow;
260}
261
262//-----------------------------------------------------------------------------
263// wxApp
264//-----------------------------------------------------------------------------
265
266IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
267
268BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
269 EVT_IDLE(wxAppBase::OnIdle)
270END_EVENT_TABLE()
271
272wxApp::wxApp()
273{
274#ifdef __WXDEBUG__
275 m_isInAssert = false;
276#endif // __WXDEBUG__
277#if wxUSE_THREADS
278 m_idleMutex = NULL;
279#endif
280 m_idleSourceId = 0;
281}
282
283wxApp::~wxApp()
284{
285}
286
287bool wxApp::OnInitGui()
288{
289 if ( !wxAppBase::OnInitGui() )
290 return false;
291
292 // if this is a wxGLApp (derived from wxApp), and we've already
293 // chosen a specific visual, then derive the GdkVisual from that
294 if ( GetXVisualInfo() )
295 {
296 GdkVisual* vis = gtk_widget_get_default_visual();
297
298 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
299 gtk_widget_set_default_colormap( colormap );
300 }
301 else
302 {
303 // On some machines, the default visual is just 256 colours, so
304 // we make sure we get the best. This can sometimes be wasteful.
305 if (m_useBestVisual)
306 {
307 if (m_forceTrueColour)
308 {
309 GdkVisual* visual = gdk_visual_get_best_with_both( 24, GDK_VISUAL_TRUE_COLOR );
310 if (!visual)
311 {
312 wxLogError(wxT("Unable to initialize TrueColor visual."));
313 return false;
314 }
315 GdkColormap *colormap = gdk_colormap_new( visual, FALSE );
316 gtk_widget_set_default_colormap( colormap );
317 }
318 else
319 {
320 if (gdk_visual_get_best() != gdk_visual_get_system())
321 {
322 GdkVisual* visual = gdk_visual_get_best();
323 GdkColormap *colormap = gdk_colormap_new( visual, FALSE );
324 gtk_widget_set_default_colormap( colormap );
325 }
326 }
327 }
328 }
329
330 return true;
331}
332
333GdkVisual *wxApp::GetGdkVisual()
334{
335 GdkVisual *visual = NULL;
336
337 XVisualInfo *xvi = (XVisualInfo *)GetXVisualInfo();
338 if ( xvi )
339 visual = gdkx_visual_get( xvi->visualid );
340 else
341 visual = gdk_drawable_get_visual( wxGetRootWindow()->window );
342
343 wxASSERT( visual );
344
345 return visual;
346}
347
348bool wxApp::Initialize(int& argc, wxChar **argv)
349{
350 if ( !wxAppBase::Initialize(argc, argv) )
351 return false;
352
353#if wxUSE_THREADS
354 if (!g_thread_supported())
355 g_thread_init(NULL);
356
357 wxgs_poll_func = g_main_context_get_poll_func(NULL);
358 g_main_context_set_poll_func(NULL, wxapp_poll_func);
359#endif // wxUSE_THREADS
360
361 // We should have the wxUSE_WCHAR_T test on the _outside_
362#if wxUSE_WCHAR_T
363 // gtk+ 2.0 supports Unicode through UTF-8 strings
364 wxConvCurrent = &wxConvUTF8;
365#else // !wxUSE_WCHAR_T
366 if (!wxOKlibc())
367 wxConvCurrent = (wxMBConv*) NULL;
368#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
369
370 // decide which conversion to use for the file names
371
372 // (1) this variable exists for the sole purpose of specifying the encoding
373 // of the filenames for GTK+ programs, so use it if it is set
374 wxString encName(wxGetenv(_T("G_FILENAME_ENCODING")));
375 encName = encName.BeforeFirst(_T(','));
376 if (encName.CmpNoCase(_T("@locale")) == 0)
377 encName.clear();
378 encName.MakeUpper();
379#if wxUSE_INTL
380 if (encName.empty())
381 {
382 // (2) if a non default locale is set, assume that the user wants his
383 // filenames in this locale too
384 encName = wxLocale::GetSystemEncodingName().Upper();
385 // (3) finally use UTF-8 by default
386 if (encName.empty() || encName == _T("US-ASCII"))
387 encName = _T("UTF-8");
388 wxSetEnv(_T("G_FILENAME_ENCODING"), encName);
389 }
390#else
391 if (encName.empty())
392 encName = _T("UTF-8");
393
394 // if wxUSE_INTL==0 it probably indicates that only "C" locale is supported
395 // by the program anyhow so prevent GTK+ from calling setlocale(LC_ALL, "")
396 // from gtk_init_check() as it does by default
397 gtk_disable_setlocale();
398
399#endif // wxUSE_INTL
400 static wxConvBrokenFileNames fileconv(encName);
401 wxConvFileName = &fileconv;
402
403
404 bool init_result;
405
406#if wxUSE_UNICODE
407 // gtk_init() wants UTF-8, not wchar_t, so convert
408 int i;
409 char **argvGTK = new char *[argc + 1];
410 for ( i = 0; i < argc; i++ )
411 {
412 argvGTK[i] = wxStrdupA(wxConvUTF8.cWX2MB(argv[i]));
413 }
414
415 argvGTK[argc] = NULL;
416
417 int argcGTK = argc;
418
419#ifdef __WXGPE__
420 init_result = true; // is there a _check() version of this?
421 gpe_application_init( &argcGTK, &argvGTK );
422#else
423 init_result = gtk_init_check( &argcGTK, &argvGTK );
424#endif
425
426 if ( argcGTK != argc )
427 {
428 // we have to drop the parameters which were consumed by GTK+
429 for ( i = 0; i < argcGTK; i++ )
430 {
431 while ( strcmp(wxConvUTF8.cWX2MB(argv[i]), argvGTK[i]) != 0 )
432 {
433 memmove(argv + i, argv + i + 1, (argc - i)*sizeof(*argv));
434 }
435 }
436
437 argc = argcGTK;
438 }
439 //else: gtk_init() didn't modify our parameters
440
441 // free our copy
442 for ( i = 0; i < argcGTK; i++ )
443 {
444 free(argvGTK[i]);
445 }
446
447 delete [] argvGTK;
448#else // !wxUSE_UNICODE
449 // gtk_init() shouldn't actually change argv itself (just its contents) so
450 // it's ok to pass pointer to it
451 init_result = gtk_init_check( &argc, &argv );
452#endif // wxUSE_UNICODE/!wxUSE_UNICODE
453
454 if (!init_result) {
455 wxLogError(wxT("Unable to initialize gtk, is DISPLAY set properly?"));
456 return false;
457 }
458
459 // we can not enter threads before gtk_init is done
460 gdk_threads_enter();
461
462 wxSetDetectableAutoRepeat( true );
463
464#if wxUSE_INTL
465 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
466#endif
467
468#if wxUSE_THREADS
469 m_idleMutex = new wxMutex;
470#endif
471 // make sure GtkWidget type is loaded, idle hooks need it
472 g_type_class_ref(GTK_TYPE_WIDGET);
473 WakeUpIdle();
474
475 return true;
476}
477
478void wxApp::CleanUp()
479{
480 if (m_idleSourceId != 0)
481 g_source_remove(m_idleSourceId);
482#if wxUSE_THREADS
483 delete m_idleMutex;
484 m_idleMutex = NULL;
485#endif
486 // release reference acquired by Initialize()
487 g_type_class_unref(g_type_class_peek(GTK_TYPE_WIDGET));
488
489 gdk_threads_leave();
490
491 wxAppBase::CleanUp();
492}
493
494void wxApp::WakeUpIdle()
495{
496#if wxUSE_THREADS
497 wxMutexLocker lock(*m_idleMutex);
498#endif
499 if (m_idleSourceId == 0)
500 m_idleSourceId = g_idle_add_full(G_PRIORITY_LOW, wxapp_idle_callback, NULL, NULL);
501}
502
503// Checking for pending events requires first removing our idle source,
504// otherwise it will cause the check to always return true.
505bool wxApp::EventsPending()
506{
507#if wxUSE_THREADS
508 wxMutexLocker lock(*m_idleMutex);
509#endif
510 if (m_idleSourceId != 0)
511 {
512 g_source_remove(m_idleSourceId);
513 m_idleSourceId = 0;
514 wx_add_idle_hooks();
515 }
516 return gtk_events_pending() != 0;
517}
518
519#ifdef __WXDEBUG__
520
521void wxApp::OnAssertFailure(const wxChar *file,
522 int line,
523 const wxChar* func,
524 const wxChar* cond,
525 const wxChar *msg)
526{
527
528 // block wx idle events while assert dialog is showing
529 m_isInAssert = true;
530
531 wxAppBase::OnAssertFailure(file, line, func, cond, msg);
532
533 m_isInAssert = false;
534}
535
536#endif // __WXDEBUG__