]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/app.cpp
removed extra membersections (patch 1702329)
[wxWidgets.git] / src / gtk / app.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
88a7a4e1 2// Name: src/gtk/app.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
32e9da8b 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
df744f4d 10#ifdef __VMS
f3858bf5
JJ
11// vms_jackets.h should for proper working be included before anything else
12# include <vms_jackets.h>
ff7d1dcb 13#undef ConnectionNumber
df744f4d
JJ
14#endif
15
f3858bf5
JJ
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
c801d85f 19#include "wx/app.h"
88a7a4e1
WS
20
21#ifndef WX_PRECOMP
22 #include "wx/intl.h"
e4db172a 23 #include "wx/log.h"
de6185e2 24 #include "wx/utils.h"
5b56bffb 25 #include "wx/memory.h"
48a1108e 26 #include "wx/font.h"
88a7a4e1
WS
27#endif
28
fe593cc5 29#include "wx/thread.h"
afb74891 30
62be94e1 31#ifdef __WXGPE__
88a7a4e1 32 #include <gpe/init.h>
62be94e1
RR
33#endif
34
e8106239 35#include "wx/gtk/win_gtk.h"
84833214 36#include "wx/gtk/private.h"
c801d85f 37
c259ffdf 38#include <gdk/gdkx.h>
24178e4a 39
2b850ae1
RR
40//-----------------------------------------------------------------------------
41// link GnomeVFS
42//-----------------------------------------------------------------------------
43
09a09455
PC
44#if wxUSE_MIMETYPE && wxUSE_LIBGNOMEVFS
45 #include "wx/link.h"
46 wxFORCE_LINK_MODULE(gnome_vfs)
2b850ae1
RR
47#endif
48
c801d85f
KB
49//-----------------------------------------------------------------------------
50// global data
51//-----------------------------------------------------------------------------
52
de6185e2 53bool g_mainThreadLocked = false;
3ac8d3bc 54
c2fa61e8 55static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
d76fe38b 56
bf9e3e73
RR
57//-----------------------------------------------------------------------------
58// wxYield
59//-----------------------------------------------------------------------------
53a8af59 60
1ee339ee
VZ
61// not static because used by textctrl.cpp
62//
63// MT-FIXME
88a7a4e1 64bool wxIsInsideYield = false;
1ee339ee 65
8461e4c2 66bool wxApp::Yield(bool onlyIfNeeded)
c801d85f 67{
1ee339ee 68 if ( wxIsInsideYield )
8461e4c2
VZ
69 {
70 if ( !onlyIfNeeded )
71 {
72 wxFAIL_MSG( wxT("wxYield called recursively" ) );
73 }
74
88a7a4e1 75 return false;
8461e4c2
VZ
76 }
77
6dc5fd71
VZ
78#if wxUSE_THREADS
79 if ( !wxThread::IsMain() )
80 {
81 // can't call gtk_main_iteration() from other threads like this
88a7a4e1 82 return true;
6dc5fd71
VZ
83 }
84#endif // wxUSE_THREADS
85
88a7a4e1 86 wxIsInsideYield = true;
e90c1d2a 87
dd7641ef 88#if wxUSE_LOG
2ed3265e
VZ
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();
dd7641ef 92#endif
2ed3265e 93
a1abca32 94 while (EventsPending())
406a6f6b
VZ
95 gtk_main_iteration();
96
5375a1f5
RR
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
be88a6ad 99 // OnUpdateUI() which is a nice (and desired) side effect). But we
5375a1f5
RR
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();
2ed3265e 104
dd7641ef 105#if wxUSE_LOG
2ed3265e
VZ
106 // let the logs be flashed again
107 wxLog::Resume();
dd7641ef 108#endif
7741c4e1 109
88a7a4e1 110 wxIsInsideYield = false;
99ba739f 111
88a7a4e1 112 return true;
acfd422a
RR
113}
114
bf9e3e73
RR
115//-----------------------------------------------------------------------------
116// local functions
117//-----------------------------------------------------------------------------
118
a1abca32
PC
119// One-shot signal emission hook, to install idle handler.
120extern "C" {
14819684 121static gboolean
a1abca32 122wx_emission_hook(GSignalInvocationHint*, guint, const GValue*, gpointer data)
14819684 123{
a1abca32
PC
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;
14819684
PC
130 // remove hook
131 return false;
132}
a1abca32 133}
14819684 134
a1abca32
PC
135// Add signal emission hooks, to re-install idle handler when needed.
136static void wx_add_idle_hooks()
8a378a9e 137{
a1abca32 138 // "event" hook
176d9824 139 {
a1abca32
PC
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 }
176d9824 163 }
8a378a9e
PC
164}
165
a1abca32
PC
166extern "C" {
167static gboolean wxapp_idle_callback(gpointer)
96997d65 168{
a1abca32
PC
169 return wxTheApp->DoIdle();
170}
171}
ec439571 172
a1abca32
PC
173bool wxApp::DoIdle()
174{
175 guint id_save;
ec439571 176 {
a1abca32
PC
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.
046c2f14 180#if wxUSE_THREADS
a1abca32 181 wxMutexLocker lock(*m_idleMutex);
046c2f14 182#endif
a1abca32
PC
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 }
ec439571 193
a1abca32
PC
194 gdk_threads_enter();
195 bool needMore;
196 do {
197 needMore = ProcessIdle();
198 } while (needMore && gtk_events_pending() == 0);
199 gdk_threads_leave();
f4322df6 200
046c2f14 201#if wxUSE_THREADS
a1abca32 202 wxMutexLocker lock(*m_idleMutex);
046c2f14 203#endif
a1abca32
PC
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;
ec439571 210 }
a1abca32
PC
211 // if more idle processing requested
212 if (needMore)
9a5c9a0c 213 {
a1abca32
PC
214 // keep this source installed
215 m_idleSourceId = id_save;
216 return true;
9a5c9a0c 217 }
a1abca32
PC
218 // add hooks and remove this source
219 wx_add_idle_hooks();
220 return false;
acfd422a 221}
8801832d 222
90350682
VZ
223#if wxUSE_THREADS
224
3b5d2007 225static GPollFunc wxgs_poll_func;
2b5f62a0 226
3b5d2007 227extern "C" {
3133cb9f 228static gint wxapp_poll_func( GPollFD *ufds, guint nfds, gint timeout )
acfd422a 229{
49f29fbe
PC
230 gdk_threads_enter();
231
232 wxMutexGuiLeave();
e4db172a 233 g_mainThreadLocked = true;
7941ba11 234
3b5d2007 235 gint res = (*wxgs_poll_func)(ufds, nfds, timeout);
90350682 236
49f29fbe 237 wxMutexGuiEnter();
de6185e2 238 g_mainThreadLocked = false;
90350682 239
49f29fbe
PC
240 gdk_threads_leave();
241
3133cb9f 242 return res;
ff7b1510 243}
3b5d2007 244}
c801d85f 245
90350682
VZ
246#endif // wxUSE_THREADS
247
005f5d18
RR
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
c801d85f
KB
262//-----------------------------------------------------------------------------
263// wxApp
264//-----------------------------------------------------------------------------
265
266IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
267
53010e52 268BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
955a9197 269 EVT_IDLE(wxAppBase::OnIdle)
53010e52
RR
270END_EVENT_TABLE()
271
c801d85f
KB
272wxApp::wxApp()
273{
a5f1fd3e 274#ifdef __WXDEBUG__
de6185e2 275 m_isInAssert = false;
a5f1fd3e 276#endif // __WXDEBUG__
a1abca32
PC
277#if wxUSE_THREADS
278 m_idleMutex = NULL;
279#endif
280 m_idleSourceId = 0;
ff7b1510 281}
c801d85f 282
60acb947 283wxApp::~wxApp()
c801d85f 284{
ff7b1510 285}
c801d85f 286
0d2a2b60 287bool wxApp::OnInitGui()
c801d85f 288{
1e6feb95 289 if ( !wxAppBase::OnInitGui() )
de6185e2 290 return false;
1e6feb95 291
a6f5aa49
VZ
292 // if this is a wxGLApp (derived from wxApp), and we've already
293 // chosen a specific visual, then derive the GdkVisual from that
498ace9e 294 if ( GetXVisualInfo() )
005f5d18 295 {
a6f5aa49 296 GdkVisual* vis = gtk_widget_get_default_visual();
a6f5aa49
VZ
297
298 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
299 gtk_widget_set_default_colormap( colormap );
a6f5aa49 300 }
005f5d18 301 else
b134516c 302 {
c77eea28
RR
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 }
f6fcbb63 328 }
c801d85f 329
88a7a4e1 330 return true;
bbe0af5b
RR
331}
332
005f5d18
RR
333GdkVisual *wxApp::GetGdkVisual()
334{
335 GdkVisual *visual = NULL;
be88a6ad 336
498ace9e
VZ
337 XVisualInfo *xvi = (XVisualInfo *)GetXVisualInfo();
338 if ( xvi )
339 visual = gdkx_visual_get( xvi->visualid );
005f5d18 340 else
22a3bce4 341 visual = gdk_drawable_get_visual( wxGetRootWindow()->window );
be88a6ad 342
005f5d18 343 wxASSERT( visual );
be88a6ad 344
005f5d18
RR
345 return visual;
346}
347
abca8ebf 348bool wxApp::Initialize(int& argc, wxChar **argv)
c801d85f 349{
d774f916
VZ
350 if ( !wxAppBase::Initialize(argc, argv) )
351 return false;
68567a96 352
924ef850 353#if wxUSE_THREADS
ac131bab
MR
354 if (!g_thread_supported())
355 g_thread_init(NULL);
3b5d2007
PC
356
357 wxgs_poll_func = g_main_context_get_poll_func(NULL);
358 g_main_context_set_poll_func(NULL, wxapp_poll_func);
05e2b077 359#endif // wxUSE_THREADS
2286341c 360
f9862abd
JS
361 // We should have the wxUSE_WCHAR_T test on the _outside_
362#if wxUSE_WCHAR_T
68567a96
MR
363 // gtk+ 2.0 supports Unicode through UTF-8 strings
364 wxConvCurrent = &wxConvUTF8;
05e2b077
VZ
365#else // !wxUSE_WCHAR_T
366 if (!wxOKlibc())
367 wxConvCurrent = (wxMBConv*) NULL;
368#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
002f4218 369
845905d5
MW
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")));
29c326b7 375 encName = encName.BeforeFirst(_T(','));
7c8ec100 376 if (encName.CmpNoCase(_T("@locale")) == 0)
d24b23b7 377 encName.clear();
845905d5 378 encName.MakeUpper();
68567a96 379#if wxUSE_INTL
845905d5
MW
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");
7ecb75b7
VZ
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
845905d5
MW
399#endif // wxUSE_INTL
400 static wxConvBrokenFileNames fileconv(encName);
401 wxConvFileName = &fileconv;
66bf0099 402
d774f916
VZ
403
404 bool init_result;
405
05e2b077
VZ
406#if wxUSE_UNICODE
407 // gtk_init() wants UTF-8, not wchar_t, so convert
408 int i;
0d8dda32 409 char **argvGTK = new char *[argc + 1];
05e2b077 410 for ( i = 0; i < argc; i++ )
924ef850 411 {
05e2b077 412 argvGTK[i] = wxStrdupA(wxConvUTF8.cWX2MB(argv[i]));
924ef850 413 }
0cf2cb36 414
05e2b077 415 argvGTK[argc] = NULL;
954de0f1 416
05e2b077 417 int argcGTK = argc;
68567a96 418
62be94e1 419#ifdef __WXGPE__
c156411a 420 init_result = true; // is there a _check() version of this?
62be94e1
RR
421 gpe_application_init( &argcGTK, &argvGTK );
422#else
c156411a 423 init_result = gtk_init_check( &argcGTK, &argvGTK );
62be94e1 424#endif
954de0f1 425
05e2b077 426 if ( argcGTK != argc )
924ef850 427 {
05e2b077
VZ
428 // we have to drop the parameters which were consumed by GTK+
429 for ( i = 0; i < argcGTK; i++ )
430 {
0d8dda32 431 while ( strcmp(wxConvUTF8.cWX2MB(argv[i]), argvGTK[i]) != 0 )
05e2b077 432 {
c8db4e15 433 memmove(argv + i, argv + i + 1, (argc - i)*sizeof(*argv));
05e2b077
VZ
434 }
435 }
0cf2cb36 436
05e2b077 437 argc = argcGTK;
2b5f62a0 438 }
05e2b077 439 //else: gtk_init() didn't modify our parameters
e0253070 440
05e2b077
VZ
441 // free our copy
442 for ( i = 0; i < argcGTK; i++ )
0151c3eb 443 {
05e2b077 444 free(argvGTK[i]);
0151c3eb 445 }
0cf2cb36 446
05e2b077
VZ
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
c156411a 451 init_result = gtk_init_check( &argc, &argv );
05e2b077 452#endif // wxUSE_UNICODE/!wxUSE_UNICODE
0cf2cb36 453
c156411a
RD
454 if (!init_result) {
455 wxLogError(wxT("Unable to initialize gtk, is DISPLAY set properly?"));
456 return false;
457 }
68567a96 458
05e2b077
VZ
459 // we can not enter threads before gtk_init is done
460 gdk_threads_enter();
0cf2cb36 461
e4db172a 462 wxSetDetectableAutoRepeat( true );
be88a6ad 463
05e2b077
VZ
464#if wxUSE_INTL
465 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
466#endif
be88a6ad 467
a1abca32
PC
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
05e2b077
VZ
475 return true;
476}
0cf2cb36 477
05e2b077
VZ
478void wxApp::CleanUp()
479{
a1abca32
PC
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
05e2b077 489 gdk_threads_leave();
abca8ebf
VZ
490
491 wxAppBase::CleanUp();
ff7b1510 492}
1a56f55c 493
a1abca32
PC
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
a5f1fd3e
VZ
519#ifdef __WXDEBUG__
520
2d97237d
VZ
521void wxApp::OnAssertFailure(const wxChar *file,
522 int line,
523 const wxChar* func,
524 const wxChar* cond,
525 const wxChar *msg)
a5f1fd3e 526{
ec439571
PC
527
528 // block wx idle events while assert dialog is showing
529 m_isInAssert = true;
a5f1fd3e 530
2d97237d 531 wxAppBase::OnAssertFailure(file, line, func, cond, msg);
a5f1fd3e 532
ec439571 533 m_isInAssert = false;
a5f1fd3e
VZ
534}
535
536#endif // __WXDEBUG__