check in the 'selective yield' patch (see ticket #10320):
- implements YieldFor() with event filtering for wxMSW and wxGTK, adds TODO markers in other ports; - replaces wxYield() in GTK's clipboard code with a wxTheApp->YieldFor() call, thus fixing possible reentrancies (and modifies clipboard sample to test synchronous IsSupported calls) - replaces wxYieldIfNeeded() calls in wxProgressDialog with wxTheApp->YieldFor() calls, so that it processes only UI/user-input events, thus fixing the race condition visible in the "thread" sample - documents the new functions git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58654 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
122
src/gtk/app.cpp
122
src/gtk/app.cpp
@@ -49,12 +49,13 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static GtkWidget *gs_RootWindow = NULL;
|
||||
static wxArrayPtrVoid g_arrGdkEvents;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxYield
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool wxApp::Yield(bool onlyIfNeeded)
|
||||
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
|
||||
{
|
||||
if ( m_isInsideYield )
|
||||
{
|
||||
@@ -75,6 +76,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
|
||||
#endif // wxUSE_THREADS
|
||||
|
||||
m_isInsideYield = true;
|
||||
m_eventsToProcessInsideYield = eventsToProcess;
|
||||
|
||||
#if wxUSE_LOG
|
||||
// disable log flushing from here because a call to wxYield() shouldn't
|
||||
@@ -82,16 +84,116 @@ bool wxApp::Yield(bool onlyIfNeeded)
|
||||
wxLog::Suspend();
|
||||
#endif
|
||||
|
||||
while (EventsPending())
|
||||
gtk_main_iteration();
|
||||
// NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
|
||||
// rather use gtk_main_do_event() after filtering the events at
|
||||
// GDK level
|
||||
|
||||
// It's necessary to call ProcessIdle() to update the frames sizes which
|
||||
// might have been changed (it also will update other things set from
|
||||
// OnUpdateUI() which is a nice (and desired) side effect). But we
|
||||
// call ProcessIdle() only once since this is not meant for longish
|
||||
// background jobs (controlled by wxIdleEvent::RequestMore() and the
|
||||
// return value of Processidle().
|
||||
ProcessIdle();
|
||||
GdkDisplay* disp = gtk_widget_get_display(gs_RootWindow);
|
||||
|
||||
// gdk_display_get_event() will transform X11 events into GDK events
|
||||
// and will queue all of them in the display (private) structure;
|
||||
// finally it will "unqueue" the last one and return it to us
|
||||
GdkEvent* event = gdk_display_get_event(disp);
|
||||
while (event)
|
||||
{
|
||||
// categorize the GDK event according to wxEventCategory.
|
||||
// See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
|
||||
// for more info.
|
||||
|
||||
wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_SELECTION_REQUEST:
|
||||
case GDK_SELECTION_NOTIFY:
|
||||
case GDK_SELECTION_CLEAR:
|
||||
case GDK_OWNER_CHANGE:
|
||||
cat = wxEVT_CATEGORY_CLIPBOARD;
|
||||
break;
|
||||
|
||||
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_SCROLL: // generated from mouse buttons
|
||||
case GDK_CLIENT_EVENT:
|
||||
cat = wxEVT_CATEGORY_USER_INPUT;
|
||||
break;
|
||||
|
||||
|
||||
case GDK_PROXIMITY_IN:
|
||||
case GDK_PROXIMITY_OUT:
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
case GDK_VISIBILITY_NOTIFY:
|
||||
case GDK_PROPERTY_NOTIFY:
|
||||
|
||||
case GDK_FOCUS_CHANGE:
|
||||
case GDK_CONFIGURE:
|
||||
case GDK_WINDOW_STATE:
|
||||
case GDK_SETTING:
|
||||
case GDK_DELETE:
|
||||
case GDK_DESTROY:
|
||||
|
||||
case GDK_EXPOSE:
|
||||
case GDK_NO_EXPOSE:
|
||||
case GDK_MAP:
|
||||
case GDK_UNMAP:
|
||||
//case GDK_DAMAGE:
|
||||
|
||||
case GDK_DRAG_ENTER:
|
||||
case GDK_DRAG_LEAVE:
|
||||
case GDK_DRAG_MOTION:
|
||||
case GDK_DRAG_STATUS:
|
||||
case GDK_DROP_START:
|
||||
case GDK_DROP_FINISHED:
|
||||
case GDK_GRAB_BROKEN:
|
||||
cat = wxEVT_CATEGORY_UI;
|
||||
break;
|
||||
|
||||
default:
|
||||
cat = wxEVT_CATEGORY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (eventsToProcess & cat)
|
||||
gtk_main_do_event(event); // process it now
|
||||
else
|
||||
g_arrGdkEvents.Add(event); // process it later
|
||||
|
||||
// get next event
|
||||
event = gdk_display_get_event(disp);
|
||||
}
|
||||
|
||||
if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
|
||||
{
|
||||
// It's necessary to call ProcessIdle() to update the frames sizes which
|
||||
// might have been changed (it also will update other things set from
|
||||
// OnUpdateUI() which is a nice (and desired) side effect). But we
|
||||
// call ProcessIdle() only once since this is not meant for longish
|
||||
// background jobs (controlled by wxIdleEvent::RequestMore() and the
|
||||
// return value of Processidle().
|
||||
ProcessIdle(); // ProcessIdle() also calls ProcessPendingEvents()
|
||||
}
|
||||
//else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
|
||||
// the user app contains an UI update handler which calls wxClipboard::IsSupported,
|
||||
// then we fall into a never-ending loop...
|
||||
|
||||
// put all unprocessed GDK events back in the queue
|
||||
for (size_t i=0; i<g_arrGdkEvents.GetCount(); i++)
|
||||
{
|
||||
GdkEvent* ev = (GdkEvent*)g_arrGdkEvents[i];
|
||||
|
||||
// NOTE: gdk_display_put_event makes a copy of the event passed to it
|
||||
gdk_display_put_event(disp, ev);
|
||||
gdk_event_free(ev);
|
||||
}
|
||||
|
||||
g_arrGdkEvents.Clear();
|
||||
|
||||
#if wxUSE_LOG
|
||||
// let the logs be flashed again
|
||||
|
Reference in New Issue
Block a user