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