#if wxUSE_GUI
struct WXDLLIMPEXP_FWD_CORE wxVideoMode;
+ class WXDLLIMPEXP_FWD_CORE wxWindow;
#endif
// ----------------------------------------------------------------------------
// (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
// 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();
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_BASE wxEvtHandler;
+
// the application object is a singleton anyhow, there is no sense in
// copying it
DECLARE_NO_COPY_CLASS(wxAppConsoleBase)
// 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
// does any of our windows have focus?
bool m_isActive;
+ // Yield() helpers:
bool m_isInsideYield;
+ long m_eventsToProcessInsideYield;
DECLARE_NO_COPY_CLASS(wxAppBase)
};
// 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
// 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);
virtual void CleanUp();
virtual bool CallOnInit();
-
+
virtual bool OnInit();
virtual bool OnInitGui();
virtual void CleanUp();
virtual void WakeUpIdle();
- virtual bool Yield(bool onlyIfNeeded = false);
virtual wxVideoMode GetDisplayMode() const;
virtual bool SetDisplayMode(const wxVideoMode& mode);
private:
wxVideoMode m_videoMode;
+ virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
DECLARE_DYNAMIC_CLASS(wxApp)
};
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)
// 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,
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.).
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; }
// 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; }
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;
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
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.
/*
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxScrollWinEvent)
};
+
+
// Mouse event class
/*
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)
{
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)
*/
+
// ============================================================================
// event handler and related classes
// ============================================================================
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
};
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&);
#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) \
#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
// ----------------------------------------------------------------------------
//
// 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
// ----------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// Name: wx/gtk/app.h
-// Purpose:
+// Purpose: wxApp definition for wxGTK
// Author: Robert Roebling
// Id: $Id$
// Copyright: (c) 1998 Robert Roebling, Julian Smart
virtual bool OnInitGui();
// override base class (pure) virtuals
- virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool Initialize(int& argc, wxChar **argv);
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 OnInitGui();
// override base class (pure) virtuals
- virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool Initialize(int& argc, wxChar **argv);
bool m_isInAssert;
#endif // __WXDEBUG__
+ virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
DECLARE_DYNAMIC_CLASS(wxApp)
};
(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__
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);
private:
DECLARE_DYNAMIC_CLASS(wxApp)
+ virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
wxVideoMode m_displayMode;
};
virtual void Exit();
- virtual bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle(); // implemented in motif/evtloop.cpp
// implementation from now on
// 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; }
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; }
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();
virtual bool OnInitGui(void);
- virtual bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle(void);
virtual void SetPrintMode(int mode) { m_nPrintMode = mode; }
// Implementation
static bool RegisterWindowClasses(HAB vHab);
+ virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
public:
int m_nCmdShow;
HMQ m_hMq;
wxApp();
virtual ~wxApp() {}
- virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual void SetPrintMode(int mode) { m_printMode = mode; }
// 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 ; }
private:
// mac specifics
virtual bool DoInitGui();
- virtual void DoCleanUp();
+ virtual void DoCleanUp();
WXEVENTHANDLERREF m_macEventHandler ;
WXEVENTHANDLERCALLREF m_macCurrentEventHandlerCallRef ;
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; }
protected:
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
+ virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
public:
// Implementation
static bool RegisterWindowClasses();
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;
// 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;
virtual void Exit();
- virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool OnInitGui();
// 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);
@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;
//@}
/**
Returns the one and only global application object.
- Usually wxTheApp is used instead.
+ Usually ::wxTheApp is used instead.
@see SetInstance()
*/
*/
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.
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}
*/
// 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
*/
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.
*/
};
+/**
+ @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.
+
+ Initializes the event type to @c wxEVT_THREAD (but you can change it
+ using wxEvent::SetEventType.
+ */
+ wxThreadEvent(int id = wxID_ANY);
- /** event generated by wxContextHelp or from the [?] button on
- the title bar (Windows). */
- wxHE_ORIGIN_HELPBUTTON
+ /**
+ 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
/////////////////////////////////////////////////////////////////////////////
// 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
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
-
+
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#endif
-#define USE_ASYNCHRONOUS_CLIPBOARD_REQUEST 1
+#define USE_ASYNCHRONOUS_CLIPBOARD_REQUEST 0
class MyApp : public wxApp
{
MyFrame *frame = new MyFrame("wxClipboard sample");
frame->Show(true);
-
+
return true;
}
{
// set the frame icon
SetIcon(wxICON(sample));
-
+
#if USE_ASYNCHRONOUS_CLIPBOARD_REQUEST
m_request = Idle;
m_clipboardSupportsText = false;
#endif // wxUSE_MENUS
wxPanel *panel = new wxPanel( this, -1 );
-
+
wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
main_sizer->Add( new wxButton( panel, ID_Write, "Get clipboard text" ) );
m_textctrl = new wxTextCtrl( panel, ID_Text, "", wxDefaultPosition,
wxTheClipboard->GetData( data );
m_textctrl->Clear();
m_textctrl->SetValue( data.GetText() );
-
+
}
wxTheClipboard->Close();
}
}
m_request = Waiting;
event.Enable( m_clipboardSupportsText ); // not yet known, assume last value
- }
+ }
else if (m_request == Waiting)
{
event.Enable( m_clipboardSupportsText ); // not yet known, assume last value
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
+ wxMessageBox("Clipboard sample", "About clipboard", wxOK|wxICON_INFORMATION, this);
}
void OnResumeThread(wxCommandEvent& event);
void OnStartWorker(wxCommandEvent& event);
- void OnWorkerEvent(wxCommandEvent& event);
+ void OnWorkerEvent(wxThreadEvent& event);
void OnUpdateWorker(wxUpdateUIEvent& event);
void OnExecMain(wxCommandEvent& event);
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
};
// ----------------------------------------------------------------------------
{
}
+#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
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;
}
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()
m_txtctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxPoint(0, 0), wxSize(0, 0),
wxTE_MULTILINE | wxTE_READONLY);
-
}
MyFrame::~MyFrame()
thread->Run();
}
-void MyFrame::OnWorkerEvent(wxCommandEvent& event)
+void MyFrame::OnWorkerEvent(wxThreadEvent& event)
{
int n = event.GetInt();
if ( n == -1 )
}
// 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
}
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
#if wxUSE_THREADS
wxHandlersWithPendingEventsLocker = new wxCriticalSection;
+ wxHandlersWithPendingDelayedEvents = new wxList;
#endif
#ifndef __WXPALMOS__
delete wxHandlersWithPendingEvents;
wxHandlersWithPendingEvents = NULL;
+ delete wxHandlersWithPendingDelayedEvents;
+ wxHandlersWithPendingDelayedEvents = NULL;
+
#if wxUSE_THREADS
delete wxHandlersWithPendingEventsLocker;
wxHandlersWithPendingEventsLocker = NULL;
return has;
}
+void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
+{
+ wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+}
+
+void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
+{
+ wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+}
+
/* static */
bool wxAppConsoleBase::IsMainLoopRunning()
{
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
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 );
}
}
+ // 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 );
}
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
(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
// ----------------------------------------------------------------------------
#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)
// 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
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
// ----------------------------------------------------------------------------
/*
- * 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.
*
*/
-wxEvent::wxEvent(int theId, wxEventType commandType )
+wxEvent::wxEvent(int theId, wxEventType commandType)
{
m_eventType = commandType;
m_eventObject = NULL;
}
//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);
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
"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
{
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 )
{
wxDummyConsoleApp() { }
virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; }
+ virtual bool DoYield(bool, long) { return true; }
DECLARE_NO_COPY_CLASS(wxDummyConsoleApp)
};
#endif
}
-
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
#if wxUSE_THREADS
if ( !wxThread::IsMain() )
}
m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
wxLog::Suspend();
void wxGUIEventLoop::Yield()
{
+ // TODO: implement event filtering using the eventsToProcess mask
+
// process all pending events:
while ( Pending() )
Dispatch();
m_msg->SetLabel(_("Done."));
}
- wxYieldIfNeeded();
+ wxTheApp->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
- wxYieldIfNeeded();
+ wxTheApp->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
Update();
Fit(); // adapt to the new label size
- wxYieldIfNeeded() ;
+ wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
}
}
//-----------------------------------------------------------------------------
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 )
{
#endif // wxUSE_THREADS
m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
wxLog::Suspend();
#endif
- while (EventsPending())
- gtk_main_iteration();
+ // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
+ // rather use gtk_main_do_event() after filtering the events at
+ // GDK level
- // It's necessary to call ProcessIdle() to update the frames sizes which
- // might have been changed (it also will update other things set from
- // OnUpdateUI() which is a nice (and desired) side effect). But we
- // call ProcessIdle() only once since this is not meant for longish
- // background jobs (controlled by wxIdleEvent::RequestMore() and the
- // return value of Processidle().
- ProcessIdle();
+ GdkDisplay* disp = gtk_widget_get_display(gs_RootWindow);
+
+ // gdk_display_get_event() will transform X11 events into GDK events
+ // and will queue all of them in the display (private) structure;
+ // finally it will "unqueue" the last one and return it to us
+ GdkEvent* event = gdk_display_get_event(disp);
+ while (event)
+ {
+ // categorize the GDK event according to wxEventCategory.
+ // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
+ // for more info.
+
+ wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
+ switch (event->type)
+ {
+ case GDK_SELECTION_REQUEST:
+ case GDK_SELECTION_NOTIFY:
+ case GDK_SELECTION_CLEAR:
+ case GDK_OWNER_CHANGE:
+ cat = wxEVT_CATEGORY_CLIPBOARD;
+ break;
+
+
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_SCROLL: // generated from mouse buttons
+ case GDK_CLIENT_EVENT:
+ cat = wxEVT_CATEGORY_USER_INPUT;
+ break;
+
+
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+
+ case GDK_MOTION_NOTIFY:
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ case GDK_VISIBILITY_NOTIFY:
+ case GDK_PROPERTY_NOTIFY:
+
+ case GDK_FOCUS_CHANGE:
+ case GDK_CONFIGURE:
+ case GDK_WINDOW_STATE:
+ case GDK_SETTING:
+ case GDK_DELETE:
+ case GDK_DESTROY:
+
+ case GDK_EXPOSE:
+ case GDK_NO_EXPOSE:
+ case GDK_MAP:
+ case GDK_UNMAP:
+ //case GDK_DAMAGE:
+
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DRAG_STATUS:
+ case GDK_DROP_START:
+ case GDK_DROP_FINISHED:
+ case GDK_GRAB_BROKEN:
+ cat = wxEVT_CATEGORY_UI;
+ break;
+
+ default:
+ cat = wxEVT_CATEGORY_UNKNOWN;
+ break;
+ }
+
+ if (eventsToProcess & cat)
+ gtk_main_do_event(event); // process it now
+ else
+ g_arrGdkEvents.Add(event); // process it later
+
+ // get next event
+ event = gdk_display_get_event(disp);
+ }
+
+ if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
+ {
+ // It's necessary to call ProcessIdle() to update the frames sizes which
+ // might have been changed (it also will update other things set from
+ // OnUpdateUI() which is a nice (and desired) side effect). But we
+ // call ProcessIdle() only once since this is not meant for longish
+ // background jobs (controlled by wxIdleEvent::RequestMore() and the
+ // return value of Processidle().
+ ProcessIdle(); // ProcessIdle() also calls ProcessPendingEvents()
+ }
+ //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
+ // the user app contains an UI update handler which calls wxClipboard::IsSupported,
+ // then we fall into a never-ending loop...
+
+ // put all unprocessed GDK events back in the queue
+ for (size_t i=0; i<g_arrGdkEvents.GetCount(); i++)
+ {
+ GdkEvent* ev = (GdkEvent*)g_arrGdkEvents[i];
+
+ // NOTE: gdk_display_put_event makes a copy of the event passed to it
+ gdk_display_put_event(disp, ev);
+ gdk_event_free(ev);
+ }
+
+ g_arrGdkEvents.Clear();
#if wxUSE_LOG
// let the logs be flashed again
~wxClipboardSync()
{
- while ( ms_clipboard )
- gtk_main_iteration();
+ while (ms_clipboard)
+ wxTheApp->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
}
// this method must be called by GTK+ callbacks to indicate that we got the
if (!clipboard->m_sink)
return;
-
+
wxClipboardEvent *event = new wxClipboardEvent(wxEVT_CLIPBOARD_CHANGED);
event->SetEventObject( clipboard );
-
+
if ( !selection_data || selection_data->length <= 0 )
{
clipboard->m_sink->QueueEvent( event );
event->AddFormat( format );
}
-
+
clipboard->m_sink->QueueEvent( event );
clipboard->m_sink.Release();
}
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 );
{
if (m_sink.get())
return false; // currently busy, come back later
-
+
wxCHECK_MSG( sink, false, wxT("no sink given") );
-
+
m_sink = sink;
gtk_selection_convert( m_targetsWidgetAsync,
GTKGetClipboardAtom(),
g_targetsAtom,
(guint32) GDK_CURRENT_TIME );
-
+
return true;
}
// wxYield
//-----------------------------------------------------------------------------
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
#endif // wxUSE_THREADS
m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
// We need to remove idle callbacks or the loop will
// never finish.
wxLog::Suspend();
#endif
+ // TODO: implement event filtering using the eventsToProcess mask
while (gtk_events_pending())
gtk_main_iteration();
// wxYield
//-----------------------------------------------------------------------------
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
#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();
}
// Yield to other processes
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
}
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;
// 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 )
{
// 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
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;
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS
- if ( !wxTheApp->Dispatch() )
- break;
+ 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;
}
#else // !wxUSE_GUI
+
+// ============================================================================
+// wxConsoleEventLoop implementation
+// ============================================================================
+
#if wxUSE_CONSOLE_EVENTLOOP
void wxConsoleEventLoop::WakeUp()
//
// Yield to incoming messages
//
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
if ( m_isInsideYield )
{
wxLog::Suspend();
m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
//
// We want to go back to the main message loop
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
// 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
}
m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// Yield to incoming messages
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
{
return true;
}
// 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
}
m_isInsideYield = true;
+ m_eventsToProcessInsideYield = eventsToProcess;
// Make sure we have an event loop object,
// or Pending/Dispatch will fail
// can be tested
wxTheApp->Dispatch();
+ // TODO: implement event filtering using the eventsToProcess mask
while (wxTheApp && wxTheApp->Pending())
wxTheApp->Dispatch();