]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/evtloop.cpp
fixing setting initial value under osx_cocoa for single line text controls
[wxWidgets.git] / src / gtk / evtloop.cpp
CommitLineData
8000ae7f 1///////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/gtk/evtloop.cpp
8000ae7f
VZ
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>
65571936 9// License: wxWindows licence
8000ae7f
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
8000ae7f
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
8000ae7f 27#include "wx/evtloop.h"
670f9935
WS
28
29#ifndef WX_PRECOMP
30 #include "wx/app.h"
bcf79477 31 #include "wx/log.h"
670f9935 32#endif // WX_PRECOMP
8000ae7f
VZ
33
34#include <gtk/gtk.h>
35
8000ae7f
VZ
36// ============================================================================
37// wxEventLoop implementation
38// ============================================================================
39
dde19c21
FM
40extern GtkWidget *wxGetRootWindow();
41
8000ae7f
VZ
42// ----------------------------------------------------------------------------
43// wxEventLoop running and exiting
44// ----------------------------------------------------------------------------
45
564c7fc4 46wxGUIEventLoop::wxGUIEventLoop()
8000ae7f 47{
564c7fc4 48 m_exitcode = 0;
8000ae7f
VZ
49}
50
b46b1d59 51int wxGUIEventLoop::Run()
8000ae7f
VZ
52{
53 // event loops are not recursive, you need to create another loop!
564c7fc4 54 wxCHECK_MSG( !IsRunning(), -1, "can't reenter a message loop" );
8000ae7f 55
77fb1a02 56 wxEventLoopActivator activate(this);
b9f246f7 57
8000ae7f
VZ
58 gtk_main();
59
16d17da6
VZ
60 OnExit();
61
564c7fc4 62 return m_exitcode;
8000ae7f
VZ
63}
64
b46b1d59 65void wxGUIEventLoop::Exit(int rc)
8000ae7f 66{
564c7fc4 67 wxCHECK_RET( IsRunning(), "can't call Exit() if not running" );
8000ae7f 68
564c7fc4 69 m_exitcode = rc;
8000ae7f
VZ
70
71 gtk_main_quit();
72}
73
564c7fc4
VZ
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
8000ae7f
VZ
84// ----------------------------------------------------------------------------
85// wxEventLoop message processing dispatching
86// ----------------------------------------------------------------------------
87
b46b1d59 88bool wxGUIEventLoop::Pending() const
8000ae7f 89{
564c7fc4
VZ
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;
8000ae7f
VZ
97}
98
b46b1d59 99bool wxGUIEventLoop::Dispatch()
8000ae7f 100{
9a83f860 101 wxCHECK_MSG( IsRunning(), false, wxT("can't call Dispatch() if not running") );
8000ae7f 102
4b8af4ac
VZ
103 // gtk_main_iteration() returns TRUE only if gtk_main_quit() was called
104 return !gtk_main_iteration();
8000ae7f 105}
564c7fc4
VZ
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
dde19c21
FM
132//-----------------------------------------------------------------------------
133// YieldFor
134//-----------------------------------------------------------------------------
135
f629f37a
PC
136extern "C" {
137static void wxgtk_main_do_event(GdkEvent* event, void* data)
387e72ba
FM
138{
139 // categorize the GDK event according to wxEventCategory.
140 // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
141 // for more info.
03647350 142
3bb5029d
FM
143 // NOTE: GDK_* constants which were not present in the GDK2.0 can be tested for
144 // only at compile-time; when running the program (compiled with a recent GDK)
03647350
VZ
145 // on a system with an older GDK lib we can be sure there won't be problems
146 // because event->type will never assume those values corresponding to
3bb5029d
FM
147 // new event types (since new event types are always added in GDK with non
148 // conflicting values for ABI compatibility).
387e72ba
FM
149
150 wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
151 switch (event->type)
152 {
153 case GDK_SELECTION_REQUEST:
154 case GDK_SELECTION_NOTIFY:
155 case GDK_SELECTION_CLEAR:
3bb5029d 156#if GTK_CHECK_VERSION(2,6,0)
387e72ba 157 case GDK_OWNER_CHANGE:
3bb5029d 158#endif
387e72ba
FM
159 cat = wxEVT_CATEGORY_CLIPBOARD;
160 break;
161
387e72ba
FM
162 case GDK_KEY_PRESS:
163 case GDK_KEY_RELEASE:
164 case GDK_BUTTON_PRESS:
165 case GDK_2BUTTON_PRESS:
166 case GDK_3BUTTON_PRESS:
167 case GDK_BUTTON_RELEASE:
168 case GDK_SCROLL: // generated from mouse buttons
169 case GDK_CLIENT_EVENT:
170 cat = wxEVT_CATEGORY_USER_INPUT;
171 break;
172
173 case GDK_PROXIMITY_IN:
174 case GDK_PROXIMITY_OUT:
175
176 case GDK_MOTION_NOTIFY:
177 case GDK_ENTER_NOTIFY:
178 case GDK_LEAVE_NOTIFY:
179 case GDK_VISIBILITY_NOTIFY:
180 case GDK_PROPERTY_NOTIFY:
181
182 case GDK_FOCUS_CHANGE:
183 case GDK_CONFIGURE:
184 case GDK_WINDOW_STATE:
185 case GDK_SETTING:
186 case GDK_DELETE:
187 case GDK_DESTROY:
188
189 case GDK_EXPOSE:
190 case GDK_NO_EXPOSE:
191 case GDK_MAP:
192 case GDK_UNMAP:
193
194 case GDK_DRAG_ENTER:
195 case GDK_DRAG_LEAVE:
196 case GDK_DRAG_MOTION:
197 case GDK_DRAG_STATUS:
198 case GDK_DROP_START:
199 case GDK_DROP_FINISHED:
3bb5029d 200#if GTK_CHECK_VERSION(2,8,0)
387e72ba 201 case GDK_GRAB_BROKEN:
3bb5029d
FM
202#endif
203#if GTK_CHECK_VERSION(2,14,0)
204 case GDK_DAMAGE:
205#endif
387e72ba
FM
206 cat = wxEVT_CATEGORY_UI;
207 break;
208
209 default:
210 cat = wxEVT_CATEGORY_UNKNOWN;
211 break;
212 }
213
f629f37a
PC
214 wxGUIEventLoop* evtloop = static_cast<wxGUIEventLoop*>(data);
215
387e72ba
FM
216 // is this event allowed now?
217 if (evtloop->IsEventAllowedInsideYield(cat))
218 gtk_main_do_event(event); // process it now
219 else if (event->type != GDK_NOTHING)
220 evtloop->StoreGdkEventForLaterProcessing(gdk_event_copy(event));
221 // process it later (but make a copy; the caller will free the event pointer)
222}
f629f37a 223}
387e72ba 224
dde19c21
FM
225bool wxGUIEventLoop::YieldFor(long eventsToProcess)
226{
227#if wxUSE_THREADS
228 if ( !wxThread::IsMain() )
229 {
230 // can't call gtk_main_iteration() from other threads like this
231 return true;
232 }
233#endif // wxUSE_THREADS
234
235 m_isInsideYield = true;
236 m_eventsToProcessInsideYield = eventsToProcess;
237
238#if wxUSE_LOG
239 // disable log flushing from here because a call to wxYield() shouldn't
240 // normally result in message boxes popping up &c
241 wxLog::Suspend();
242#endif
243
387e72ba
FM
244 // temporarily replace the global GDK event handler with our function, which
245 // categorizes the events and using m_eventsToProcessInsideYield decides
246 // if an event should be processed immediately or not
247 // NOTE: this approach is better than using gdk_display_get_event() because
248 // gtk_main_iteration() does more than just calling gdk_display_get_event()
249 // and then call gtk_main_do_event()!
250 // In particular in this way we also process input from sources like
251 // GIOChannels (this is needed for e.g. wxGUIAppTraits::WaitForChild).
f629f37a 252 gdk_event_handler_set(wxgtk_main_do_event, this, NULL);
387e72ba
FM
253 while (Pending()) // avoid false positives from our idle source
254 gtk_main_iteration();
255 gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
564c7fc4 256
dde19c21
FM
257 if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
258 {
259 // It's necessary to call ProcessIdle() to update the frames sizes which
260 // might have been changed (it also will update other things set from
261 // OnUpdateUI() which is a nice (and desired) side effect). But we
262 // call ProcessIdle() only once since this is not meant for longish
263 // background jobs (controlled by wxIdleEvent::RequestMore() and the
264 // return value of Processidle().
265 ProcessIdle(); // ProcessIdle() also calls ProcessPendingEvents()
266 }
267 //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
268 // the user app contains an UI update handler which calls wxClipboard::IsSupported,
269 // then we fall into a never-ending loop...
270
271 // put all unprocessed GDK events back in the queue
387e72ba 272 GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
dde19c21
FM
273 for (size_t i=0; i<m_arrGdkEvents.GetCount(); i++)
274 {
275 GdkEvent* ev = (GdkEvent*)m_arrGdkEvents[i];
276
277 // NOTE: gdk_display_put_event makes a copy of the event passed to it
278 gdk_display_put_event(disp, ev);
279 gdk_event_free(ev);
280 }
281
282 m_arrGdkEvents.Clear();
283
284#if wxUSE_LOG
285 // let the logs be flashed again
286 wxLog::Resume();
287#endif
288
289 m_isInsideYield = false;
290
291 return true;
292}