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:
Francesco Montorsi
2009-02-04 17:42:28 +00:00
parent a721fd82b7
commit d48b06bd90
39 changed files with 777 additions and 111 deletions

View File

@@ -32,6 +32,7 @@ class WXDLLIMPEXP_FWD_BASE wxMessageOutput;
#if wxUSE_GUI
struct WXDLLIMPEXP_FWD_CORE wxVideoMode;
class WXDLLIMPEXP_FWD_CORE wxWindow;
#endif
// ----------------------------------------------------------------------------
@@ -254,6 +255,13 @@ public:
// (already) be dispatched
static bool IsMainLoopRunning();
// temporary suspends processing of the pending events
virtual void SuspendProcessingOfPendingEvents();
// resume processing of the pending events previously stopped because of a
// call to SuspendProcessingOfPendingEvents()
virtual void ResumeProcessingOfPendingEvents();
// process all events in the wxHandlersWithPendingEvents list -- it is necessary
// to call this function to process posted events. This happens during each
// event loop iteration in GUI mode but if there is no main loop, it may be
@@ -263,9 +271,6 @@ public:
// check if there are pending events on global pending event list
bool HasPendingEvents() const;
// doesn't do anything in this class, just a hook for GUI wxApp
virtual bool Yield(bool WXUNUSED(onlyIfNeeded) = false) { return true; }
// make sure that idle events are sent again
virtual void WakeUpIdle();
@@ -300,6 +305,30 @@ public:
virtual bool OnExceptionInMainLoop();
#endif // wxUSE_EXCEPTIONS
// Yield-related hooks
// -------------------
// process all currently pending events right now
//
// it is an error to call Yield() recursively unless the value of
// onlyIfNeeded is true
//
// WARNING: this function is dangerous as it can lead to unexpected
// reentrancies (i.e. when called from an event handler it
// may result in calling the same event handler again), use
// with _extreme_ care or, better, don't use at all!
// NOTE: in wxConsoleBase it doesn't do anything, just a hook for GUI wxApp
bool Yield(bool onlyIfNeeded = false)
{ return DoYield(onlyIfNeeded, wxEVT_CATEGORY_ALL); }
bool YieldFor(long eventsToProcess)
{ return DoYield(true, eventsToProcess); }
virtual bool IsYielding() const
{ return false; }
virtual bool IsEventAllowedInsideYield(wxEventCategory WXUNUSED(cat)) const
{ return true; }
// no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
// debugging support
// -----------------
@@ -366,6 +395,9 @@ protected:
// for the first time
virtual wxAppTraits *CreateTraits();
// the real yield function hook:
virtual bool DoYield(bool WXUNUSED(onlyIfNeeded), long WXUNUSED(eventsToProcess))
{ return true; }
// function used for dynamic wxApp creation
static wxAppInitializerFunction ms_appInitFn;
@@ -392,6 +424,15 @@ protected:
// been started yet or has already terminated)
wxEventLoopBase *m_mainLoop;
// the array of the handlers with pending events which needs to be processed
// inside ProcessPendingEvents()
// wxEvtHandlerArray m_handlersWithPendingEvents; FIXME: enable this and remove global lists
// helper array used by ProcessPendingEvents()
// wxEvtHandlerArray m_handlersWithPendingDelayedEvents; FIXME: enable this and remove global lists
friend class WXDLLIMPEXP_BASE wxEvtHandler;
// the application object is a singleton anyhow, there is no sense in
// copying it
DECLARE_NO_COPY_CLASS(wxAppConsoleBase)
@@ -451,23 +492,19 @@ public:
// the worker functions - usually not used directly by the user code
// -----------------------------------------------------------------
// process all currently pending events right now
//
// it is an error to call Yield() recursively unless the value of
// onlyIfNeeded is true
//
// WARNING: this function is dangerous as it can lead to unexpected
// reentrancies (i.e. when called from an event handler it
// may result in calling the same event handler again), use
// with _extreme_ care or, better, don't use at all!
virtual bool Yield(bool onlyIfNeeded = false) = 0;
// safer alternatives to Yield(), using wxWindowDisabler
virtual bool SafeYield(wxWindow *win, bool onlyIfNeeded);
virtual bool SafeYieldFor(wxWindow *win, long eventsToProcess);
// returns true if the main thread is inside a Yield() call
bool IsYielding() const
virtual bool IsYielding() const
{ return m_isInsideYield; }
// returns true if events of the given event category should be immediately
// processed inside a wxApp::Yield() call or rather should be queued for
// later processing by the main event loop
virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const;
// this virtual function is called in the GUI mode when the application
// becomes idle and normally just sends wxIdleEvent to all interested
// parties
@@ -590,7 +627,9 @@ protected:
// does any of our windows have focus?
bool m_isActive;
// Yield() helpers:
bool m_isInsideYield;
long m_eventsToProcessInsideYield;
DECLARE_NO_COPY_CLASS(wxAppBase)
};
@@ -660,7 +699,7 @@ protected:
// Force an exit from main loop
WXDLLIMPEXP_BASE void wxExit();
// avoid redeclaring this function here if it had been already declated by
// avoid redeclaring this function here if it had been already declared by
// wx/utils.h, this results in warnings from g++ with -Wredundant-decls
#ifndef wx_YIELD_DECLARED
#define wx_YIELD_DECLARED

View File

@@ -57,7 +57,7 @@ public:
// Implement wxAppBase pure virtuals
virtual void Exit();
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
virtual void WakeUpIdle();
virtual bool Initialize(int& argc, wxChar **argv);

View File

@@ -32,7 +32,6 @@ public:
virtual void CleanUp();
virtual void WakeUpIdle();
virtual bool Yield(bool onlyIfNeeded = false);
virtual wxVideoMode GetDisplayMode() const;
virtual bool SetDisplayMode(const wxVideoMode& mode);
@@ -40,6 +39,8 @@ public:
private:
wxVideoMode m_videoMode;
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
DECLARE_DYNAMIC_CLASS(wxApp)
};

View File

@@ -574,6 +574,9 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_RCLICKED, wxComman
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, wxCommandEvent)
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_ENTER, wxCommandEvent)
// Thread events
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_THREAD, wxCommandEvent)
// Mouse event types
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_LEFT_DOWN, wxMouseEvent)
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_LEFT_UP, wxMouseEvent)
@@ -718,9 +721,14 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_DETAILED_HELP, wxHelpEvent)
// still, any new code using it should include wx/textctrl.h explicitly
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEvent)
// ----------------------------------------------------------------------------
// wxEvent(-derived) classes
// ----------------------------------------------------------------------------
// the predefined constants for the number of times we propagate event
// upwards window child-parent chain
enum Propagation_state
enum wxEventPropagation
{
// don't propagate it at all
wxEVENT_PROPAGATE_NONE = 0,
@@ -729,6 +737,58 @@ enum Propagation_state
wxEVENT_PROPAGATE_MAX = INT_MAX
};
// The different categories for a wxEvent; see wxEvent::GetEventCategory.
// NOTE: they are used as OR-combinable flags by wxApp::Yield
enum wxEventCategory
{
// this is the category for those events which are generated to update
// the appearance of the GUI but which (usually) do not comport data
// processing, i.e. which do not provide input or output data
// (e.g. size events, scroll events, etc).
// They are events NOT directly generated by the user's input devices.
wxEVT_CATEGORY_UI = 1,
// this category groups those events which are generated directly from the
// user through input devices like mouse and keyboard and usually result in
// data to be processed from the application.
// (e.g. mouse clicks, key presses, etc)
wxEVT_CATEGORY_USER_INPUT = 2,
// this category is for wxSocketEvent
wxEVT_CATEGORY_SOCKET = 4,
// this category is for wxTimerEvent
wxEVT_CATEGORY_TIMER = 8,
// this category is for any event used to send notifications from the
// secondary threads to the main one or in general for notifications among
// different threads (which may or may not be user-generated)
wxEVT_CATEGORY_THREAD = 16,
// implementation only
// used in the implementations of DoYield()
wxEVT_CATEGORY_UNKNOWN = 32,
// a special category used as an argument to wxApp::Yield() to indicate that
// Yield() should leave all wxEvents on the queue while emptying the native event queue
// (native events will be processed but the wxEvents they generate will be queued)
wxEVT_CATEGORY_CLIPBOARD = 64,
// shortcut masks
// this category groups those events which are emitted in response to
// events of the native toolkit and which typically are not-"delayable".
wxEVT_CATEGORY_NATIVE_EVENTS = wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT,
// used in wxApp::Yield to specify all event categories should be processed:
wxEVT_CATEGORY_ALL =
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
wxEVT_CATEGORY_TIMER|wxEVT_CATEGORY_THREAD
};
/*
* wxWidgets events, covering all interesting things that might happen
* (button clicking, resizing, setting text in widgets, etc.).
@@ -748,10 +808,13 @@ public:
void SetEventType(wxEventType typ) { m_eventType = typ; }
wxEventType GetEventType() const { return m_eventType; }
wxObject *GetEventObject() const { return m_eventObject; }
void SetEventObject(wxObject *obj) { m_eventObject = obj; }
long GetTimestamp() const { return m_timeStamp; }
void SetTimestamp(long ts = 0) { m_timeStamp = ts; }
int GetId() const { return m_id; }
void SetId(int Id) { m_id = Id; }
@@ -767,6 +830,12 @@ public:
// for them wouldn't work (it needs to do a copy of the event)
virtual wxEvent *Clone() const = 0;
// this function is used to selectively process events in wxApp::YieldFor
// NOTE: by default it returns wxEVT_CATEGORY_UI just because the major
// part of wxWidgets events belong to that category.
virtual wxEventCategory GetEventCategory() const
{ return wxEVT_CATEGORY_UI; }
// Implementation only: this test is explicitly anti OO and this function
// exists only for optimization purposes.
bool IsCommandEvent() const { return m_isCommandEvent; }
@@ -818,9 +887,6 @@ public:
protected:
// the propagation level: while it is positive, we propagate the event to
// the parent window (if any)
//
// this one doesn't have to be public, we don't have to worry about
// backwards compatibility as it is new
int m_propagationLevel;
bool m_skipped;
@@ -956,6 +1022,7 @@ public:
int GetInt() const { return m_commandInt; }
virtual wxEvent *Clone() const { return new wxCommandEvent(*this); }
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; }
protected:
wxString m_cmdString; // String event argument
@@ -999,6 +1066,36 @@ private:
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxNotifyEvent)
};
// Thread event
class WXDLLIMPEXP_BASE wxThreadEvent : public wxCommandEvent
{
public:
wxThreadEvent(int id = wxID_ANY)
: wxCommandEvent(wxEVT_COMMAND_THREAD, id)
{ }
virtual wxEvent *Clone() const
{
// make sure our string member (which uses COW aka refcounting) is not
// shared by other string instances:
const_cast<wxThreadEvent*>(this)->SetString(GetString().c_str());
return new wxThreadEvent(*this);
}
// this is important to avoid that calling wxApp::Yield() thread events
// gets processed when this is unwanted:
virtual wxEventCategory GetEventCategory() const
{ return wxEVT_CATEGORY_THREAD; }
private:
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxThreadEvent)
};
// Scroll event class, derived form wxCommandEvent. wxScrollEvents are
// sent by wxSlider and wxScrollBar.
/*
@@ -1067,6 +1164,8 @@ private:
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxScrollWinEvent)
};
// Mouse event class
/*
@@ -1247,6 +1346,7 @@ public:
bool IsPageScroll() const { return ((unsigned int)m_linesPerAction == UINT_MAX); }
virtual wxEvent *Clone() const { return new wxMouseEvent(*this); }
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; }
wxMouseEvent& operator=(const wxMouseEvent& event)
{
@@ -1370,6 +1470,7 @@ public:
wxCoord GetY() const { return m_y; }
virtual wxEvent *Clone() const { return new wxKeyEvent(*this); }
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; }
// we do need to copy wxKeyEvent sometimes (in wxTreeCtrl code, for
// example)
@@ -2537,6 +2638,7 @@ private:
*/
// ============================================================================
// event handler and related classes
// ============================================================================
@@ -3217,6 +3319,8 @@ private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler)
};
WX_DEFINE_EXPORTED_ARRAY_PTR(wxEvtHandler*, wxEvtHandlerArray);
// ----------------------------------------------------------------------------
// wxEventConnectionRef represents all connections between two event handlers
// and enables automatic disconnect when an event handler sink goes out of
@@ -3322,6 +3426,7 @@ protected:
};
typedef void (wxEvtHandler::*wxCommandEventFunction)(wxCommandEvent&);
typedef void (wxEvtHandler::*wxThreadEventFunction)(wxThreadEvent&);
typedef void (wxEvtHandler::*wxScrollEventFunction)(wxScrollEvent&);
typedef void (wxEvtHandler::*wxScrollWinEventFunction)(wxScrollWinEvent&);
typedef void (wxEvtHandler::*wxSizeEventFunction)(wxSizeEvent&);
@@ -3361,6 +3466,8 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
#define wxCommandEventHandler(func) \
wxEVENT_HANDLER_CAST(wxCommandEventFunction, func)
#define wxThreadEventHandler(func) \
wxEVENT_HANDLER_CAST(wxThreadEventFunction, func)
#define wxScrollEventHandler(func) \
wxEVENT_HANDLER_CAST(wxScrollEventFunction, func)
#define wxScrollWinEventHandler(func) \
@@ -3840,6 +3947,9 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
#define EVT_TEXT_COPY(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_COPY, winid, wxClipboardTextEventHandler(func))
#define EVT_TEXT_PASTE(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_PASTE, winid, wxClipboardTextEventHandler(func))
// Thread events
#define EVT_THREAD(id, func) wx__DECLARE_EVT1(wxEVT_COMMAND_THREAD, id, wxThreadEventHandler(func))
// ----------------------------------------------------------------------------
// Global data
// ----------------------------------------------------------------------------
@@ -3848,10 +3958,16 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
//
// notice that each event handler should occur at most once in this list
extern WXDLLIMPEXP_BASE wxList *wxHandlersWithPendingEvents;
extern WXDLLIMPEXP_BASE wxList *wxHandlersWithPendingDelayedEvents;
#if wxUSE_THREADS
// this critical section protectes both the lists above
extern WXDLLIMPEXP_BASE wxCriticalSection *wxHandlersWithPendingEventsLocker;
#endif
// old list names:
#define wxPendingEvents wxHandlersWithPendingEvents
#define wxPendingEventsLocker wxHandlersWithPendingEventsLocker
// ----------------------------------------------------------------------------
// Helper functions
// ----------------------------------------------------------------------------

View File

@@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/gtk/app.h
// Purpose:
// Purpose: wxApp definition for wxGTK
// Author: Robert Roebling
// Id: $Id$
// Copyright: (c) 1998 Robert Roebling, Julian Smart
@@ -40,7 +40,6 @@ public:
virtual bool OnInitGui();
// override base class (pure) virtuals
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool Initialize(int& argc, wxChar **argv);
@@ -79,6 +78,10 @@ public:
bool EventsPending();
bool DoIdle();
protected:
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
private:
// true if we're inside an assert modal dialog
#ifdef __WXDEBUG__

View File

@@ -38,7 +38,6 @@ public:
virtual bool OnInitGui();
// override base class (pure) virtuals
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool Initialize(int& argc, wxChar **argv);
@@ -71,6 +70,8 @@ private:
bool m_isInAssert;
#endif // __WXDEBUG__
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
DECLARE_DYNAMIC_CLASS(wxApp)
};

View File

@@ -1277,4 +1277,15 @@ public:
(list).clear(); \
}
// append all element of one list to another one
#define WX_APPEND_LIST(list, other) \
{ \
wxList::compatibility_iterator node = other->GetFirst(); \
while ( node ) \
{ \
(list)->push_back(node->GetData()); \
node = node->GetNext(); \
} \
}
#endif // _WX_LISTH__

View File

@@ -44,7 +44,6 @@ public:
virtual void Exit();
virtual void WakeUpIdle();
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual wxVideoMode GetDisplayMode() const { return m_displayMode; }
virtual bool SetDisplayMode(const wxVideoMode& mode);
@@ -52,6 +51,8 @@ public:
private:
DECLARE_DYNAMIC_CLASS(wxApp)
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
wxVideoMode m_displayMode;
};

View File

@@ -53,7 +53,6 @@ public:
virtual void Exit();
virtual bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle(); // implemented in motif/evtloop.cpp
// implementation from now on
@@ -66,6 +65,7 @@ public:
// Implementation
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
// Motif-specific
WXAppContext GetAppContext() const { return m_appContext; }

View File

@@ -33,7 +33,6 @@ public:
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
virtual bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle();
virtual void SetPrintMode(int mode) { m_printMode = mode; }
@@ -79,6 +78,8 @@ public:
protected:
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
public:
// unregister any window classes registered by GetRegisteredClassName()
static void UnregisterWindowClasses();

View File

@@ -75,7 +75,6 @@ public:
virtual bool OnInitGui(void);
virtual bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle(void);
virtual void SetPrintMode(int mode) { m_nPrintMode = mode; }
@@ -111,6 +110,8 @@ public:
// Implementation
static bool RegisterWindowClasses(HAB vHab);
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
public:
int m_nCmdShow;
HMQ m_hMq;

View File

@@ -38,7 +38,6 @@ class WXDLLIMPEXP_CORE wxApp: public wxAppBase
wxApp();
virtual ~wxApp() {}
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual void SetPrintMode(int mode) { m_printMode = mode; }
@@ -67,6 +66,7 @@ public:
// Implementation
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
// the installed application event handler
WXEVENTHANDLERREF MacGetEventHandler() { return m_macEventHandler ; }

View File

@@ -35,7 +35,6 @@ public:
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
virtual bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle();
virtual void SetPrintMode(int mode) { m_printMode = mode; }
@@ -52,6 +51,8 @@ public:
protected:
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
public:
// Implementation
static bool RegisterWindowClasses();

View File

@@ -382,6 +382,7 @@ public:
void *GetClientData() const { return m_clientData; }
virtual wxEvent *Clone() const { return new wxSocketEvent(*this); }
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_SOCKET; }
public:
wxSocketNotify m_event;

View File

@@ -172,6 +172,7 @@ public:
// implement the base class pure virtual
virtual wxEvent *Clone() const { return new wxTimerEvent(*this); }
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; }
private:
wxTimer* m_timer;

View File

@@ -45,7 +45,6 @@ public:
virtual void Exit();
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool OnInitGui();
@@ -64,6 +63,7 @@ public:
// Implementation
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
WXWindow GetTopLevelWidget() const { return m_topLevelWidget; }
WXColormap GetMainColormap(WXDisplay* display);

View File

@@ -162,7 +162,26 @@ public:
@a onlyIfNeeded parameter is @true, the method will just silently
return @false instead.
*/
virtual bool Yield(bool onlyIfNeeded = false);
bool Yield(bool onlyIfNeeded = false);
/**
Works like Yield() with @e onlyIfNeeded == @true, except that it allows
the caller to specify a mask of the ::wxEventCategory values which
indicates which events should be processed and which should instead
be "delayed" (i.e. processed by the main loop later).
Note that this is a safer alternative to Yield() since it ensures that
only the events you're interested to are processed; i.e. helps to avoid
unwanted reentrancies.
*/
bool YieldFor(long eventsToProcess);
/**
Returns @true if the given event category is allowed inside
a YieldFor() call (i.e. compares the given category against the
last mask passed to YieldFor()).
*/
virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const;
//@}
@@ -180,7 +199,7 @@ public:
/**
Returns the one and only global application object.
Usually wxTheApp is used instead.
Usually ::wxTheApp is used instead.
@see SetInstance()
*/
@@ -621,6 +640,25 @@ public:
*/
virtual bool IsActive() const;
/**
This function is similar to wxYield(), except that it disables the user
input to all program windows before calling wxAppConsole::Yield and re-enables it
again afterwards. If @a win is not @NULL, this window will remain enabled,
allowing the implementation of some limited user interaction.
Returns the result of the call to wxAppConsole::Yield.
@see wxSafeYield
*/
virtual bool SafeYield(wxWindow *win, bool onlyIfNeeded);
/**
Works like SafeYield() with @e onlyIfNeeded == @true except that
it allows the caller to specify a mask of events to be processed.
See wxAppConsole::YieldFor for more info.
*/
virtual bool SafeYieldFor(wxWindow *win, long eventsToProcess);
/**
Windows-only function for processing a message. This function is called
from the main message loop, checking for windows that may wish to process it.
@@ -857,22 +895,18 @@ void wxUninitialize();
void wxWakeUpIdle();
/**
Calls wxApp::Yield.
Calls wxAppConsole::Yield.
@deprecated
This function is kept only for backwards compatibility. Please use
the wxApp::Yield method instead in any new code.
the wxAppConsole::Yield method instead in any new code.
@header{wx/app.h}
*/
bool wxYield();
/**
This function is similar to wxYield(), except that it disables the user
input to all program windows before calling wxYield() and re-enables it
again afterwards. If @a win is not @NULL, this window will remain enabled,
allowing the implementation of some limited user interaction.
Returns the result of the call to ::wxYield.
Calls wxApp::SafeYield.
@header{wx/app.h}
*/

View File

@@ -7,6 +7,64 @@
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
/**
The predefined constants for the number of times we propagate event
upwards window child-parent chain.
*/
enum wxEventPropagation
{
/// don't propagate it at all
wxEVENT_PROPAGATE_NONE = 0,
/// propagate it until it is processed
wxEVENT_PROPAGATE_MAX = INT_MAX
};
/**
The different categories for a wxEvent; see wxEvent::GetEventCategory.
@note They are used as OR-combinable flags by wxApp::Yield.
*/
enum wxEventCategory
{
/**
This is the category for those events which are generated to update
the appearance of the GUI but which (usually) do not comport data
processing, i.e. which do not provide input or output data
(e.g. size events, scroll events, etc).
They are events NOT directly generated by the user's input devices.
*/
wxEVT_CATEGORY_UI = 1,
/**
This category groups those events which are generated directly from the
user through input devices like mouse and keyboard and usually result in
data to be processed from the application
(e.g. mouse clicks, key presses, etc).
*/
wxEVT_CATEGORY_USER_INPUT = 2,
/// This category is for wxSocketEvent
wxEVT_CATEGORY_SOCKET = 4,
/// This category is for wxTimerEvent
wxEVT_CATEGORY_TIMER = 8,
/**
This category is for any event used to send notifications from the
secondary threads to the main one or in general for notifications among
different threads (which may or may not be user-generated).
*/
wxEVT_CATEGORY_THREAD = 16,
/**
This mask is used in wxApp::Yield to specify that all event categories should
be processed.
*/
wxEVT_CATEGORY_ALL =
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
wxEVT_CATEGORY_TIMER|wxEVT_CATEGORY_THREAD
};
/**
@class wxEvent
@@ -87,6 +145,13 @@ public:
*/
wxEventType GetEventType() const;
/**
Returns a generic category for this event.
This function is used to selectively process events in wxApp::Yield.
*/
virtual wxEventCategory GetEventCategory() const;
/**
Returns the identifier associated with this event, such as a button command id.
*/
@@ -2463,18 +2528,45 @@ public:
};
/**
@class wxThreadEvent
This class adds some simple functionalities to wxCommandEvent coinceived
for inter-threads communications.
enum wxHelpEventOrigin
@library{wxcore}
@category{events}
@see @ref overview_thread, wxApp::YieldFor
*/
class wxThreadEvent : public wxCommandEvent
{
wxHE_ORIGIN_UNKNOWN = -1,
wxHE_ORIGIN_KEYBOARD,
public:
/**
Constructor.
/** event generated by wxContextHelp or from the [?] button on
the title bar (Windows). */
wxHE_ORIGIN_HELPBUTTON
Initializes the event type to @c wxEVT_THREAD (but you can change it
using wxEvent::SetEventType.
*/
wxThreadEvent(int id = wxID_ANY);
/**
Clones this event making sure that all internal members which use
COW (only @c m_commandString for now; see @ref overview_refcount)
are unshared (see wxObject::UnShare).
*/
virtual wxEvent *Clone() const;
/**
Returns @c wxEVT_CATEGORY_THREAD.
This is important to avoid that calling wxApp::Yield() thread events
gets processed when this is unwanted:
*/
virtual wxEventCategory GetEventCategory() const;
};
/**
@class wxHelpEvent

View File

@@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////
// Name: clipboard.cpp
// Purpose: clipbaord wxWidgets sample
// Purpose: clipboard wxWidgets sample
// Author: Robert Roebling
// RCS-ID: $Id: minimal.cpp 53461 2008-05-05 23:30:33Z VZ $
// Copyright: (c) Robert Roebling
@@ -27,7 +27,7 @@
#endif
#define USE_ASYNCHRONOUS_CLIPBOARD_REQUEST 1
#define USE_ASYNCHRONOUS_CLIPBOARD_REQUEST 0
class MyApp : public wxApp
{
@@ -198,6 +198,7 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
wxMessageBox("Clipboard sample", "About clipboard", wxOK|wxICON_INFORMATION, this);
}

View File

@@ -105,7 +105,7 @@ private:
void OnResumeThread(wxCommandEvent& event);
void OnStartWorker(wxCommandEvent& event);
void OnWorkerEvent(wxCommandEvent& event);
void OnWorkerEvent(wxThreadEvent& event);
void OnUpdateWorker(wxUpdateUIEvent& event);
void OnExecMain(wxCommandEvent& event);
@@ -169,7 +169,7 @@ enum
THREAD_SHOWCPUS,
WORKER_EVENT // this one gets sent from the worker thread
WORKER_EVENT = wxID_HIGHEST+1 // this one gets sent from the worker thread
};
// ----------------------------------------------------------------------------
@@ -292,8 +292,22 @@ void MyWorkerThread::OnExit()
{
}
#define TEST_YIELD_RACE_CONDITION 1
void *MyWorkerThread::Entry()
{
#if TEST_YIELD_RACE_CONDITION
if ( TestDestroy() )
return NULL;
wxThreadEvent event( WORKER_EVENT );
event.SetInt( 50 );
wxQueueEvent( m_frame, new wxThreadEvent(event) );
event.SetInt(-1);
wxQueueEvent( m_frame, new wxThreadEvent(event) );
#else
for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ )
{
// check if we were asked to exit
@@ -301,18 +315,19 @@ void *MyWorkerThread::Entry()
break;
// create any type of command event here
wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
wxThreadEvent event( WORKER_EVENT );
event.SetInt( m_count );
// send in a thread-safe way
wxQueueEvent( m_frame, new wxCommandEvent(event) );
wxQueueEvent( m_frame, new wxThreadEvent(event) );
wxMilliSleep(200);
}
wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
wxThreadEvent event( WORKER_EVENT );
event.SetInt(-1); // that's all
wxQueueEvent( m_frame, new wxCommandEvent(event) );
wxQueueEvent( m_frame, new wxThreadEvent(event) );
#endif
return NULL;
}
@@ -360,7 +375,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_UPDATE_UI(THREAD_START_WORKER, MyFrame::OnUpdateWorker)
EVT_MENU(THREAD_START_WORKER, MyFrame::OnStartWorker)
EVT_MENU(WORKER_EVENT, MyFrame::OnWorkerEvent)
EVT_THREAD(WORKER_EVENT, MyFrame::OnWorkerEvent)
EVT_IDLE(MyFrame::OnIdle)
END_EVENT_TABLE()
@@ -442,7 +458,6 @@ MyFrame::MyFrame(wxFrame *frame, const wxString& title,
m_txtctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxPoint(0, 0), wxSize(0, 0),
wxTE_MULTILINE | wxTE_READONLY);
}
MyFrame::~MyFrame()
@@ -758,7 +773,7 @@ void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
thread->Run();
}
void MyFrame::OnWorkerEvent(wxCommandEvent& event)
void MyFrame::OnWorkerEvent(wxThreadEvent& event)
{
int n = event.GetInt();
if ( n == -1 )

View File

@@ -295,7 +295,7 @@ void wxApp::Exit()
}
// Yield to other processes
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
@@ -314,10 +314,13 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// Run the event loop until it is out of events
while(1)
{
// TODO: implement event filtering using the eventsToProcess mask
wxAutoNSAutoreleasePool pool;
/* NOTE: It may be better to use something like
NSEventTrackingRunLoopMode since we don't necessarily want all

View File

@@ -164,6 +164,7 @@ bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **argv)
#if wxUSE_THREADS
wxHandlersWithPendingEventsLocker = new wxCriticalSection;
wxHandlersWithPendingDelayedEvents = new wxList;
#endif
#ifndef __WXPALMOS__
@@ -193,6 +194,9 @@ void wxAppConsoleBase::CleanUp()
delete wxHandlersWithPendingEvents;
wxHandlersWithPendingEvents = NULL;
delete wxHandlersWithPendingDelayedEvents;
wxHandlersWithPendingDelayedEvents = NULL;
#if wxUSE_THREADS
delete wxHandlersWithPendingEventsLocker;
wxHandlersWithPendingEventsLocker = NULL;
@@ -336,6 +340,16 @@ bool wxAppConsoleBase::HasPendingEvents() const
return has;
}
void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
{
wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
}
void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
{
wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
}
/* static */
bool wxAppConsoleBase::IsMainLoopRunning()
{
@@ -353,6 +367,9 @@ void wxAppConsoleBase::ProcessPendingEvents()
wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
wxCHECK_RET( wxHandlersWithPendingDelayedEvents->IsEmpty(),
"this helper list should be empty" );
if (wxHandlersWithPendingEvents)
{
// iterate until the list becomes empty: the handlers remove themselves
@@ -360,7 +377,7 @@ void wxAppConsoleBase::ProcessPendingEvents()
wxList::compatibility_iterator node = wxHandlersWithPendingEvents->GetFirst();
while (node)
{
// In ProcessPendingEvents(), new handlers might be add
// In ProcessPendingEvents(), new handlers might be added
// and we can safely leave the critical section here.
wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
@@ -374,6 +391,20 @@ void wxAppConsoleBase::ProcessPendingEvents()
}
}
// now the wxHandlersWithPendingEvents is surely empty; however some event
// handlers may have moved themselves into wxHandlersWithPendingDelayedEvents
// because of a selective wxYield call in progress.
// Now we need to move them back to wxHandlersWithPendingEvents so the next
// call to this function has the chance of processing them:
if (!wxHandlersWithPendingDelayedEvents->IsEmpty())
{
if (!wxHandlersWithPendingEvents)
wxHandlersWithPendingEvents = new wxList;
WX_APPEND_LIST(wxHandlersWithPendingEvents, wxHandlersWithPendingDelayedEvents);
wxHandlersWithPendingDelayedEvents->Clear();
}
wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
}

View File

@@ -79,6 +79,7 @@ wxAppBase::wxAppBase()
m_isActive = true;
m_isInsideYield = false;
m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
// We don't want to exit the app if the user code shows a dialog from its
// OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
@@ -325,6 +326,26 @@ void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
(void)ProcessEvent(event);
}
bool wxAppBase::IsEventAllowedInsideYield(wxEventCategory cat) const
{
return m_eventsToProcessInsideYield & cat;
}
bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
{
wxWindowDisabler wd(win);
return Yield(onlyIfNeeded);
}
bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
{
wxWindowDisabler wd(win);
return YieldFor(eventsToProcess);
}
// ----------------------------------------------------------------------------
// idle handling
// ----------------------------------------------------------------------------

View File

@@ -65,6 +65,7 @@
#if wxUSE_GUI
IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxThreadEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent)
@@ -147,6 +148,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule)
// List containing event handlers with pending events (each handler can occur
// at most once here)
wxList *wxHandlersWithPendingEvents = NULL;
wxList *wxHandlersWithPendingDelayedEvents = NULL;
#if wxUSE_THREADS
// protects wxHandlersWithPendingEvents list
@@ -316,6 +318,9 @@ wxDEFINE_EVENT( wxEVT_COMMAND_ENTER, wxCommandEvent )
wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent )
wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent )
// Thread event
DEFINE_EVENT_TYPE(wxEVT_COMMAND_THREAD)
#endif // wxUSE_GUI
#if wxUSE_BASE
@@ -350,9 +355,8 @@ wxEventFunctor::~wxEventFunctor()
// ----------------------------------------------------------------------------
/*
* General wxWidgets events, covering
* all interesting things that might happen (button clicking, resizing,
* setting text in widgets, etc.).
* General wxWidgets events, covering all interesting things that might happen
* (button clicking, resizing, setting text in widgets, etc.).
*
* For each completely new event type, derive a new event class.
*
@@ -1103,6 +1107,14 @@ wxEvtHandler::~wxEvtHandler()
}
//else: we weren't in this list at all, it's ok
if ( wxHandlersWithPendingDelayedEvents->DeleteObject(this) )
{
// check that we were present only once in the list
wxASSERT_MSG( !wxHandlersWithPendingDelayedEvents->Find(this),
"Handler occurs twice in wxHandlersWithPendingDelayedEvents list" );
}
//else: we weren't in this list at all, it's ok
#if wxUSE_THREADS
if (wxHandlersWithPendingEventsLocker)
wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
@@ -1188,6 +1200,10 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
void wxEvtHandler::ProcessPendingEvents()
{
// we need to process only a single pending event in this call because
// each call to ProcessEvent() could result in the destruction of this
// same event handler (see the comment at the end of this function)
wxENTER_CRIT_SECT( m_pendingEventsLock );
// this method is only called by wxApp if this handler does have
@@ -1196,7 +1212,40 @@ void wxEvtHandler::ProcessPendingEvents()
"should have pending events if called" );
wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
wxEventPtr event(static_cast<wxEvent *>(node->GetData()));
wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
// find the first event which can be processed now:
if (wxTheApp && wxTheApp->IsYielding())
{
while (node && pEvent && !wxTheApp->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
{
node = node->GetNext();
pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
}
if (!node)
{
// all our events are NOT processable now... signal this:
#if wxUSE_THREADS
if (wxHandlersWithPendingEventsLocker)
wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
#endif
// move us from the list of handlers with processable pending events
// to the list of handlers with pending events which needs to be processed later
wxHandlersWithPendingEvents->DeleteObject(this);
if ( !wxHandlersWithPendingDelayedEvents->Find(this) )
wxHandlersWithPendingDelayedEvents->Append(this);
#if wxUSE_THREADS
if (wxHandlersWithPendingEventsLocker)
wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
#endif
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
return;
}
}
wxEventPtr event(pEvent);
// it's important we remove event from list before processing it, else a
// nested event loop, for example from a modal dialog, might process the
@@ -1306,6 +1355,27 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event)
{
if ( wxTheApp )
{
/*
CANNOT ENABLE: ProcessEvent() must always immediately process the event!
if (wxTheApp->IsYielding() &&
!wxTheApp->IsEventAllowedInsideYield(event.GetEventCategory()))
{
wxEvent* queuedEv = event.Clone();
// queue this event rather than processing it now
QueueEvent(queuedEv);
// the wxWakeUpIdle call shouldn't probably be done
// in this context (there's wxYield in the call stack)
return true;
// it's not completely true that the event was processed;
// but we cannot even say it was skipped or discarded...
}
//else: either we're not inside a wxYield() call or if we are,
// we can process this event immediately.
*/
int rc = wxTheApp->FilterEvent(event);
if ( rc != -1 )
{

View File

@@ -63,6 +63,7 @@ public:
wxDummyConsoleApp() { }
virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; }
virtual bool DoYield(bool, long) { return true; }
DECLARE_NO_COPY_CLASS(wxDummyConsoleApp)
};

View File

@@ -163,8 +163,7 @@ void wxApp::WakeUpIdle()
#endif
}
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
#if wxUSE_THREADS
if ( !wxThread::IsMain() )
@@ -182,6 +181,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
wxLog::Suspend();

View File

@@ -204,6 +204,8 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
void wxGUIEventLoop::Yield()
{
// TODO: implement event filtering using the eventsToProcess mask
// process all pending events:
while ( Pending() )
Dispatch();

View File

@@ -401,7 +401,7 @@ wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip)
m_msg->SetLabel(_("Done."));
}
wxYieldIfNeeded();
wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
(void)ShowModal();
}
@@ -451,7 +451,7 @@ bool wxProgressDialog::DoAfterUpdate(bool *skip)
{
// we have to yield because not only we want to update the display but
// also to process the clicks on the cancel and skip buttons
wxYieldIfNeeded();
wxTheApp->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
Update();
@@ -670,7 +670,7 @@ void wxProgressDialog::UpdateMessage(const wxString &newmsg)
Fit(); // adapt to the new label size
wxYieldIfNeeded() ;
wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
}
}

View File

@@ -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
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(); // 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

View File

@@ -74,7 +74,7 @@ public:
~wxClipboardSync()
{
while (ms_clipboard)
gtk_main_iteration();
wxTheApp->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
}
// this method must be called by GTK+ callbacks to indicate that we got the
@@ -438,7 +438,7 @@ wxClipboard::wxClipboard()
g_signal_connect (m_targetsWidget, "selection_received",
G_CALLBACK (targets_selection_received), this);
// we use m_targetsWidgetAsync to query what formats asynchronously
// we use m_targetsWidgetAsync to query what formats are available asynchronously
m_targetsWidgetAsync = gtk_window_new( GTK_WINDOW_POPUP );
gtk_widget_realize( m_targetsWidgetAsync );

View File

@@ -103,7 +103,7 @@ static wxMutex gs_idleTagsMutex;
// wxYield
//-----------------------------------------------------------------------------
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
@@ -124,6 +124,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
#endif // wxUSE_THREADS
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// We need to remove idle callbacks or the loop will
// never finish.
@@ -135,6 +136,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Suspend();
#endif
// TODO: implement event filtering using the eventsToProcess mask
while (gtk_events_pending())
gtk_main_iteration();

View File

@@ -48,7 +48,7 @@ void wxApp::Exit()
// wxYield
//-----------------------------------------------------------------------------
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
@@ -69,12 +69,15 @@ bool wxApp::Yield(bool onlyIfNeeded)
#endif // wxUSE_THREADS
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
wxLog::Suspend();
wxEventLoopBase * const eventLoop = wxEventLoop::GetActive();
if ( eventLoop )
{
// TODO: implement event filtering using the eventsToProcess mask
while (eventLoop->Pending())
eventLoop->Dispatch();
}

View File

@@ -470,7 +470,7 @@ void wxApp::SetTopLevelRealizedWidget(WXDisplay* display, WXWidget widget)
// Yield to other processes
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
@@ -483,9 +483,11 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
wxEventLoopGuarantor dummyLoopIfNeeded;
while (wxTheApp && wxTheApp->Pending())
// TODO: implement event filtering using the eventsToProcess mask
wxTheApp->Dispatch();
m_isInsideYield = false;

View File

@@ -1015,7 +1015,14 @@ int wxApp::GetShell32Version()
// Yield to incoming messages
// ----------------------------------------------------------------------------
bool wxApp::Yield(bool onlyIfNeeded)
WX_DECLARE_OBJARRAY(MSG, wxMSGArray);
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(wxMSGArray);
static wxMSGArray g_arrMSG;
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
@@ -1029,8 +1036,9 @@ bool wxApp::Yield(bool onlyIfNeeded)
// set the flag and don't forget to reset it before returning
m_isInsideYield = true;
wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
m_eventsToProcessInsideYield = eventsToProcess;
wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
@@ -1041,7 +1049,6 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxON_BLOCK_EXIT0(wxLog::Resume);
#endif // wxUSE_LOG
// we don't want to process WM_QUIT from here - it should be processed in
// the main event loop in order to stop it
wxEventLoopGuarantor dummyLoopIfNeeded;
@@ -1053,13 +1060,105 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS
wxEventCategory cat;
switch (msg.message)
{
case WM_NCMOUSEMOVE:
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONUP:
case WM_NCLBUTTONDBLCLK:
case WM_NCRBUTTONDOWN:
case WM_NCRBUTTONUP:
case WM_NCRBUTTONDBLCLK:
case WM_NCMBUTTONDOWN:
case WM_NCMBUTTONUP:
case WM_NCMBUTTONDBLCLK:
case WM_KEYFIRST:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_KEYLAST:
case WM_HOTKEY:
case WM_IME_STARTCOMPOSITION:
case WM_IME_ENDCOMPOSITION:
case WM_IME_COMPOSITION:
case WM_IME_KEYLAST:
case WM_COMMAND:
case WM_SYSCOMMAND:
case WM_IME_SETCONTEXT:
case WM_IME_NOTIFY:
case WM_IME_CONTROL:
case WM_IME_COMPOSITIONFULL:
case WM_IME_SELECT:
case WM_IME_CHAR:
case WM_IME_KEYDOWN:
case WM_IME_KEYUP:
case WM_MOUSEHOVER:
case WM_NCMOUSELEAVE:
case WM_MOUSELEAVE:
case WM_CUT:
case WM_COPY:
case WM_PASTE:
case WM_CLEAR:
case WM_UNDO:
case WM_MOUSEFIRST:
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
case WM_MOUSELAST:
case WM_MOUSEWHEEL:
cat = wxEVT_CATEGORY_USER_INPUT;
case WM_TIMER:
cat = wxEVT_CATEGORY_TIMER;
default:
// there are too many of these types of messages to handle them in this switch
cat = wxEVT_CATEGORY_UI;
}
if (cat & eventsToProcess)
{
if ( !wxTheApp->Dispatch() )
break;
}
else
{
// remove the message and store it
PeekMessage(&msg, (HWND)0, 0, 0, PM_REMOVE)
g_arrMSG.Add(msg);
}
}
// if there are pending events, we must process them.
ProcessPendingEvents();
// put back unprocessed events in the queue
DWORD id = GetCurrentThreadId();
for (size_t i=0; i<g_arrMSG.GetCount(); i++)
{
PostThreadMessage(id, g_arrMSG[i].message, g_arrMSG[i].wParam, g_arrMSG[i].lParam);
}
g_arrMSG.Clear();
return true;
}

View File

@@ -360,6 +360,11 @@ void wxGUIEventLoop::WakeUp()
#else // !wxUSE_GUI
// ============================================================================
// wxConsoleEventLoop implementation
// ============================================================================
#if wxUSE_CONSOLE_EVENTLOOP
void wxConsoleEventLoop::WakeUp()

View File

@@ -507,7 +507,7 @@ void wxApp::OnQueryEndSession( wxCloseEvent& rEvent )
//
// Yield to incoming messages
//
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
@@ -529,6 +529,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Suspend();
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
//
// We want to go back to the main message loop
@@ -537,6 +538,8 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxEventLoopGuarantor dummyLoopIfNeeded;
while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
{
// TODO: implement event filtering using the eventsToProcess mask
#if wxUSE_THREADS
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS

View File

@@ -1119,7 +1119,7 @@ void wxCYield()
// Yield to other processes
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
#if wxUSE_THREADS
// Yielding from a non-gui thread needs to bail out, otherwise we end up
@@ -1141,6 +1141,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't

View File

@@ -287,7 +287,7 @@ int wxApp::GetComCtl32Version()
// Yield to incoming messages
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
return true;
}

View File

@@ -769,7 +769,7 @@ void wxApp::Exit()
// Yield to other processes
bool wxApp::Yield(bool onlyIfNeeded)
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
// Sometimes only 2 yields seem
// to do the trick, e.g. in the
@@ -788,6 +788,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// Make sure we have an event loop object,
// or Pending/Dispatch will fail
@@ -797,6 +798,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
// can be tested
wxTheApp->Dispatch();
// TODO: implement event filtering using the eventsToProcess mask
while (wxTheApp && wxTheApp->Pending())
wxTheApp->Dispatch();