use wxEventLoop in wxApp under wxMSW; factored out common code from wxX11/wxMotif/wxMGL to wxAppBase; changed wxApp::Dispatch() return type

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23609 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2003-09-15 19:48:16 +00:00
parent 4c9d78a4f9
commit 1bf77ee556
20 changed files with 145 additions and 345 deletions

View File

@ -32,6 +32,8 @@ class WXDLLIMPEXP_BASE wxCmdLineParser;
class WXDLLIMPEXP_BASE wxLog;
class WXDLLIMPEXP_BASE wxMessageOutput;
class WXDLLEXPORT wxEventLoop;
// ----------------------------------------------------------------------------
// typedefs
// ----------------------------------------------------------------------------
@ -367,24 +369,27 @@ public:
// -----------------------------------------------------------------
// execute the main GUI loop, the function returns when the loop ends
virtual int MainLoop() = 0;
virtual int MainLoop();
// exit the main loop thus terminating the application
virtual void Exit();
// exit the main GUI loop during the next iteration (i.e. it does not
// stop the program immediately!)
virtual void ExitMainLoop() = 0;
virtual void ExitMainLoop();
// returns TRUE if the program is initialized
// returns true if the program is initialized, i.e. OnInit() has been
// completed successfully
virtual bool Initialized() = 0;
// returns TRUE if there are unprocessed events in the event queue
virtual bool Pending() = 0;
virtual bool Pending();
// process the first event in the event queue (blocks until an event
// apperas if there are none currently)
virtual void Dispatch() = 0;
// 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();
// process all currently pending events right now
//
@ -402,7 +407,7 @@ public:
// parties
//
// it should return TRUE if more idle events are needed, FALSE if not
virtual bool ProcessIdle() ;
virtual bool ProcessIdle();
// Send idle event to window and all subwindows
// Returns TRUE if more idle time is requested.
@ -493,6 +498,10 @@ protected:
virtual wxAppTraits *CreateTraits();
// the main event loop of the application (may be NULL if the loop hasn't
// been started yet or has already terminated)
wxEventLoop *m_mainLoop;
// the main top level window (may be NULL)
wxWindow *m_topWindow;

View File

@ -50,7 +50,7 @@ public:
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
virtual void Dispatch();
virtual bool Dispatch();
virtual void Exit();

View File

@ -45,7 +45,7 @@ public:
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
virtual void Dispatch();
virtual bool Dispatch();
virtual void Exit();

View File

@ -45,7 +45,7 @@ public:
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
virtual void Dispatch();
virtual bool Dispatch();
virtual void Exit();

View File

@ -51,7 +51,7 @@ class WXDLLEXPORT wxApp: public wxAppBase
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending() ;
virtual void Dispatch() ;
virtual bool Dispatch() ;
virtual void Exit();

View File

@ -42,11 +42,7 @@ public:
virtual bool OnInitGui();
// override base class (pure) virtuals
virtual int MainLoop();
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
virtual void Dispatch();
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
@ -59,8 +55,7 @@ public:
private:
DECLARE_DYNAMIC_CLASS(wxApp)
DECLARE_EVENT_TABLE()
wxEventLoop *m_mainLoop;
wxDisplayModeInfo m_displayMode;
};

View File

@ -53,8 +53,6 @@ public:
virtual int MainLoop();
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
virtual void Dispatch();
virtual void Exit();

View File

@ -39,11 +39,7 @@ public:
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
virtual int MainLoop();
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
virtual void Dispatch();
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
@ -67,18 +63,6 @@ public:
static bool RegisterWindowClasses();
static bool UnregisterWindowClasses();
// message processing
// ------------------
// process the given message
virtual void DoMessage(WXMSG *pMsg);
// retrieve the next message from the queue and process it
virtual bool DoMessage();
// preprocess the message
virtual bool ProcessMessage(WXMSG* pMsg);
// idle processing
// ---------------
@ -98,9 +82,6 @@ public:
static int m_nCmdShow;
protected:
// we exit the main event loop when this flag becomes false
bool m_keepGoing;
DECLARE_EVENT_TABLE()
DECLARE_NO_COPY_CLASS(wxApp)
};

View File

@ -75,7 +75,7 @@ public:
virtual void ExitMainLoop(void);
virtual bool Initialized(void);
virtual bool Pending(void) ;
virtual void Dispatch(void);
virtual bool Dispatch(void);
virtual void Exit();

View File

@ -32,7 +32,6 @@ class WXDLLEXPORT wxWindow;
class WXDLLEXPORT wxApp;
class WXDLLEXPORT wxKeyEvent;
class WXDLLEXPORT wxLog;
class WXDLLEXPORT wxEventLoop;
class WXDLLEXPORT wxXVisualInfo;
// ----------------------------------------------------------------------------
@ -42,14 +41,14 @@ class WXDLLEXPORT wxXVisualInfo;
class WXDLLEXPORT wxApp : public wxAppBase
{
DECLARE_DYNAMIC_CLASS(wxApp)
public:
wxApp();
~wxApp();
// override base class (pure) virtuals
// -----------------------------------
virtual int MainLoop();
virtual void ExitMainLoop();
virtual bool Initialized();
@ -60,45 +59,45 @@ public:
virtual bool Yield(bool onlyIfNeeded = FALSE);
virtual void WakeUpIdle();
virtual bool OnInitGui();
// implementation from now on
// --------------------------
// Processes an X event.
virtual bool ProcessXEvent(WXEvent* event);
#ifdef __WXDEBUG__
virtual void OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg);
#endif // __WXDEBUG__
protected:
bool m_showOnInit;
public:
// Implementation
virtual bool Initialize(int& argc, wxChar **argv);
virtual void CleanUp();
WXWindow GetTopLevelWidget() const { return m_topLevelWidget; }
WXColormap GetMainColormap(WXDisplay* display);
long GetMaxRequestSize() const { return m_maxRequestSize; }
// This handler is called when a property change event occurs
virtual bool HandlePropertyChange(WXEvent *event);
// Values that can be passed on the command line.
// Returns -1, -1 if none specified.
const wxSize& GetInitialSize() const { return m_initialSize; }
bool GetShowIconic() const { return m_showIconic; }
#if wxUSE_UNICODE
// Global context for Pango layout. Either use X11
// or use Xft rendering according to GDK_USE_XFT
// environment variable
PangoContext* GetPangoContext();
#endif
#endif
wxXVisualInfo* GetVisualInfo(WXDisplay* display)
{
@ -113,21 +112,20 @@ public:
public:
static long sm_lastMessageTime;
bool m_showIconic;
bool m_showIconic;
wxSize m_initialSize;
#if !wxUSE_NANOX
wxXVisualInfo* m_visualInfo;
#endif
protected:
bool m_keepGoing;
WXWindow m_topLevelWidget;
WXColormap m_mainColormap;
long m_maxRequestSize;
wxEventLoop* m_mainLoop;
DECLARE_EVENT_TABLE()
};

View File

@ -273,8 +273,9 @@ bool wxApp::Pending()
}
// Dispatch a message.
void wxApp::Dispatch()
bool wxApp::Dispatch()
{
return true;
}
// Yield to other processes

View File

@ -41,9 +41,11 @@
#include "wx/apptrait.h"
#include "wx/cmdline.h"
#include "wx/evtloop.h"
#include "wx/msgout.h"
#include "wx/thread.h"
#include "wx/utils.h"
#include "wx/ptr_scpd.h"
#if defined(__WXMSW__)
#include "wx/msw/private.h" // includes windows.h for LOGFONT
@ -57,6 +59,30 @@
#include "wx/build.h"
WX_CHECK_BUILD_OPTIONS("wxCore")
// ----------------------------------------------------------------------------
// wxEventLoopPtr
// ----------------------------------------------------------------------------
// this defines wxEventLoopPtr
wxDEFINE_SCOPED_PTR_TYPE(wxEventLoop);
// but we need a smart pointer tied to wxAppBase::m_mainLoop, so we define
// another helper class
class wxTiedEventLoopPtr : public wxEventLoopPtr
{
public:
wxTiedEventLoopPtr(wxEventLoop **ppEvtLoop, wxEventLoop *pLoop)
: wxEventLoopPtr(*ppEvtLoop = pLoop), m_ppEvtLoop(ppEvtLoop)
{
}
~wxTiedEventLoopPtr() { *m_ppEvtLoop = NULL; }
private:
wxEventLoop **m_ppEvtLoop;
};
// ============================================================================
// wxAppBase implementation
// ============================================================================
@ -71,6 +97,8 @@ wxAppBase::wxAppBase()
m_useBestVisual = FALSE;
m_isActive = TRUE;
m_mainLoop = NULL;
// 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.
@ -236,6 +264,45 @@ bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser)
#endif // wxUSE_CMDLINE_PARSER
// ----------------------------------------------------------------------------
// main event loop implementation
// ----------------------------------------------------------------------------
int wxAppBase::MainLoop()
{
wxTiedEventLoopPtr mainLoop(&m_mainLoop, new wxEventLoop);
return m_mainLoop->Run();
}
void wxAppBase::ExitMainLoop()
{
// we should exit from the main event loop, not just any currently active
// (e.g. modal dialog) event loop
if ( m_mainLoop )
{
m_mainLoop->Exit(0);
}
}
bool wxAppBase::Pending()
{
// use the currently active message loop here, not m_mainLoop, because if
// we're showing a modal dialog (with its own event loop) currently the
// main event loop is not running anyhow
wxEventLoop * const loop = wxEventLoop::GetActive();
return loop && loop->Pending();
}
bool wxAppBase::Dispatch()
{
// see comment in Pending()
wxEventLoop * const loop = wxEventLoop::GetActive();
return loop ? loop->Dispatch() : true;
}
// ----------------------------------------------------------------------------
// OnXXX() hooks
// ----------------------------------------------------------------------------

View File

@ -567,9 +567,11 @@ bool wxApp::Pending()
return (gtk_events_pending() > 0);
}
void wxApp::Dispatch()
bool wxApp::Dispatch()
{
gtk_main_iteration();
return true;
}
bool wxApp::Initialize(int& argc, wxChar **argv)

View File

@ -567,9 +567,11 @@ bool wxApp::Pending()
return (gtk_events_pending() > 0);
}
void wxApp::Dispatch()
bool wxApp::Dispatch()
{
gtk_main_iteration();
return true;
}
bool wxApp::Initialize(int& argc, wxChar **argv)

View File

@ -1049,9 +1049,11 @@ bool wxApp::Pending()
}
// Dispatch a message.
void wxApp::Dispatch()
bool wxApp::Dispatch()
{
MacDoOneEvent() ;
return true;
}
void wxApp::OnIdle(wxIdleEvent& event)

View File

@ -1049,9 +1049,11 @@ bool wxApp::Pending()
}
// Dispatch a message.
void wxApp::Dispatch()
bool wxApp::Dispatch()
{
MacDoOneEvent() ;
return true;
}
void wxApp::OnIdle(wxIdleEvent& event)

View File

@ -272,37 +272,9 @@ bool wxApp::OnInitGui()
return TRUE;
}
int wxApp::MainLoop()
{
int rt;
m_mainLoop = new wxEventLoop;
rt = m_mainLoop->Run();
delete m_mainLoop;
m_mainLoop = NULL;
return rt;
}
void wxApp::ExitMainLoop()
{
if ( m_mainLoop )
m_mainLoop->Exit(0);
}
bool wxApp::Initialized()
{
return (wxTopLevelWindows.GetCount() != 0);
}
bool wxApp::Pending()
{
return wxEventLoop::GetActive()->Pending();
}
void wxApp::Dispatch()
{
wxEventLoop::GetActive()->Dispatch();
return wxTopLevelWindows.GetCount() != 0;
}
bool wxApp::Initialize(int& argc, wxChar **argv)

View File

@ -176,25 +176,6 @@ void wxApp::ExitMainLoop()
m_eventLoop->Exit();
}
// Is a message/event pending?
bool wxApp::Pending()
{
return m_eventLoop->Pending();
#if 0
XFlush(XtDisplay( (Widget) wxTheApp->GetTopLevelWidget() ));
// Fix by Doug from STI, to prevent a stall if non-X event
// is found.
return ((XtAppPending( (XtAppContext) GetAppContext() ) & XtIMXEvent) != 0) ;
#endif
}
// Dispatch a message.
void wxApp::Dispatch()
{
m_eventLoop->Dispatch();
}
// This should be redefined in a derived class for
// handling property change events for XAtom IPC.
void wxApp::HandlePropertyChange(WXEvent *event)

View File

@ -89,7 +89,7 @@
#if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
!defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
(!defined(_MSC_VER) || (_MSC_VER > 1100))
(!defined(_MSC_VER) || (_MSC_VER > 1100))
#include <shlwapi.h>
#endif
@ -103,8 +103,6 @@ extern wxList WXDLLEXPORT wxPendingDelete;
extern void wxSetKeyboardHook(bool doIt);
#endif
MSG s_currentMsg;
// NB: all "NoRedraw" classes must have the same names as the "normal" classes
// with NR suffix - wxWindow::MSWCreate() supposes this
const wxChar *wxCanvasClassName = wxT("wxWindowClass");
@ -200,12 +198,14 @@ void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
bool wxGUIAppTraits::DoMessageFromThreadWait()
{
return !wxTheApp || wxTheApp->DoMessage();
// we should return false only if the app should exit, i.e. only if
// Dispatch() determines that the main event loop should terminate
return !wxTheApp || wxTheApp->Dispatch();
}
wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
{
static wxToolkitInfo info;
static wxToolkitInfo info;
wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
info.versionMajor = baseInfo.versionMajor;
info.versionMinor = baseInfo.versionMinor;
@ -568,219 +568,6 @@ bool wxApp::Initialized()
#endif
}
/*
* Get and process a message, returning FALSE if WM_QUIT
* received (and also set the flag telling the app to exit the main loop)
*
*/
bool wxApp::DoMessage()
{
BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
if ( rc == 0 )
{
// got WM_QUIT
m_keepGoing = FALSE;
return FALSE;
}
else if ( rc == -1 )
{
// should never happen, but let's test for it nevertheless
wxLogLastError(wxT("GetMessage"));
}
else
{
#if wxUSE_THREADS
wxASSERT_MSG( wxThread::IsMain(),
wxT("only the main thread can process Windows messages") );
static bool s_hadGuiLock = TRUE;
static wxMsgArray s_aSavedMessages;
// if a secondary thread owns is doing GUI calls, save all messages for
// later processing - we can't process them right now because it will
// lead to recursive library calls (and we're not reentrant)
if ( !wxGuiOwnedByMainThread() )
{
s_hadGuiLock = FALSE;
// leave out WM_COMMAND messages: too dangerous, sometimes
// the message will be processed twice
if ( !wxIsWaitingForThread() ||
s_currentMsg.message != WM_COMMAND )
{
s_aSavedMessages.Add(s_currentMsg);
}
return TRUE;
}
else
{
// have we just regained the GUI lock? if so, post all of the saved
// messages
//
// FIXME of course, it's not _exactly_ the same as processing the
// messages normally - expect some things to break...
if ( !s_hadGuiLock )
{
s_hadGuiLock = TRUE;
size_t count = s_aSavedMessages.GetCount();
for ( size_t n = 0; n < count; n++ )
{
MSG& msg = s_aSavedMessages[n];
DoMessage((WXMSG *)&msg);
}
s_aSavedMessages.Empty();
}
}
#endif // wxUSE_THREADS
// Process the message
DoMessage((WXMSG *)&s_currentMsg);
}
return TRUE;
}
void wxApp::DoMessage(WXMSG *pMsg)
{
if ( !ProcessMessage(pMsg) )
{
::TranslateMessage((MSG *)pMsg);
::DispatchMessage((MSG *)pMsg);
}
}
/*
* Keep trying to process messages until WM_QUIT
* received.
*
* If there are messages to be processed, they will all be
* processed and OnIdle will not be called.
* When there are no more messages, OnIdle is called.
* If OnIdle requests more time,
* it will be repeatedly called so long as there are no pending messages.
* A 'feature' of this is that once OnIdle has decided that no more processing
* is required, then it won't get processing time until further messages
* are processed (it'll sit in DoMessage).
*/
int wxApp::MainLoop()
{
m_keepGoing = TRUE;
while ( m_keepGoing )
{
#if wxUSE_THREADS
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS
while ( !Pending() && ProcessIdle() )
;
// a message came or no more idle processing to do
DoMessage();
}
return s_currentMsg.wParam;
}
void wxApp::ExitMainLoop()
{
// this will set m_keepGoing to FALSE a bit later
::PostQuitMessage(0);
}
bool wxApp::Pending()
{
return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
}
void wxApp::Dispatch()
{
DoMessage();
}
/*
* Give all windows a chance to preprocess
* the message. Some may have accelerator tables, or have
* MDI complications.
*/
bool wxApp::ProcessMessage(WXMSG *wxmsg)
{
MSG *msg = (MSG *)wxmsg;
HWND hwnd = msg->hwnd;
wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
// this may happen if the event occured in a standard modeless dialog (the
// only example of which I know of is the find/replace dialog) - then call
// IsDialogMessage() to make TAB navigation in it work
if ( !wndThis )
{
// we need to find the dialog containing this control as
// IsDialogMessage() just eats all the messages (i.e. returns TRUE for
// them) if we call it for the control itself
while ( hwnd && ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )
{
hwnd = ::GetParent(hwnd);
}
return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
}
#if wxUSE_TOOLTIPS
// we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
// popup the tooltip bubbles
if ( (msg->message == WM_MOUSEMOVE) )
{
wxToolTip *tt = wndThis->GetToolTip();
if ( tt )
{
tt->RelayEvent(wxmsg);
}
}
#endif // wxUSE_TOOLTIPS
// allow the window to prevent certain messages from being
// translated/processed (this is currently used by wxTextCtrl to always
// grab Ctrl-C/V/X, even if they are also accelerators in some parent)
if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) )
{
return FALSE;
}
// try translations first: the accelerators override everything
wxWindow *wnd;
for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
{
if ( wnd->MSWTranslateMessage(wxmsg))
return TRUE;
// stop at first top level window, i.e. don't try to process the key
// strokes originating in a dialog using the accelerators of the parent
// frame - this doesn't make much sense
if ( wnd->IsTopLevel() )
break;
}
// now try the other hooks (kbd navigation is handled here): we start from
// wndThis->GetParent() because wndThis->MSWProcessMessage() was already
// called above
for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() )
{
if ( wnd->MSWProcessMessage(wxmsg) )
return TRUE;
}
// no special preprocessing for this message, dispatch it normally
return FALSE;
}
// this is a temporary hack and will be replaced by using wxEventLoop in the
// future
//
@ -796,7 +583,7 @@ void wxApp::OnIdle(wxIdleEvent& event)
return;
wxIsInOnIdleFlag = TRUE;
wxAppBase::OnIdle(event);
#if wxUSE_DC_CACHEING
@ -965,7 +752,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS
if ( !wxTheApp->DoMessage() )
if ( !wxTheApp->Dispatch() )
break;
}

View File

@ -162,9 +162,6 @@
// global variables
// ---------------------------------------------------------------------------
// the last Windows message we got (FIXME-MT)
extern MSG s_currentMsg;
#if wxUSE_MENUS_NATIVE
wxMenu *wxCurrentPopupMenu = NULL;
#endif // wxUSE_MENUS_NATIVE
@ -1750,15 +1747,21 @@ static void wxYieldForCommandsOnly()
// peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
// want to process it here)
MSG msg;
while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE)
&& msg.message != WM_QUIT )
while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
{
wxTheApp->DoMessage((WXMSG *)&msg);
}
if ( msg.message != WM_QUIT )
{
// if we retrieved a WM_QUIT, insert back into the message queue.
::PostQuitMessage(0);
break;
}
// If we retrieved a WM_QUIT, insert back into the message queue.
if (msg.message == WM_QUIT)
::PostQuitMessage(0);
// luckily (as we don't have access to wxEventLoopImpl method from here
// anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
// immediately
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
@ -4220,7 +4223,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
// so simply test for negative value.
event.m_altDown = ::GetKeyState(VK_MENU) < 0;
event.SetTimestamp(s_currentMsg.time);
event.SetTimestamp(::GetMessageTime());
event.m_eventObject = this;
event.SetId(GetId());
@ -4418,7 +4421,7 @@ wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
event.m_keyCode = id;
event.m_rawCode = (wxUint32) wParam;
event.m_rawFlags = (wxUint32) lParam;
event.SetTimestamp(s_currentMsg.time);
event.SetTimestamp(::GetMessageTime());
// translate the position to client coords
POINT pt;
@ -5092,7 +5095,7 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
event.m_keyCode = id;
event.m_shiftDown = wxIsShiftDown();
event.m_controlDown = wxIsCtrlDown();
event.SetTimestamp(s_currentMsg.time);
event.SetTimestamp(::GetMessageTime());
wxWindow *win = wxGetActiveWindow();
wxEvtHandler *handler;