1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/app.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
19 #include "wx/memory.h"
23 #include "wx/thread.h"
29 #include "wx/gtk/private.h"
30 #include "wx/apptrait.h"
33 #include <hildon-widgets/hildon-program.h>
34 #endif // wxUSE_LIBHILDON
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 #if wxUSE_MIMETYPE && wxUSE_LIBGNOMEVFS
44 wxFORCE_LINK_MODULE(gnome_vfs
)
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
51 static GtkWidget
*gs_RootWindow
= NULL
;
52 static wxArrayPtrVoid g_arrGdkEvents
;
54 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
58 bool wxApp::DoYield(bool onlyIfNeeded
, long eventsToProcess
)
60 if ( m_isInsideYield
)
64 wxFAIL_MSG( wxT("wxYield called recursively" ) );
71 if ( !wxThread::IsMain() )
73 // can't call gtk_main_iteration() from other threads like this
76 #endif // wxUSE_THREADS
78 m_isInsideYield
= true;
79 m_eventsToProcessInsideYield
= eventsToProcess
;
82 // disable log flushing from here because a call to wxYield() shouldn't
83 // normally result in message boxes popping up &c
87 // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
88 // rather use gtk_main_do_event() after filtering the events at
91 GdkDisplay
* disp
= gtk_widget_get_display(gs_RootWindow
);
93 // gdk_display_get_event() will transform X11 events into GDK events
94 // and will queue all of them in the display (private) structure;
95 // finally it will "unqueue" the last one and return it to us
96 GdkEvent
* event
= gdk_display_get_event(disp
);
99 // categorize the GDK event according to wxEventCategory.
100 // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
103 wxEventCategory cat
= wxEVT_CATEGORY_UNKNOWN
;
106 case GDK_SELECTION_REQUEST
:
107 case GDK_SELECTION_NOTIFY
:
108 case GDK_SELECTION_CLEAR
:
109 case GDK_OWNER_CHANGE
:
110 cat
= wxEVT_CATEGORY_CLIPBOARD
;
115 case GDK_KEY_RELEASE
:
116 case GDK_BUTTON_PRESS
:
117 case GDK_2BUTTON_PRESS
:
118 case GDK_3BUTTON_PRESS
:
119 case GDK_BUTTON_RELEASE
:
120 case GDK_SCROLL
: // generated from mouse buttons
121 case GDK_CLIENT_EVENT
:
122 cat
= wxEVT_CATEGORY_USER_INPUT
;
126 case GDK_PROXIMITY_IN
:
127 case GDK_PROXIMITY_OUT
:
129 case GDK_MOTION_NOTIFY
:
130 case GDK_ENTER_NOTIFY
:
131 case GDK_LEAVE_NOTIFY
:
132 case GDK_VISIBILITY_NOTIFY
:
133 case GDK_PROPERTY_NOTIFY
:
135 case GDK_FOCUS_CHANGE
:
137 case GDK_WINDOW_STATE
:
150 case GDK_DRAG_MOTION
:
151 case GDK_DRAG_STATUS
:
153 case GDK_DROP_FINISHED
:
154 case GDK_GRAB_BROKEN
:
155 cat
= wxEVT_CATEGORY_UI
;
159 cat
= wxEVT_CATEGORY_UNKNOWN
;
163 if (eventsToProcess
& cat
)
164 gtk_main_do_event(event
); // process it now
166 g_arrGdkEvents
.Add(event
); // process it later
169 event
= gdk_display_get_event(disp
);
172 if (eventsToProcess
!= wxEVT_CATEGORY_CLIPBOARD
)
174 // It's necessary to call ProcessIdle() to update the frames sizes which
175 // might have been changed (it also will update other things set from
176 // OnUpdateUI() which is a nice (and desired) side effect). But we
177 // call ProcessIdle() only once since this is not meant for longish
178 // background jobs (controlled by wxIdleEvent::RequestMore() and the
179 // return value of Processidle().
180 ProcessIdle(); // ProcessIdle() also calls ProcessPendingEvents()
182 //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
183 // the user app contains an UI update handler which calls wxClipboard::IsSupported,
184 // then we fall into a never-ending loop...
186 // put all unprocessed GDK events back in the queue
187 for (size_t i
=0; i
<g_arrGdkEvents
.GetCount(); i
++)
189 GdkEvent
* ev
= (GdkEvent
*)g_arrGdkEvents
[i
];
191 // NOTE: gdk_display_put_event makes a copy of the event passed to it
192 gdk_display_put_event(disp
, ev
);
196 g_arrGdkEvents
.Clear();
199 // let the logs be flashed again
203 m_isInsideYield
= false;
208 //-----------------------------------------------------------------------------
210 //-----------------------------------------------------------------------------
212 // One-shot signal emission hook, to install idle handler.
215 wx_emission_hook(GSignalInvocationHint
*, guint
, const GValue
*, gpointer data
)
217 wxApp
* app
= wxTheApp
;
220 gulong
* hook_id
= (gulong
*)data
;
221 // record that hook is not installed
228 // Add signal emission hooks, to re-install idle handler when needed.
229 static void wx_add_idle_hooks()
233 static gulong hook_id
= 0;
236 static guint sig_id
= 0;
238 sig_id
= g_signal_lookup("event", GTK_TYPE_WIDGET
);
239 hook_id
= g_signal_add_emission_hook(
240 sig_id
, 0, wx_emission_hook
, &hook_id
, NULL
);
243 // "size_allocate" hook
244 // Needed to match the behavior of the old idle system,
245 // but probably not necessary.
247 static gulong hook_id
= 0;
250 static guint sig_id
= 0;
252 sig_id
= g_signal_lookup("size_allocate", GTK_TYPE_WIDGET
);
253 hook_id
= g_signal_add_emission_hook(
254 sig_id
, 0, wx_emission_hook
, &hook_id
, NULL
);
260 static gboolean
wxapp_idle_callback(gpointer
)
262 return wxTheApp
->DoIdle();
270 // Allow another idle source to be added while this one is busy.
271 // Needed if an idle event handler runs a new event loop,
272 // for example by showing a dialog.
274 wxMutexLocker
lock(*m_idleMutex
);
276 id_save
= m_idleSourceId
;
280 // don't generate the idle events while the assert modal dialog is shown,
281 // this matches the behavior of wxMSW
290 needMore
= ProcessIdle();
291 } while (needMore
&& gtk_events_pending() == 0);
295 wxMutexLocker
lock(*m_idleMutex
);
297 // if a new idle source was added during ProcessIdle
298 if (m_idleSourceId
!= 0)
301 g_source_remove(m_idleSourceId
);
305 // Pending events can be added asynchronously,
306 // need to keep idle source if any have appeared
307 needMore
= needMore
|| HasPendingEvents();
309 // if more idle processing requested
312 // keep this source installed
313 m_idleSourceId
= id_save
;
316 // add hooks and remove this source
321 //-----------------------------------------------------------------------------
322 // Access to the root window global
323 //-----------------------------------------------------------------------------
325 GtkWidget
* wxGetRootWindow()
327 if (gs_RootWindow
== NULL
)
329 gs_RootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
330 gtk_widget_realize( gs_RootWindow
);
332 return gs_RootWindow
;
335 //-----------------------------------------------------------------------------
337 //-----------------------------------------------------------------------------
339 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
344 m_isInAssert
= false;
345 #endif // __WXDEBUG__
356 bool wxApp::SetNativeTheme(const wxString
& theme
)
359 path
= gtk_rc_get_theme_dir();
361 path
+= theme
.utf8_str();
362 path
+= "/gtk-2.0/gtkrc";
364 if ( wxFileExists(path
.utf8_str()) )
365 gtk_rc_add_default_file(path
.utf8_str());
366 else if ( wxFileExists(theme
.utf8_str()) )
367 gtk_rc_add_default_file(theme
.utf8_str());
370 wxLogWarning("Theme \"%s\" not available.", theme
);
375 gtk_rc_reparse_all_for_settings(gtk_settings_get_default(), TRUE
);
380 bool wxApp::OnInitGui()
382 if ( !wxAppBase::OnInitGui() )
385 // if this is a wxGLApp (derived from wxApp), and we've already
386 // chosen a specific visual, then derive the GdkVisual from that
387 if ( GetXVisualInfo() )
389 GdkVisual
* vis
= gtk_widget_get_default_visual();
391 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
392 gtk_widget_set_default_colormap( colormap
);
396 // On some machines, the default visual is just 256 colours, so
397 // we make sure we get the best. This can sometimes be wasteful.
400 if (m_forceTrueColour
)
402 GdkVisual
* visual
= gdk_visual_get_best_with_both( 24, GDK_VISUAL_TRUE_COLOR
);
405 wxLogError(wxT("Unable to initialize TrueColor visual."));
408 GdkColormap
*colormap
= gdk_colormap_new( visual
, FALSE
);
409 gtk_widget_set_default_colormap( colormap
);
413 if (gdk_visual_get_best() != gdk_visual_get_system())
415 GdkVisual
* visual
= gdk_visual_get_best();
416 GdkColormap
*colormap
= gdk_colormap_new( visual
, FALSE
);
417 gtk_widget_set_default_colormap( colormap
);
424 m_hildonProgram
= hildon_program_get_instance();
425 if ( !m_hildonProgram
)
427 wxLogError(_("Unable to initialize Hildon program"));
430 #endif // wxUSE_LIBHILDON
435 GdkVisual
*wxApp::GetGdkVisual()
437 GdkVisual
*visual
= NULL
;
439 XVisualInfo
*xvi
= (XVisualInfo
*)GetXVisualInfo();
441 visual
= gdkx_visual_get( xvi
->visualid
);
443 visual
= gdk_drawable_get_visual( wxGetRootWindow()->window
);
450 // use unusual names for the parameters to avoid conflict with wxApp::arg[cv]
451 bool wxApp::Initialize(int& argc_
, wxChar
**argv_
)
453 if ( !wxAppBase::Initialize(argc_
, argv_
) )
457 if (!g_thread_supported())
462 #endif // wxUSE_THREADS
464 // gtk+ 2.0 supports Unicode through UTF-8 strings
465 wxConvCurrent
= &wxConvUTF8
;
467 // decide which conversion to use for the file names
469 // (1) this variable exists for the sole purpose of specifying the encoding
470 // of the filenames for GTK+ programs, so use it if it is set
471 wxString
encName(wxGetenv(_T("G_FILENAME_ENCODING")));
472 encName
= encName
.BeforeFirst(_T(','));
473 if (encName
.CmpNoCase(_T("@locale")) == 0)
479 // (2) if a non default locale is set, assume that the user wants his
480 // filenames in this locale too
481 encName
= wxLocale::GetSystemEncodingName().Upper();
482 // (3) finally use UTF-8 by default
483 if (encName
.empty() || encName
== _T("US-ASCII"))
484 encName
= _T("UTF-8");
485 wxSetEnv(_T("G_FILENAME_ENCODING"), encName
);
489 encName
= _T("UTF-8");
491 // if wxUSE_INTL==0 it probably indicates that only "C" locale is supported
492 // by the program anyhow so prevent GTK+ from calling setlocale(LC_ALL, "")
493 // from gtk_init_check() as it does by default
494 gtk_disable_setlocale();
497 static wxConvBrokenFileNames
fileconv(encName
);
498 wxConvFileName
= &fileconv
;
505 // gtk_init() wants UTF-8, not wchar_t, so convert
506 char **argvGTK
= new char *[argc_
+ 1];
507 for ( i
= 0; i
< argc_
; i
++ )
509 argvGTK
[i
] = wxStrdupA(wxConvUTF8
.cWX2MB(argv_
[i
]));
512 argvGTK
[argc_
] = NULL
;
517 init_result
= true; // is there a _check() version of this?
518 gpe_application_init( &argcGTK
, &argvGTK
);
520 init_result
= gtk_init_check( &argcGTK
, &argvGTK
);
522 wxUpdateLocaleIsUtf8();
524 if ( argcGTK
!= argc_
)
526 // we have to drop the parameters which were consumed by GTK+
527 for ( i
= 0; i
< argcGTK
; i
++ )
529 while ( strcmp(wxConvUTF8
.cWX2MB(argv_
[i
]), argvGTK
[i
]) != 0 )
531 memmove(argv_
+ i
, argv_
+ i
+ 1, (argc_
- i
)*sizeof(*argv_
));
538 //else: gtk_init() didn't modify our parameters
541 for ( i
= 0; i
< argcGTK
; i
++ )
547 #else // !wxUSE_UNICODE
548 // gtk_init() shouldn't actually change argv_ itself (just its contents) so
549 // it's ok to pass pointer to it
550 init_result
= gtk_init_check( &argc_
, &argv_
);
551 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
553 // update internal arg[cv] as GTK+ may have removed processed options:
559 // if there are still GTK+ standard options unparsed in the command
560 // line, it means that they were not syntactically correct and GTK+
561 // already printed a warning on the command line and we should now
563 wxArrayString opt
, desc
;
564 m_traits
->GetStandardCmdLineOptions(opt
, desc
);
566 for ( i
= 0; i
< argc_
; i
++ )
568 // leave just the names of the options with values
569 const wxString str
= wxString(argv_
[i
]).BeforeFirst('=');
571 for ( size_t j
= 0; j
< opt
.size(); j
++ )
573 // remove the leading spaces from the option string as it does
575 if ( opt
[j
].Trim(false).BeforeFirst('=') == str
)
577 // a GTK+ option can be left on the command line only if
578 // there was an error in (or before, in another standard
579 // options) it, so abort, just as we do if incorrect
580 // program option is given
581 wxLogError(_("Invalid GTK+ command line option, use \"%s --help\""),
591 wxLogError(_("Unable to initialize GTK+, is DISPLAY set properly?"));
595 // we can not enter threads before gtk_init is done
598 wxSetDetectableAutoRepeat( true );
601 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
605 m_idleMutex
= new wxMutex
;
607 // make sure GtkWidget type is loaded, idle hooks need it
608 g_type_class_ref(GTK_TYPE_WIDGET
);
614 void wxApp::CleanUp()
616 if (m_idleSourceId
!= 0)
617 g_source_remove(m_idleSourceId
);
619 // release reference acquired by Initialize()
620 g_type_class_unref(g_type_class_peek(GTK_TYPE_WIDGET
));
624 wxAppBase::CleanUp();
626 // delete this mutex as late as possible as it's used from WakeUpIdle(), in
627 // particular do it after calling the base class CleanUp() which can result
628 // in it being called
635 void wxApp::WakeUpIdle()
638 wxMutexLocker
lock(*m_idleMutex
);
640 if (m_idleSourceId
== 0)
641 m_idleSourceId
= g_idle_add_full(G_PRIORITY_LOW
, wxapp_idle_callback
, NULL
, NULL
);
644 // Checking for pending events requires first removing our idle source,
645 // otherwise it will cause the check to always return true.
646 bool wxApp::EventsPending()
649 wxMutexLocker
lock(*m_idleMutex
);
651 if (m_idleSourceId
!= 0)
653 g_source_remove(m_idleSourceId
);
657 return gtk_events_pending() != 0;
662 void wxApp::OnAssertFailure(const wxChar
*file
,
669 // block wx idle events while assert dialog is showing
672 wxAppBase::OnAssertFailure(file
, line
, func
, cond
, msg
);
674 m_isInAssert
= false;
677 #endif // __WXDEBUG__
680 void wxGUIAppTraits::MutexGuiEnter()
685 void wxGUIAppTraits::MutexGuiLeave()
689 #endif // wxUSE_THREADS