]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/evtloop.cpp
fixed wxXmlResource::Load's detection of filenames to be done as early as possible
[wxWidgets.git] / src / gtk / evtloop.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/evtloop.cpp
3// Purpose: implements wxEventLoop for GTK+
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 10.07.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// License: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#include "wx/evtloop.h"
28
29#ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/log.h"
32#endif // WX_PRECOMP
33
34#include <gtk/gtk.h>
35
36// ============================================================================
37// wxEventLoop implementation
38// ============================================================================
39
40extern GtkWidget *wxGetRootWindow();
41
42// ----------------------------------------------------------------------------
43// wxEventLoop running and exiting
44// ----------------------------------------------------------------------------
45
46wxGUIEventLoop::wxGUIEventLoop()
47{
48 m_exitcode = 0;
49}
50
51int wxGUIEventLoop::Run()
52{
53 // event loops are not recursive, you need to create another loop!
54 wxCHECK_MSG( !IsRunning(), -1, "can't reenter a message loop" );
55
56 wxEventLoopActivator activate(this);
57
58 gtk_main();
59
60 OnExit();
61
62 return m_exitcode;
63}
64
65void wxGUIEventLoop::Exit(int rc)
66{
67 wxCHECK_RET( IsRunning(), "can't call Exit() if not running" );
68
69 m_exitcode = rc;
70
71 gtk_main_quit();
72}
73
74void wxGUIEventLoop::WakeUp()
75{
76 // TODO: idle events handling should really be done by wxEventLoop itself
77 // but for now it's completely in gtk/app.cpp so just call there when
78 // we have wxTheApp and hope that it doesn't matter that we do
79 // nothing when we don't...
80 if ( wxTheApp )
81 wxTheApp->WakeUpIdle();
82}
83
84// ----------------------------------------------------------------------------
85// wxEventLoop message processing dispatching
86// ----------------------------------------------------------------------------
87
88bool wxGUIEventLoop::Pending() const
89{
90 if ( wxTheApp )
91 {
92 // this avoids false positives from our idle source
93 return wxTheApp->EventsPending();
94 }
95
96 return gtk_events_pending() != 0;
97}
98
99bool wxGUIEventLoop::Dispatch()
100{
101 wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") );
102
103 // gtk_main_iteration() returns TRUE only if gtk_main_quit() was called
104 return !gtk_main_iteration();
105}
106
107extern "C" {
108static gboolean wx_event_loop_timeout(void* data)
109{
110 bool* expired = static_cast<bool*>(data);
111 *expired = true;
112
113 // return FALSE to remove this timeout
114 return FALSE;
115}
116}
117
118int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
119{
120 bool expired = false;
121 const unsigned id = g_timeout_add(timeout, wx_event_loop_timeout, &expired);
122 bool quit = gtk_main_iteration() != 0;
123
124 if ( expired )
125 return -1;
126
127 g_source_remove(id);
128
129 return !quit;
130}
131
132//-----------------------------------------------------------------------------
133// YieldFor
134//-----------------------------------------------------------------------------
135
136bool wxGUIEventLoop::YieldFor(long eventsToProcess)
137{
138#if wxUSE_THREADS
139 if ( !wxThread::IsMain() )
140 {
141 // can't call gtk_main_iteration() from other threads like this
142 return true;
143 }
144#endif // wxUSE_THREADS
145
146 m_isInsideYield = true;
147 m_eventsToProcessInsideYield = eventsToProcess;
148
149#if wxUSE_LOG
150 // disable log flushing from here because a call to wxYield() shouldn't
151 // normally result in message boxes popping up &c
152 wxLog::Suspend();
153#endif
154
155 // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
156 // rather use gtk_main_do_event() after filtering the events at
157 // GDK level
158
159 GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
160
161 // gdk_display_get_event() will transform X11 events into GDK events
162 // and will queue all of them in the display (private) structure;
163 // finally it will "unqueue" the last one and return it to us
164 GdkEvent* event = gdk_display_get_event(disp);
165 while (event)
166 {
167 // categorize the GDK event according to wxEventCategory.
168 // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
169 // for more info.
170
171 wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
172 switch (event->type)
173 {
174 case GDK_SELECTION_REQUEST:
175 case GDK_SELECTION_NOTIFY:
176 case GDK_SELECTION_CLEAR:
177 case GDK_OWNER_CHANGE:
178 cat = wxEVT_CATEGORY_CLIPBOARD;
179 break;
180
181
182 case GDK_KEY_PRESS:
183 case GDK_KEY_RELEASE:
184 case GDK_BUTTON_PRESS:
185 case GDK_2BUTTON_PRESS:
186 case GDK_3BUTTON_PRESS:
187 case GDK_BUTTON_RELEASE:
188 case GDK_SCROLL: // generated from mouse buttons
189 case GDK_CLIENT_EVENT:
190 cat = wxEVT_CATEGORY_USER_INPUT;
191 break;
192
193
194 case GDK_PROXIMITY_IN:
195 case GDK_PROXIMITY_OUT:
196
197 case GDK_MOTION_NOTIFY:
198 case GDK_ENTER_NOTIFY:
199 case GDK_LEAVE_NOTIFY:
200 case GDK_VISIBILITY_NOTIFY:
201 case GDK_PROPERTY_NOTIFY:
202
203 case GDK_FOCUS_CHANGE:
204 case GDK_CONFIGURE:
205 case GDK_WINDOW_STATE:
206 case GDK_SETTING:
207 case GDK_DELETE:
208 case GDK_DESTROY:
209
210 case GDK_EXPOSE:
211 case GDK_NO_EXPOSE:
212 case GDK_MAP:
213 case GDK_UNMAP:
214 //case GDK_DAMAGE:
215
216 case GDK_DRAG_ENTER:
217 case GDK_DRAG_LEAVE:
218 case GDK_DRAG_MOTION:
219 case GDK_DRAG_STATUS:
220 case GDK_DROP_START:
221 case GDK_DROP_FINISHED:
222 case GDK_GRAB_BROKEN:
223 cat = wxEVT_CATEGORY_UI;
224 break;
225
226 default:
227 cat = wxEVT_CATEGORY_UNKNOWN;
228 break;
229 }
230
231 if (eventsToProcess & cat)
232 gtk_main_do_event(event); // process it now
233 else
234 m_arrGdkEvents.Add(event); // process it later
235
236 // get next event
237 event = gdk_display_get_event(disp);
238 }
239
240 if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
241 {
242 // It's necessary to call ProcessIdle() to update the frames sizes which
243 // might have been changed (it also will update other things set from
244 // OnUpdateUI() which is a nice (and desired) side effect). But we
245 // call ProcessIdle() only once since this is not meant for longish
246 // background jobs (controlled by wxIdleEvent::RequestMore() and the
247 // return value of Processidle().
248 ProcessIdle(); // ProcessIdle() also calls ProcessPendingEvents()
249 }
250 //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
251 // the user app contains an UI update handler which calls wxClipboard::IsSupported,
252 // then we fall into a never-ending loop...
253
254 // put all unprocessed GDK events back in the queue
255 for (size_t i=0; i<m_arrGdkEvents.GetCount(); i++)
256 {
257 GdkEvent* ev = (GdkEvent*)m_arrGdkEvents[i];
258
259 // NOTE: gdk_display_put_event makes a copy of the event passed to it
260 gdk_display_put_event(disp, ev);
261 gdk_event_free(ev);
262 }
263
264 m_arrGdkEvents.Clear();
265
266#if wxUSE_LOG
267 // let the logs be flashed again
268 wxLog::Resume();
269#endif
270
271 m_isInsideYield = false;
272
273 return true;
274}