- wxDos2UnixFilename, wxUnix2DosFilename, wxStripExtension, wxGetTempFileName,
wxExpandPath, wxContractPath, wxRealPath, wxCopyAbsolutePath, wxSplitPath
were deprecated in favour of wxFileName methods. See docs for more info.
+- global wxPendingEvents and wxPendingEventsLocker objects were removed; now you may use
+ wxEventLoopBase::SuspendProcessingOfPendingEvents instead of locking wxPendingEventsLocker.
Major new features in this release
----------------------------------
- Added wxIMAGE_OPTION_PNG_FILTER and many wxIMAGE_OPTION_PNG_COMPRESSION_* options
to wxImage and wxPNGHandler to allow for custom compression levels when saving PNGs
- Added GetValue(), GetRange(), GetMessage() functions to wxProgressDialog
+- Moved yield functions to wxEventLoopBase and implemented for wxMSW and wxGTK
+ a selective wxEventLoopBase::YieldFor() function.
+ Added also wxEventLoopBase::IsYielding to help cure re-entrancy problems with Yield().
wxGTK:
// had been already processed or won't be processed at all, respectively
virtual int FilterEvent(wxEvent& event);
+ // return true if we're running event loop, i.e. if the events can
+ // (already) be dispatched
+ static bool IsMainLoopRunning();
+
#if wxUSE_EXCEPTIONS
// execute the functor to handle the given event
//
// exit, if you need to really handle the exceptions you need to override
// OnExceptionInMainLoop()
virtual void OnUnhandledException();
+
+ // Function called if an uncaught exception is caught inside the main
+ // event loop: it may return true to continue running the event loop or
+ // false to stop it (in the latter case it may rethrow the exception as
+ // well)
+ virtual bool OnExceptionInMainLoop();
+
#endif // wxUSE_EXCEPTIONS
- // event processing functions
- // --------------------------
- // return true if we're running event loop, i.e. if the events can
- // (already) be dispatched
- static bool IsMainLoopRunning();
+ // wxEventLoop redirections
+ // ------------------------
- // 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
- // also called directly.
virtual void ProcessPendingEvents();
-
- // check if there are pending events on global pending event list
bool HasPendingEvents() const;
- // make sure that idle events are sent again
- virtual void WakeUpIdle();
+ virtual bool Pending();
+ virtual bool Dispatch();
- // execute the main GUI loop, the function returns when the loop ends
virtual int MainLoop();
-
- // exit the main GUI loop during the next iteration (i.e. it does not
- // stop the program immediately!)
virtual void ExitMainLoop();
- // returns true if there are unprocessed events in the event queue
- virtual bool Pending();
+ bool Yield(bool onlyIfNeeded = false);
- // process the first event in the event queue (blocks until an event
- // appears if there are none currently, use Pending() if this is not
- // wanted), returns false if the event loop should stop and true
- // otherwise
- virtual bool Dispatch();
-
- // this virtual function is called when the application
- // becomes idle and normally just sends wxIdleEvent to all interested
- // parties
- //
- // it should return true if more idle events are needed, false if not
+ virtual void WakeUpIdle();
virtual bool ProcessIdle();
-#if wxUSE_EXCEPTIONS
- // Function called if an uncaught exception is caught inside the main
- // event loop: it may return true to continue running the event loop or
- // false to stop it (in the latter case it may rethrow the exception as
- // well)
- 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
// -----------------
// 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;
// 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_FWD_BASE wxEvtHandler;
// the application object is a singleton anyhow, there is no sense in
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
- 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
// does any of our windows have focus?
bool m_isActive;
- // Yield() helpers:
- bool m_isInsideYield;
- long m_eventsToProcessInsideYield;
-
wxDECLARE_NO_COPY_CLASS(wxAppBase);
};
// Implement wxAppBase pure virtuals
virtual void Exit();
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
virtual void WakeUpIdle();
virtual bool Initialize(int& argc, wxChar **argv);
virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp() { }
+ virtual bool YieldFor(long eventsToProcess);
protected:
int m_exitcode;
private:
wxVideoMode m_videoMode;
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
DECLARE_DYNAMIC_CLASS(wxApp)
};
public:
wxGUIEventLoop();
+ virtual bool YieldFor(long eventsToProcess);
+
// returns DirectFB event buffer used by wx
static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();
private:
- // wxYield implementation: iterate the loop as long as there are any
- // pending events
- void Yield();
-
static void InitBuffer();
static void CleanUp();
};
// The different categories for a wxEvent; see wxEvent::GetEventCategory.
-// NOTE: they are used as OR-combinable flags by wxApp::Yield
+// NOTE: they are used as OR-combinable flags by wxEventLoopBase::YieldFor
enum wxEventCategory
{
// this is the category for those events which are generated to update
// implementation only
- // used in the implementations of DoYield()
+ // used in the implementations of wxEventLoopBase::YieldFor
wxEVT_CATEGORY_UNKNOWN = 32,
- // a special category used as an argument to wxApp::Yield() to indicate that
+ // a special category used as an argument to wxEventLoopBase::YieldFor 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,
// 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:
+ // used in wxEventLoopBase::YieldFor 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
// 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
+ // this function is used to selectively process events in wxEventLoopBase::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 ev;
}
- // this is important to avoid that calling wxApp::Yield() thread events
+ // this is important to avoid that calling wxEventLoopBase::YieldFor thread events
// gets processed when this is unwanted:
virtual wxEventCategory GetEventCategory() const
{ return wxEVT_CATEGORY_THREAD; }
// Thread events
#define EVT_THREAD(id, func) wx__DECLARE_EVT1(wxEVT_COMMAND_THREAD, id, wxThreadEventHandler(func))
-// ----------------------------------------------------------------------------
-// Global data
-// ----------------------------------------------------------------------------
-
-// list containing event handlers with pending events for them
-//
-// 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
// ----------------------------------------------------------------------------
#include "wx/utils.h"
+
+/*
+ NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
+ ------------------------------------------
+
+ The YieldFor() function helps to avoid re-entrancy problems and problems
+ caused by out-of-order event processing
+ (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
+
+ The logic behind YieldFor() is simple: it analyzes the queue of the native
+ events generated by the underlying GUI toolkit and picks out and processes
+ only those matching the given mask.
+
+ It's important to note that YieldFor() is used to selectively process the
+ events generated by the NATIVE toolkit.
+ Events syntethized by wxWidgets code or by user code are instead selectively
+ processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
+ In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
+ YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
+ if the pending events for that event handler can be processed.
+ If all the pending events associated with that event handler result as "not processable",
+ the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
+ (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
+ Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
+ event handlers back into the list of handlers with pending events
+ (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
+ a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
+ will process all pending events as usual.
+*/
+
// ----------------------------------------------------------------------------
// wxEventLoopBase: interface for wxEventLoop
// ----------------------------------------------------------------------------
{
public:
// trivial, but needed (because of wxEventLoopBase) ctor
- wxEventLoopBase() { }
+ wxEventLoopBase();
// dtor
virtual ~wxEventLoopBase() { }
virtual bool IsOk() const { return true; }
+ // dispatch&processing
+ // -------------------
+
// start the event loop, return the exit code when it is finished
virtual int Run() = 0;
+ // is this event loop running now?
+ //
+ // notice that even if this event loop hasn't terminated yet but has just
+ // spawned a nested (e.g. modal) event loop, this would return false
+ bool IsRunning() const;
+
// exit from the loop with the given exit code
virtual void Exit(int rc = 0) = 0;
// exit the loop or -1 if timeout expired
virtual int DispatchTimeout(unsigned long timeout) = 0;
+ // implement this to wake up the loop: usually done by posting a dummy event
+ // to it (can be called from non main thread)
+ virtual void WakeUp() = 0;
+
+
+ // pending events
+ // --------------
+
+ // 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
+ // also called directly.
+ virtual void ProcessPendingEvents();
+
+ // check if there are pending events on global pending event list
+ bool HasPendingEvents() const;
+
+ // temporary suspends processing of the pending events
+ void SuspendProcessingOfPendingEvents();
+
+ // resume processing of the pending events previously stopped because of a
+ // call to SuspendProcessingOfPendingEvents()
+ void ResumeProcessingOfPendingEvents();
+
+ // called by ~wxEvtHandler to (eventually) remove the handler from the list of
+ // the handlers with pending events
+ void RemovePendingEventHandler(wxEvtHandler* toRemove);
+
+ // adds an event handler to the list of the handlers with pending events
+ void AppendPendingEventHandler(wxEvtHandler* toAppend);
+
+ // moves the event handler from the list of the handlers with pending events
+ //to the list of the handlers with _delayed_ pending events
+ void DelayPendingEventHandler(wxEvtHandler* toDelay);
+
+
+ // idle handling
+ // -------------
+
+ // make sure that idle events are sent again
+ virtual void WakeUpIdle();
+
+ // this virtual function is called when the application
+ // becomes idle and normally just sends wxIdleEvent to all interested
+ // parties
+ //
+ // it should return true if more idle events are needed, false if not
+ virtual bool ProcessIdle();
+
+
+ // 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!
+ bool Yield(bool onlyIfNeeded = false);
+ virtual bool YieldFor(long eventsToProcess) = 0;
+
+ // returns true if the main thread is inside a Yield() call
+ 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
+ { return (m_eventsToProcessInsideYield & cat) != 0; }
+
+ // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
+
+
+ // active loop
+ // -----------
// return currently active (running) event loop, may be NULL
static wxEventLoopBase *GetActive() { return ms_activeLoop; }
// set currently active (running) event loop
static void SetActive(wxEventLoopBase* loop) { ms_activeLoop = loop; }
- // is this event loop running now?
- //
- // notice that even if this event loop hasn't terminated yet but has just
- // spawned a nested (e.g. modal) event loop, this would return false
- bool IsRunning() const;
-
- // implement this to wake up the loop: usually done by posting a dummy event
- // to it (can be called from non main thread)
- virtual void WakeUp() = 0;
protected:
// this function should be called before the event loop terminates, whether
// an exception thrown from inside the loop)
virtual void OnExit() { }
-
// the pointer to currently active loop
static wxEventLoopBase *ms_activeLoop;
+ // the array of the handlers with pending events which needs to be processed
+ // inside ProcessPendingEvents()
+ wxEvtHandlerArray m_handlersWithPendingEvents;
+
+ // helper array used by ProcessPendingEvents()
+ wxEvtHandlerArray m_handlersWithPendingDelayedEvents;
+
+#if wxUSE_THREADS
+ // this critical section protects both the lists above
+ wxCriticalSection m_handlersWithPendingEventsLocker;
+#endif
+
+ // Yield() helpers:
+ bool m_isInsideYield;
+ long m_eventsToProcessInsideYield;
+
wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
};
}
}
virtual void WakeUp() { }
+ virtual bool YieldFor(long eventsToProcess);
protected:
// the pointer to the port specific implementation class
bool EventsPending();
bool DoIdle();
-protected:
-
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
private:
// true if we're inside an assert modal dialog
#ifdef __WXDEBUG__
virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
+ virtual bool YieldFor(long eventsToProcess);
protected:
+
// the exit code of this event loop
int m_exitcode;
+ // used to temporarily store events in DoYield()
+ wxArrayPtrVoid m_arrGdkEvents;
+
wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
};
bool m_isInAssert;
#endif // __WXDEBUG__
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
DECLARE_DYNAMIC_CLASS(wxApp)
};
private:
DECLARE_DYNAMIC_CLASS(wxApp)
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
wxVideoMode m_displayMode;
};
// 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; }
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();
#if wxUSE_GUI
+WX_DECLARE_OBJARRAY(MSG, wxMSGArray);
+
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxMSWEventLoopBase
{
public:
virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
+ virtual bool YieldFor(long eventsToProcess);
protected:
virtual void OnNextIteration();
// non NULL)
static bool IsChildOfCriticalWindow(wxWindowMSW *win);
+ // array of messages used for temporary storage by YieldFor()
+ wxMSGArray m_arrMSG;
// critical window or NULL
static wxWindowMSW *ms_winCritical;
// Implementation
static bool RegisterWindowClasses(HAB vHab);
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
public:
int m_nCmdShow;
HMQ m_hMq;
// 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 ; }
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
+ virtual bool YieldFor(long eventsToProcess);
private:
// dispatch an event and release it
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
+ virtual bool YieldFor(long eventsToProcess);
private:
double m_sleepTime;
protected:
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
- virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
public:
// Implementation
static bool RegisterWindowClasses();
virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual bool IsRunning() const;
+ virtual bool YieldFor(long eventsToProcess);
// MSW-specific methods
// --------------------
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
virtual bool IsOk() const { return m_dispatcher != NULL; }
+ virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; }
protected:
virtual void OnNextIteration();
// 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);
/**
@name Event-handling
+
+ Note that you should look at wxEvtLoopBase for more event-processing
+ documentation.
*/
//@{
/**
- Dispatches the next event in the windowing system event queue.
- Blocks until an event appears if there are none currently
- (use Pending() if this is not wanted).
-
- This can be used for programming event loops, e.g.
-
- @code
- while (app.Pending())
- Dispatch();
- @endcode
-
- @return @false if the event loop should stop and @true otherwise.
+ Called by wxWidgets on creation of the application. Override this if you wish
+ to provide your own (environment-dependent) main loop.
- @see Pending(), wxEventLoopBase
+ @return 0 under X, and the wParam of the WM_QUIT message under Windows.
*/
- virtual bool Dispatch();
+ virtual int MainLoop();
/**
Call this to explicitly exit the main message (event) loop.
You should normally exit the main loop (and the application) by deleting
the top window.
+
+ This function simply calls wxEvtLoopBase::Exit() on the active loop.
*/
virtual void ExitMainLoop();
wxEventFunction func,
wxEvent& event) const;
- /**
- Returns @true if called from inside Yield().
- */
- virtual bool IsYielding() const;
-
- /**
- Process all pending events; 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 also called directly.
- */
- virtual void ProcessPendingEvents();
-
- /**
- Called by wxWidgets on creation of the application. Override this if you wish
- to provide your own (environment-dependent) main loop.
-
- @return 0 under X, and the wParam of the WM_QUIT message under Windows.
- */
- virtual int MainLoop();
-
- /**
- Returns @true if unprocessed events are in the window system event queue.
-
- @see Dispatch()
- */
- virtual bool Pending();
-
- /**
- Yields control to pending messages in the windowing system.
-
- This can be useful, for example, when a time-consuming process writes to a
- text window. Without an occasional yield, the text window will not be updated
- properly, and on systems with cooperative multitasking, such as Windows 3.1
- other processes will not respond.
-
- Caution should be exercised, however, since yielding may allow the
- user to perform actions which are not compatible with the current task.
- Disabling menu items or whole menus during processing can avoid unwanted
- reentrance of code: see ::wxSafeYield for a better function.
- You can avoid unwanted reentrancies also using IsYielding().
-
- Note that Yield() will not flush the message logs. This is intentional as
- calling Yield() is usually done to quickly update the screen and popping up
- a message box dialog may be undesirable. If you do wish to flush the log
- messages immediately (otherwise it will be done during the next idle loop
- iteration), call wxLog::FlushActive.
-
- Calling Yield() recursively is normally an error and an assert failure is
- raised in debug build if such situation is detected. However if the
- @a onlyIfNeeded parameter is @true, the method will just silently
- return @false instead.
- */
- 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;
-
//@}
/**
The different categories for a wxEvent; see wxEvent::GetEventCategory.
- @note They are used as OR-combinable flags by wxApp::Yield.
+ @note They are used as OR-combinable flags by wxEventLoopBase::YieldFor.
*/
enum wxEventCategory
{
wxEVT_CATEGORY_THREAD = 16,
/**
- This mask is used in wxApp::Yield to specify that all event categories should
- be processed.
+ This mask is used in wxEventLoopBase::YieldFor to specify that all event
+ categories should be processed.
*/
wxEVT_CATEGORY_ALL =
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
/**
Returns a generic category for this event.
- This function is used to selectively process events in wxApp::Yield.
+ This function is used to selectively process events in wxEventLoopBase::YieldFor.
*/
virtual wxEventCategory GetEventCategory() const;
@library{wxcore}
@category{events}
- @see @ref overview_thread, wxApp::YieldFor
+ @see @ref overview_thread, wxEventLoopBase::YieldFor
*/
class wxThreadEvent : public wxCommandEvent
{
Returns @c wxEVT_CATEGORY_THREAD.
This is important to avoid unwanted processing of thread events
- when calling wxApp::YieldFor().
+ when calling wxEventLoopBase::YieldFor().
*/
virtual wxEventCategory GetEventCategory() const;
};
@library{wxbase}
@category{appmanagement}
- @see wxApp
+ @see wxApp, wxEventLoopActivator
*/
class wxEventLoopBase
{
/**
- Use this to check whether the event loop was successfully created
- before using it
- */
- virtual bool IsOk() const;
+ @name Dispatch and processing
+ */
+ //@{
/**
Start the event loop, return the exit code when it is finished.
*/
virtual int Run() = 0;
+ /**
+ Return true if this event loop is currently running.
+
+ Notice that even if this event loop hasn't terminated yet but has just
+ spawned a nested (e.g. modal) event loop, this method would return
+ @false.
+ */
+ bool IsRunning() const;
+
+ /**
+ Use this to check whether the event loop was successfully created
+ before using it
+ */
+ virtual bool IsOk() const;
+
/**
Exit from the loop with the given exit code.
*/
virtual bool Pending() const = 0;
/**
- Dispatch a single event.
+ Dispatches the next event in the windowing system event queue.
+ Blocks until an event appears if there are none currently
+ (use Pending() if this is not wanted).
- If there are currently no events in the queue, blocks until an event
- becomes available.
+ This can be used for programming event loops, e.g.
- @return @false only if the event loop should terminate.
- */
+ @code
+ while (evtloop->Pending())
+ evtloop->Dispatch();
+ @endcode
+
+ @return @false if the event loop should stop and @true otherwise.
+
+ @see Pending(), wxEventLoopBase
+ */
virtual bool Dispatch() = 0;
/**
*/
virtual int DispatchTimeout(unsigned long timeout) = 0;
- /**
- Return true if this event loop is currently running.
-
- Notice that even if this event loop hasn't terminated yet but has just
- spawned a nested (e.g. modal) event loop, this method would return
- @false.
- */
- bool IsRunning() const;
-
/**
Called by wxWidgets to wake up the event loop even if it is currently
blocked inside Dispatch().
*/
virtual void WakeUp() = 0;
+ //@}
+
+
+ /**
+ @name Pending events
+ */
+ //@{
+
+ /**
+ Process all pending events; it is necessary to call this function to
+ process posted events.
+
+ This happens during each event loop iteration in GUI mode but
+ it may be also called directly.
+ */
+ virtual void ProcessPendingEvents();
+
+ /**
+ Returns @true if there are pending events on the internal pending event list.
+ */
+ bool HasPendingEvents() const;
+
+ /**
+ Temporary suspends processing of the pending events.
+
+ @see ResumeProcessingOfPendingEvents()
+ */
+ void SuspendProcessingOfPendingEvents();
+
+ /**
+ Resume processing of the pending events previously stopped because of a
+ call to SuspendProcessingOfPendingEvents().
+ */
+ void ResumeProcessingOfPendingEvents();
+
+ //@}
+
+
+ /**
+ @name Idle handling
+ */
+ //@{
+
+ /**
+ Makes sure that idle events are sent again.
+ */
+ virtual void WakeUpIdle();
+
+ /**
+ This virtual function is called when the application becomes idle and
+ normally just sends wxIdleEvent to all interested parties.
+
+ It should return @true if more idle events are needed, @false if not.
+ */
+ virtual bool ProcessIdle();
+
+ //@}
+
+
+ /**
+ @name Yield-related hooks
+ */
+ //@{
+
+ /**
+ Returns @true if called from inside Yield().
+ */
+ virtual bool IsYielding() const;
+
+ /**
+ Yields control to pending messages in the windowing system.
+
+ This can be useful, for example, when a time-consuming process writes to a
+ text window. Without an occasional yield, the text window will not be updated
+ properly, and on systems with cooperative multitasking, such as Windows 3.1
+ other processes will not respond.
+
+ Caution should be exercised, however, since yielding may allow the
+ user to perform actions which are not compatible with the current task.
+ Disabling menu items or whole menus during processing can avoid unwanted
+ reentrance of code: see ::wxSafeYield for a better function.
+ You can avoid unwanted reentrancies also using IsYielding().
+
+ Note that Yield() will not flush the message logs. This is intentional as
+ calling Yield() is usually done to quickly update the screen and popping up
+ a message box dialog may be undesirable. If you do wish to flush the log
+ messages immediately (otherwise it will be done during the next idle loop
+ iteration), call wxLog::FlushActive.
+
+ Calling Yield() recursively is normally an error and an assert failure is
+ raised in debug build if such situation is detected. However if the
+ @a onlyIfNeeded parameter is @true, the method will just silently
+ return @false instead.
+ */
+ 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 will be processed; i.e. this method
+ helps to avoid unwanted reentrancies.
+
+ Note that currently only wxMSW and wxGTK do support selective yield of
+ native events coming from the underlying GUI toolkit.
+ wxWidgets events posted using wxEvtHandler::AddPendingEvent or
+ wxEvtHandler::QueueEvent are instead selectively processed by all ports.
+
+ @see wxEvent::GetEventCategory
+ */
+ 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()).
+
+ @see wxEvent::GetEventCategory
+ */
+ virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const;
+
+ //@}
+
+
protected:
/**
This function is called before the event loop terminates, whether this
GetTraits()->SetLocale();
#endif // wxUSE_INTL
-#if wxUSE_THREADS
- wxHandlersWithPendingEventsLocker = new wxCriticalSection;
- wxHandlersWithPendingDelayedEvents = new wxList;
-#endif
-
#ifndef __WXPALMOS__
if ( m_appName.empty() && argv && argv[0] )
{
delete m_mainLoop;
m_mainLoop = NULL;
}
-
- delete wxHandlersWithPendingEvents;
- wxHandlersWithPendingEvents = NULL;
-
- delete wxHandlersWithPendingDelayedEvents;
- wxHandlersWithPendingDelayedEvents = NULL;
-
-#if wxUSE_THREADS
- delete wxHandlersWithPendingEventsLocker;
- wxHandlersWithPendingEventsLocker = NULL;
-#endif // wxUSE_THREADS
}
// ----------------------------------------------------------------------------
}
// ----------------------------------------------------------------------------
-// event processing
+// wxEventLoop redirection
// ----------------------------------------------------------------------------
int wxAppConsoleBase::MainLoop()
bool wxAppConsoleBase::HasPendingEvents() const
{
- wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
- bool has = wxHandlersWithPendingEvents && !wxHandlersWithPendingEvents->IsEmpty();
-
- wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
- return has;
+ return loop && loop->HasPendingEvents();
}
void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
{
- wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-}
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
-void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
-{
- wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+ if (loop) loop->SuspendProcessingOfPendingEvents();
}
-/* static */
-bool wxAppConsoleBase::IsMainLoopRunning()
+void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
{
- const wxAppConsole * const app = GetInstance();
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
- return app && app->m_mainLoop != NULL;
+ if (loop) loop->ResumeProcessingOfPendingEvents();
}
void wxAppConsoleBase::ProcessPendingEvents()
{
-#if wxUSE_THREADS
- if ( !wxHandlersWithPendingEventsLocker )
- return;
-#endif
-
- 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
- // from it when they don't have any more pending events
- wxList::compatibility_iterator node = wxHandlersWithPendingEvents->GetFirst();
- while (node)
- {
- // In ProcessPendingEvents(), new handlers might be added
- // and we can safely leave the critical section here.
- wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
- wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
- handler->ProcessPendingEvents();
-
- wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
- // restart as the iterators could have been invalidated
- node = wxHandlersWithPendingEvents->GetFirst();
- }
- }
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
- // 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;
+ if (loop) loop->ProcessPendingEvents();
+}
- WX_APPEND_LIST(wxHandlersWithPendingEvents, wxHandlersWithPendingDelayedEvents);
- wxHandlersWithPendingDelayedEvents->Clear();
- }
+bool wxAppConsoleBase::Yield(bool onlyIfNeeded)
+{
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
- wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+ return loop && loop->Yield(onlyIfNeeded);
}
void wxAppConsoleBase::WakeUpIdle()
bool wxAppConsoleBase::ProcessIdle()
{
- // process pending wx events before sending idle events
- ProcessPendingEvents();
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+
+ return loop && loop->ProcessIdle();
+}
+
+// ----------------------------------------------------------------------------
+// events
+// ----------------------------------------------------------------------------
- wxIdleEvent event;
+/* static */
+bool wxAppConsoleBase::IsMainLoopRunning()
+{
+ const wxAppConsole * const app = GetInstance();
- event.SetEventObject(this);
- ProcessEvent(event);
- return event.MoreRequested();
+ return app && app->m_mainLoop != NULL;
}
int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
// normally wxLogFatalError doesn't return
return false;
}
-#undef wxCMP
return true;
}
#include "wx/msgout.h"
#include "wx/thread.h"
#include "wx/vidmode.h"
+#include "wx/evtloop.h"
#ifdef __WXDEBUG__
#if wxUSE_STACKWALKER
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
// to Yes initially as this dialog would be the last top level window.
(void)ProcessEvent(event);
}
-bool wxAppBase::IsEventAllowedInsideYield(wxEventCategory cat) const
-{
- return (m_eventsToProcessInsideYield & cat) != 0;
-}
-
bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
{
wxWindowDisabler wd(win);
- return Yield(onlyIfNeeded);
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+
+ return loop && loop->Yield(onlyIfNeeded);
}
bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
{
wxWindowDisabler wd(win);
- return YieldFor(eventsToProcess);
+ wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+
+ return loop && loop->YieldFor(eventsToProcess);
}
// global variables
// ----------------------------------------------------------------------------
-// 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
- wxCriticalSection *wxHandlersWithPendingEventsLocker = NULL;
-#endif
-
// common event types are defined here, other event types are defined by the
// components which use them
// wxEvtHandler
// ----------------------------------------------------------------------------
-/*
- * Event handler
- */
-
wxEvtHandler::wxEvtHandler()
{
m_nextHandler = NULL;
delete entry;
}
delete m_dynamicEvents;
- };
+ }
if (m_pendingEvents)
m_pendingEvents->DeleteContents(true);
delete m_pendingEvents;
- // Remove us from wxHandlersWithPendingEvents if necessary.
- if ( wxHandlersWithPendingEvents )
- {
-#if wxUSE_THREADS
- if (wxHandlersWithPendingEventsLocker)
- wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-
- if ( wxHandlersWithPendingEvents->DeleteObject(this) )
- {
- // check that we were present only once in the list
- wxASSERT_MSG( !wxHandlersWithPendingEvents->Find(this),
- "Handler occurs twice in wxHandlersWithPendingEvents list" );
- }
- //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);
-#endif
- }
+ // Remove us from the list of the pending events if necessary.
+ wxEventLoopBase *loop = wxEventLoopBase::GetActive();
+ if (loop)
+ loop->RemovePendingEventHandler(this);
// we only delete object data, not untyped
if ( m_clientDataType == wxClientData_Object )
{
wxCHECK_RET( event, "NULL event can't be posted" );
+ wxEventLoopBase* loop = wxEventLoopBase::GetActive();
+ if (!loop)
+ {
+ // we need an event loop which manages the list of event handlers with
+ // pending events... cannot proceed without it!
+ wxLogDebug("No event loop is running!");
+ return;
+ }
+
// 1) Add this event to our list of pending events
wxENTER_CRIT_SECT( m_pendingEventsLock );
// 2) Add this event handler to list of event handlers that
// have pending events.
- wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-
- if ( !wxHandlersWithPendingEvents )
- wxHandlersWithPendingEvents = new wxList;
- if ( !wxHandlersWithPendingEvents->Find(this) )
- wxHandlersWithPendingEvents->Append(this);
-
- wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
+ loop->AppendPendingEventHandler(this);
// only release m_pendingEventsLock now because otherwise there is a race
// condition as described in the ticket #9093: we could process the event
void wxEvtHandler::ProcessPendingEvents()
{
+ wxEventLoopBase* loop = wxEventLoopBase::GetActive();
+ if (!loop)
+ {
+ // we need an event loop which manages the list of event handlers with
+ // pending events... cannot proceed without it!
+ wxLogDebug("No event loop is running!");
+ return;
+ }
+
// 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)
wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
// find the first event which can be processed now:
- if (wxTheApp && wxTheApp->IsYielding())
+ wxEventLoopBase* evtLoop = wxEventLoopBase::GetActive();
+ if (evtLoop && evtLoop->IsYielding())
{
- while (node && pEvent && !wxTheApp->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
+ while (node && pEvent && !evtLoop->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
+ loop->DelayPendingEventHandler(this);
+
+ // see the comment at the beginning of evtloop.h header for the
+ // logic behind YieldFor() and behind DelayPendingEventHandler()
+
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
return;
// same event again.
m_pendingEvents->Erase(node);
- // if there are no more pending events left, we don't need to stay in this
- // list
if ( m_pendingEvents->IsEmpty() )
{
-#if wxUSE_THREADS
- if (wxHandlersWithPendingEventsLocker)
- wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
- wxHandlersWithPendingEvents->DeleteObject(this);
-#if wxUSE_THREADS
- if (wxHandlersWithPendingEventsLocker)
- wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
+ // if there are no more pending events left, we don't need to
+ // stay in this list
+ loop->RemovePendingEventHandler(this);
}
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
+wxEventLoopBase::wxEventLoopBase()
+{
+ m_isInsideYield = false;
+ m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
+}
+
+void wxEventLoopBase::DelayPendingEventHandler(wxEvtHandler* toDelay)
+{
+ wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+ // move the handler from the list of handlers with processable pending events
+ // to the list of handlers with pending events which needs to be processed later
+ m_handlersWithPendingEvents.Remove(toDelay);
+
+ if (m_handlersWithPendingDelayedEvents.Index(toDelay) == wxNOT_FOUND)
+ m_handlersWithPendingDelayedEvents.Add(toDelay);
+
+ wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::RemovePendingEventHandler(wxEvtHandler* toRemove)
+{
+ wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+ if (m_handlersWithPendingEvents.Index(toRemove) != wxNOT_FOUND)
+ {
+ m_handlersWithPendingEvents.Remove(toRemove);
+
+ // check that the handler was present only once in the list
+ wxASSERT_MSG( m_handlersWithPendingEvents.Index(toRemove) == wxNOT_FOUND,
+ "Handler occurs twice in the m_handlersWithPendingEvents list!" );
+ }
+ //else: it wasn't in this list at all, it's ok
+
+ if (m_handlersWithPendingDelayedEvents.Index(toRemove) != wxNOT_FOUND)
+ {
+ m_handlersWithPendingDelayedEvents.Remove(toRemove);
+
+ // check that the handler was present only once in the list
+ wxASSERT_MSG( m_handlersWithPendingDelayedEvents.Index(toRemove) == wxNOT_FOUND,
+ "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" );
+ }
+ //else: it wasn't in this list at all, it's ok
+
+ wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::AppendPendingEventHandler(wxEvtHandler* toAppend)
+{
+ wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+ if ( m_handlersWithPendingEvents.Index(toAppend) == wxNOT_FOUND )
+ m_handlersWithPendingEvents.Add(toAppend);
+
+ wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+bool wxEventLoopBase::HasPendingEvents() const
+{
+ wxENTER_CRIT_SECT(const_cast<wxEventLoopBase*>(this)->m_handlersWithPendingEventsLocker);
+
+ bool has = !m_handlersWithPendingEvents.IsEmpty();
+
+ wxLEAVE_CRIT_SECT(const_cast<wxEventLoopBase*>(this)->m_handlersWithPendingEventsLocker);
+
+ return has;
+}
+
+void wxEventLoopBase::SuspendProcessingOfPendingEvents()
+{
+ wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::ResumeProcessingOfPendingEvents()
+{
+ wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::ProcessPendingEvents()
+{
+ wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+ wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
+ "this helper list should be empty" );
+
+ // iterate until the list becomes empty: the handlers remove themselves
+ // from it when they don't have any more pending events
+ while (!m_handlersWithPendingEvents.IsEmpty())
+ {
+ // In ProcessPendingEvents(), new handlers might be added
+ // and we can safely leave the critical section here.
+ wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+ // NOTE: we always call ProcessPendingEvents() on the first event handler
+ // with pending events because handlers auto-remove themselves
+ // from this list (see RemovePendingEventHandler) if they have no
+ // more pending events.
+ m_handlersWithPendingEvents[0]->ProcessPendingEvents();
+
+ wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+ }
+
+ // 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 (!m_handlersWithPendingDelayedEvents.IsEmpty())
+ {
+ WX_APPEND_ARRAY(m_handlersWithPendingEvents, m_handlersWithPendingDelayedEvents);
+ m_handlersWithPendingDelayedEvents.Clear();
+ }
+
+ wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::WakeUpIdle()
+{
+ WakeUp();
+}
+
+bool wxEventLoopBase::ProcessIdle()
+{
+ // process pending wx events before sending idle events
+ ProcessPendingEvents();
+
+ wxIdleEvent event;
+
+ event.SetEventObject(wxTheApp);
+ wxTheApp->ProcessEvent(event);
+ return event.MoreRequested();
+}
+
+bool wxEventLoopBase::Yield(bool onlyIfNeeded)
+{
+ if ( m_isInsideYield )
+ {
+ if ( !onlyIfNeeded )
+ {
+ wxFAIL_MSG( wxT("wxYield called recursively" ) );
+ }
+
+ return false;
+ }
+
+ return YieldFor(wxEVT_CATEGORY_ALL);
+}
+
// wxEventLoopManual is unused in the other ports
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && wxUSE_BASE)
wxMutexGuiLeave();
#endif
}
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-#if wxUSE_THREADS
- if ( !wxThread::IsMain() )
- return true; // can't process events from other threads
-#endif // wxUSE_THREADS
-
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
- m_isInsideYield = true;
- m_eventsToProcessInsideYield = eventsToProcess;
-
-#if wxUSE_LOG
- wxLog::Suspend();
-#endif // wxUSE_LOG
-
- wxEventLoop * const
- loop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
- if ( loop )
- loop->Yield();
-
- // 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)
- while ( ProcessIdle() ) {}
-
-#if wxUSE_LOG
- wxLog::Resume();
-#endif // wxUSE_LOG
-
- m_isInsideYield = false;
-
- return true;
-}
// events dispatch and loop handling
//-----------------------------------------------------------------------------
-void wxGUIEventLoop::Yield()
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
{
+#if wxUSE_THREADS
+ if ( !wxThread::IsMain() )
+ return true; // can't process events from other threads
+#endif // wxUSE_THREADS
+
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+#if wxUSE_LOG
+ wxLog::Suspend();
+#endif // wxUSE_LOG
+
// TODO: implement event filtering using the eventsToProcess mask
// process all pending events:
// handle timers, sockets etc.
OnNextIteration();
+
+ // 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)
+ while ( ProcessIdle() ) {}
+
+#if wxUSE_LOG
+ wxLog::Resume();
+#endif // wxUSE_LOG
+
+ m_isInsideYield = false;
+
+ return true;
}
#endif
#include "wx/progdlg.h"
+#include "wx/evtloop.h"
// ---------------------------------------------------------------------------
// macros
m_msg->SetLabel(_("Done."));
}
- wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
+ wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
(void)ShowModal();
}
{
// 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
- wxTheApp->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
+ wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
Update();
Fit(); // adapt to the new label size
- wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
+ wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
}
}
wxFORCE_LINK_MODULE(gnome_vfs)
#endif
-//-----------------------------------------------------------------------------
-// global data
-//-----------------------------------------------------------------------------
-
-static GtkWidget *gs_RootWindow = NULL;
-static wxArrayPtrVoid g_arrGdkEvents;
-
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
-#if wxUSE_THREADS
- if ( !wxThread::IsMain() )
- {
- // can't call gtk_main_iteration() from other threads like this
- return true;
- }
-#endif // wxUSE_THREADS
-
- m_isInsideYield = true;
- m_eventsToProcessInsideYield = eventsToProcess;
-
-#if wxUSE_LOG
- // disable log flushing from here because a call to wxYield() shouldn't
- // normally result in message boxes popping up &c
- wxLog::Suspend();
-#endif
-
- // 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() 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
- wxLog::Resume();
-#endif
-
- m_isInsideYield = false;
-
- return true;
-}
-
//-----------------------------------------------------------------------------
// local functions
//-----------------------------------------------------------------------------
GtkWidget* wxGetRootWindow()
{
- if (gs_RootWindow == NULL)
+ static GtkWidget *s_RootWindow = NULL;
+
+ if (s_RootWindow == NULL)
{
- gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
- gtk_widget_realize( gs_RootWindow );
+ s_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ gtk_widget_realize( s_RootWindow );
}
- return gs_RootWindow;
+ return s_RootWindow;
}
//-----------------------------------------------------------------------------
#include "wx/scopedarray.h"
#include "wx/scopeguard.h"
+#include "wx/evtloop.h"
#include "wx/gtk/private.h"
~wxClipboardSync()
{
while (ms_clipboard)
- wxTheApp->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
+ wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
}
// this method must be called by GTK+ callbacks to indicate that we got the
// wxEventLoop implementation
// ============================================================================
+extern GtkWidget *wxGetRootWindow();
+
// ----------------------------------------------------------------------------
// wxEventLoop running and exiting
// ----------------------------------------------------------------------------
return !quit;
}
+//-----------------------------------------------------------------------------
+// YieldFor
+//-----------------------------------------------------------------------------
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+#if wxUSE_THREADS
+ if ( !wxThread::IsMain() )
+ {
+ // can't call gtk_main_iteration() from other threads like this
+ return true;
+ }
+#endif // wxUSE_THREADS
+
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+#if wxUSE_LOG
+ // disable log flushing from here because a call to wxYield() shouldn't
+ // normally result in message boxes popping up &c
+ wxLog::Suspend();
+#endif
+
+ // 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(wxGetRootWindow());
+
+ // 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
+ m_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<m_arrGdkEvents.GetCount(); i++)
+ {
+ GdkEvent* ev = (GdkEvent*)m_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);
+ }
+
+ m_arrGdkEvents.Clear();
+
+#if wxUSE_LOG
+ // let the logs be flashed again
+ wxLog::Resume();
+#endif
+
+ m_isInsideYield = false;
+
+ return true;
+}
static wxMutex gs_idleTagsMutex;
#endif
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
-#if wxUSE_THREADS
- if ( !wxThread::IsMain() )
- {
- // can't call gtk_main_iteration() from other threads like this
- return true;
- }
-#endif // wxUSE_THREADS
-
- m_isInsideYield = true;
- m_eventsToProcessInsideYield = eventsToProcess;
-
- // We need to remove idle callbacks or the loop will
- // never finish.
- wxTheApp->RemoveIdleTag();
-
-#if wxUSE_LOG
- // disable log flushing from here because a call to wxYield() shouldn't
- // normally result in message boxes popping up &c
- wxLog::Suspend();
-#endif
-
- // TODO: implement event filtering using the eventsToProcess mask
- while (gtk_events_pending())
- gtk_main_iteration();
-
- // 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();
-
-#if wxUSE_LOG
- // let the logs be flashed again
- wxLog::Resume();
-#endif
-
- m_isInsideYield = false;
-
- return true;
-}
//-----------------------------------------------------------------------------
// wxWakeUpIdle
return true;
}
+
+//-----------------------------------------------------------------------------
+// wxYield
+//-----------------------------------------------------------------------------
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+#if wxUSE_THREADS
+ if ( !wxThread::IsMain() )
+ {
+ // can't call gtk_main_iteration() from other threads like this
+ return true;
+ }
+#endif // wxUSE_THREADS
+
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+ // We need to remove idle callbacks or the loop will
+ // never finish.
+ wxTheApp->RemoveIdleTag();
+
+#if wxUSE_LOG
+ // disable log flushing from here because a call to wxYield() shouldn't
+ // normally result in message boxes popping up &c
+ wxLog::Suspend();
+#endif
+
+ // TODO: implement event filtering using the eventsToProcess mask
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ // 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();
+
+#if wxUSE_LOG
+ // let the logs be flashed again
+ wxLog::Resume();
+#endif
+
+ m_isInsideYield = false;
+
+ return true;
+}
exit(0);
}
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
-#if wxUSE_THREADS
- if ( !wxThread::IsMain() )
- {
- // can't process events from other threads, MGL is thread-unsafe
- return true;
- }
-#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();
- }
-
- /* 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) */
- while (wxTheApp->ProcessIdle()) { }
-
- wxLog::Resume();
-
- m_isInsideYield = false;
-
- return true;
-}
-
//-----------------------------------------------------------------------------
// wxWakeUpIdle
return m_impl->GetKeepLooping();
}
+
+//-----------------------------------------------------------------------------
+// wxYield
+//-----------------------------------------------------------------------------
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+#if wxUSE_THREADS
+ if ( !wxThread::IsMain() )
+ {
+ // can't process events from other threads, MGL is thread-unsafe
+ return true;
+ }
+#endif // wxUSE_THREADS
+
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+ wxLog::Suspend();
+
+ // TODO: implement event filtering using the eventsToProcess mask
+
+ while (Pending())
+ Dispatch();
+
+ /* 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) */
+ while (wxTheApp->ProcessIdle()) { }
+
+ wxLog::Resume();
+
+ m_isInsideYield = false;
+
+ return true;
+}
.m_topLevelRealizedWidget = (Widget)widget;
}
-// Yield to other processes
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
- 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;
-
- return true;
-}
// ----------------------------------------------------------------------------
// accessors for C modules
::wxBreakDispatch();
}
+bool wxGUIEventLoop::YieldFor(ong eventsToProcess)
+{
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+ while (wxTheApp && wxTheApp->Pending())
+ // TODO: implement event filtering using the eventsToProcess mask
+ wxTheApp->Dispatch();
+
+ m_isInsideYield = false;
+
+ return true;
+}
+
// ----------------------------------------------------------------------------
// wxEventLoop message processing dispatching
// ----------------------------------------------------------------------------
#endif // !__WXWINCE__
-// ----------------------------------------------------------------------------
-// Yield to incoming messages
-// ----------------------------------------------------------------------------
-
-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 )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
- // set the flag and don't forget to reset it before returning
- m_isInsideYield = true;
- 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
- // normally result in message boxes popping up &c
- wxLog::Suspend();
-
- // ensure the logs will be flashed again when we exit
- 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;
- MSG msg;
- while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
- msg.message != WM_QUIT )
- {
-#if wxUSE_THREADS
- wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
-
- if (msg.message == WM_PAINT)
- {
- // WM_PAINT messages are the last ones of the queue...
- break;
- }
-
- // choose a wxEventCategory for this Windows message
- 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_KEYDOWN:
- case WM_KEYUP:
- case WM_CHAR:
- case WM_DEADCHAR:
- case WM_SYSKEYDOWN:
- case WM_SYSKEYUP:
- case WM_SYSCHAR:
- case WM_SYSDEADCHAR:
-#ifdef WM_UNICHAR
- case WM_UNICHAR:
-#endif
- case WM_HOTKEY:
- case WM_IME_STARTCOMPOSITION:
- case WM_IME_ENDCOMPOSITION:
- case WM_IME_COMPOSITION:
- 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:
-#ifdef WM_NCMOUSELEAVE
- case WM_NCMOUSELEAVE:
-#endif
- case WM_MOUSELEAVE:
-
- case WM_CUT:
- case WM_COPY:
- case WM_PASTE:
- case WM_CLEAR:
- case WM_UNDO:
-
- 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_MOUSEWHEEL:
- cat = wxEVT_CATEGORY_USER_INPUT;
- break;
-
- case WM_TIMER:
- cat = wxEVT_CATEGORY_TIMER;
- break;
-
- default:
- if (msg.message < WM_USER)
- {
- // 0;WM_USER-1 is the range of message IDs reserved for use
- // by the system.
-
- // there are too many of these types of messages to handle
- // them in this switch
- cat = wxEVT_CATEGORY_UI;
- }
- else
- cat = wxEVT_CATEGORY_UNKNOWN;
- }
-
- // should we process this event now?
- if (cat & eventsToProcess)
- {
- if ( !wxTheApp->Dispatch() )
- break;
- }
- else
- {
- // remove the message and store it
- ::GetMessage(&msg, NULL, 0, 0);
- 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;
-}
-
#if wxUSE_EXCEPTIONS
// ----------------------------------------------------------------------------
#include "wx/thread.h"
#include "wx/except.h"
#include "wx/msw/private.h"
+#include "wx/scopeguard.h"
#if wxUSE_GUI
#include "wx/tooltip.h"
::PostMessage(NULL, WM_NULL, 0, 0);
}
+
+// ----------------------------------------------------------------------------
+// Yield to incoming messages
+// ----------------------------------------------------------------------------
+
+#include <wx/arrimpl.cpp>
+WX_DEFINE_OBJARRAY(wxMSGArray);
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+ // set the flag and don't forget to reset it before returning
+ m_isInsideYield = true;
+ 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
+ // normally result in message boxes popping up &c
+ wxLog::Suspend();
+
+ // ensure the logs will be flashed again when we exit
+ 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
+ MSG msg;
+ while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
+ msg.message != WM_QUIT )
+ {
+#if wxUSE_THREADS
+ wxMutexGuiLeaveOrEnter();
+#endif // wxUSE_THREADS
+
+ if (msg.message == WM_PAINT)
+ {
+ // WM_PAINT messages are the last ones of the queue...
+ break;
+ }
+
+ // choose a wxEventCategory for this Windows message
+ 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_KEYDOWN:
+ case WM_KEYUP:
+ case WM_CHAR:
+ case WM_DEADCHAR:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_SYSCHAR:
+ case WM_SYSDEADCHAR:
+#ifdef WM_UNICHAR
+ case WM_UNICHAR:
+#endif
+ case WM_HOTKEY:
+ case WM_IME_STARTCOMPOSITION:
+ case WM_IME_ENDCOMPOSITION:
+ case WM_IME_COMPOSITION:
+ 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:
+#ifdef WM_NCMOUSELEAVE
+ case WM_NCMOUSELEAVE:
+#endif
+ case WM_MOUSELEAVE:
+
+ case WM_CUT:
+ case WM_COPY:
+ case WM_PASTE:
+ case WM_CLEAR:
+ case WM_UNDO:
+
+ 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_MOUSEWHEEL:
+ cat = wxEVT_CATEGORY_USER_INPUT;
+ break;
+
+ case WM_TIMER:
+ cat = wxEVT_CATEGORY_TIMER;
+ break;
+
+ default:
+ if (msg.message < WM_USER)
+ {
+ // 0;WM_USER-1 is the range of message IDs reserved for use
+ // by the system.
+
+ // there are too many of these types of messages to handle
+ // them in this switch
+ cat = wxEVT_CATEGORY_UI;
+ }
+ else
+ cat = wxEVT_CATEGORY_UNKNOWN;
+ }
+
+ // should we process this event now?
+ if (cat & eventsToProcess)
+ {
+ if ( !wxTheApp->Dispatch() )
+ break;
+ }
+ else
+ {
+ // remove the message and store it
+ ::GetMessage(&msg, NULL, 0, 0);
+ m_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<m_arrMSG.GetCount(); i++)
+ {
+ PostThreadMessage(id, m_arrMSG[i].message,
+ m_arrMSG[i].wParam, m_arrMSG[i].lParam);
+ }
+
+ m_arrMSG.Clear();
+
+ return true;
+}
+
+
#else // !wxUSE_GUI
}
} // end of wxApp::OnQueryEndSession
-//
-// Yield to incoming messages
-//
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( _T("wxYield() called recursively") );
- }
-
- return false;
- }
-
- HAB vHab = 0;
- QMSG vMsg;
-
- //
- // Disable log flushing from here because a call to wxYield() shouldn't
- // normally result in message boxes popping up &c
- //
- wxLog::Suspend();
-
- m_isInsideYield = true;
- m_eventsToProcessInsideYield = eventsToProcess;
-
- //
- // We want to go back to the main message loop
- // if we see a WM_QUIT. (?)
- //
- 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
- if (!wxTheApp->Dispatch())
- break;
- }
-
- //
- // If they are pending events, we must process them.
- //
- if (wxTheApp)
- wxTheApp->ProcessPendingEvents();
-
- HandleSockets();
-
- //
- // Let the logs be flashed again
- //
- wxLog::Resume();
- m_isInsideYield = false;
-
- return true;
-} // end of wxYield
-
int wxApp::AddSocketHandler(int handle, int mask,
void (*callback)(void*), void * gsock)
{
return true;
}
+
+//
+// Yield to incoming messages
+//
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+ HAB vHab = 0;
+ QMSG vMsg;
+
+ //
+ // Disable log flushing from here because a call to wxYield() shouldn't
+ // normally result in message boxes popping up &c
+ //
+ wxLog::Suspend();
+
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+ //
+ // We want to go back to the main message loop
+ // if we see a WM_QUIT. (?)
+ //
+ 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
+ if (!wxTheApp->Dispatch())
+ break;
+ }
+
+ //
+ // If they are pending events, we must process them.
+ //
+ if (wxTheApp)
+ wxTheApp->ProcessPendingEvents();
+
+ HandleSockets();
+
+ //
+ // Let the logs be flashed again
+ //
+ wxLog::Resume();
+ m_isInsideYield = false;
+
+ return true;
+} // end of wxYield
return 0;
}
-// Yield to incoming messages
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- return true;
-}
-
#if wxUSE_EXCEPTIONS
// ----------------------------------------------------------------------------
return;
}
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+ return true;
+}
+
wxAppConsole::Exit();
}
-// Yield to other processes
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
- // Sometimes only 2 yields seem
- // to do the trick, e.g. in the
- // progress dialog
- int i;
- for (i = 0; i < 2; i++)
- {
- if ( m_isInsideYield )
- {
- if ( !onlyIfNeeded )
- {
- wxFAIL_MSG( wxT("wxYield called recursively" ) );
- }
-
- return false;
- }
-
- m_isInsideYield = true;
- m_eventsToProcessInsideYield = eventsToProcess;
-
- // Make sure we have an event loop object,
- // or Pending/Dispatch will fail
- wxEventLoopGuarantor dummyLoopIfNeeded;
-
- // Call dispatch at least once so that sockets
- // can be tested
- wxTheApp->Dispatch();
-
- // TODO: implement event filtering using the eventsToProcess mask
- while (wxTheApp && wxTheApp->Pending())
- wxTheApp->Dispatch();
-
-#if wxUSE_TIMER
- wxGenericTimerImpl::NotifyTimers();
-#endif
- ProcessIdle();
-
- m_isInsideYield = false;
- }
-
- return true;
-}
-
#ifdef __WXDEBUG__
void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
(void) m_impl->ProcessEvent( &event );
return true;
}
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+ // Sometimes only 2 yields seem
+ // to do the trick, e.g. in the
+ // progress dialog
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
+
+ // Call dispatch at least once so that sockets
+ // can be tested
+ wxTheApp->Dispatch();
+
+ // TODO: implement event filtering using the eventsToProcess mask
+ while (wxTheApp && wxTheApp->Pending())
+ wxTheApp->Dispatch();
+
+#if wxUSE_TIMER
+ wxGenericTimerImpl::NotifyTimers();
+#endif
+ ProcessIdle();
+
+ m_isInsideYield = false;
+ }
+
+ return true;
+}