1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/evtloop.cpp
3 // Purpose: implements wxEventLoop for GTK+
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/evtloop.h"
35 // ============================================================================
36 // wxEventLoop implementation
37 // ============================================================================
39 extern GtkWidget
*wxGetRootWindow();
41 // ----------------------------------------------------------------------------
42 // wxEventLoop running and exiting
43 // ----------------------------------------------------------------------------
45 wxGUIEventLoop::wxGUIEventLoop()
50 int wxGUIEventLoop::Run()
52 // event loops are not recursive, you need to create another loop!
53 wxCHECK_MSG( !IsRunning(), -1, "can't reenter a message loop" );
55 wxEventLoopActivator
activate(this);
64 void wxGUIEventLoop::Exit(int rc
)
66 wxCHECK_RET( IsRunning(), "can't call Exit() if not running" );
73 void wxGUIEventLoop::WakeUp()
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...
80 wxTheApp
->WakeUpIdle();
83 // ----------------------------------------------------------------------------
84 // wxEventLoop message processing dispatching
85 // ----------------------------------------------------------------------------
87 bool wxGUIEventLoop::Pending() const
91 // this avoids false positives from our idle source
92 return wxTheApp
->EventsPending();
95 return gtk_events_pending() != 0;
98 bool wxGUIEventLoop::Dispatch()
100 wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") );
102 // gtk_main_iteration() returns TRUE only if gtk_main_quit() was called
103 return !gtk_main_iteration();
107 static gboolean
wx_event_loop_timeout(void* data
)
109 bool* expired
= static_cast<bool*>(data
);
112 // return FALSE to remove this timeout
117 int wxGUIEventLoop::DispatchTimeout(unsigned long timeout
)
119 bool expired
= false;
120 const unsigned id
= g_timeout_add(timeout
, wx_event_loop_timeout
, &expired
);
121 bool quit
= gtk_main_iteration() != 0;
131 //-----------------------------------------------------------------------------
133 //-----------------------------------------------------------------------------
135 bool wxGUIEventLoop::YieldFor(long eventsToProcess
)
138 if ( !wxThread::IsMain() )
140 // can't call gtk_main_iteration() from other threads like this
143 #endif // wxUSE_THREADS
145 m_isInsideYield
= true;
146 m_eventsToProcessInsideYield
= eventsToProcess
;
149 // disable log flushing from here because a call to wxYield() shouldn't
150 // normally result in message boxes popping up &c
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
158 GdkDisplay
* disp
= gtk_widget_get_display(wxGetRootWindow());
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
);
166 // categorize the GDK event according to wxEventCategory.
167 // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
170 wxEventCategory cat
= wxEVT_CATEGORY_UNKNOWN
;
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
;
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
;
193 case GDK_PROXIMITY_IN
:
194 case GDK_PROXIMITY_OUT
:
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
:
202 case GDK_FOCUS_CHANGE
:
204 case GDK_WINDOW_STATE
:
217 case GDK_DRAG_MOTION
:
218 case GDK_DRAG_STATUS
:
220 case GDK_DROP_FINISHED
:
221 case GDK_GRAB_BROKEN
:
222 cat
= wxEVT_CATEGORY_UI
;
226 cat
= wxEVT_CATEGORY_UNKNOWN
;
230 if (eventsToProcess
& cat
)
231 gtk_main_do_event(event
); // process it now
233 m_arrGdkEvents
.Add(event
); // process it later
236 event
= gdk_display_get_event(disp
);
239 if (eventsToProcess
!= wxEVT_CATEGORY_CLIPBOARD
)
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()
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...
253 // put all unprocessed GDK events back in the queue
254 for (size_t i
=0; i
<m_arrGdkEvents
.GetCount(); i
++)
256 GdkEvent
* ev
= (GdkEvent
*)m_arrGdkEvents
[i
];
258 // NOTE: gdk_display_put_event makes a copy of the event passed to it
259 gdk_display_put_event(disp
, ev
);
263 m_arrGdkEvents
.Clear();
266 // let the logs be flashed again
270 m_isInsideYield
= false;