class WXDLLIMPEXP_BASE wxLog;
class WXDLLIMPEXP_BASE wxMessageOutput;
+class WXDLLEXPORT wxEventLoop;
+
// ----------------------------------------------------------------------------
// typedefs
// ----------------------------------------------------------------------------
// -----------------------------------------------------------------
// 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
//
// 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.
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;
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
- virtual void Dispatch();
+ virtual bool Dispatch();
virtual void Exit();
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
- virtual void Dispatch();
+ virtual bool Dispatch();
virtual void Exit();
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending();
- virtual void Dispatch();
+ virtual bool Dispatch();
virtual void Exit();
virtual void ExitMainLoop();
virtual bool Initialized();
virtual bool Pending() ;
- virtual void Dispatch() ;
+ virtual bool Dispatch() ;
virtual void Exit();
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();
private:
DECLARE_DYNAMIC_CLASS(wxApp)
DECLARE_EVENT_TABLE()
-
- wxEventLoop *m_mainLoop;
+
wxDisplayModeInfo m_displayMode;
};
virtual int MainLoop();
virtual void ExitMainLoop();
virtual bool Initialized();
- virtual bool Pending();
- virtual void Dispatch();
virtual void Exit();
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();
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
// ---------------
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)
};
virtual void ExitMainLoop(void);
virtual bool Initialized(void);
virtual bool Pending(void) ;
- virtual void Dispatch(void);
+ virtual bool Dispatch(void);
virtual void Exit();
class WXDLLEXPORT wxApp;
class WXDLLEXPORT wxKeyEvent;
class WXDLLEXPORT wxLog;
-class WXDLLEXPORT wxEventLoop;
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();
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)
{
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()
};
}
// Dispatch a message.
-void wxApp::Dispatch()
+bool wxApp::Dispatch()
{
+ return true;
}
// Yield to other processes
#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
#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
// ============================================================================
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.
#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
// ----------------------------------------------------------------------------
return (gtk_events_pending() > 0);
}
-void wxApp::Dispatch()
+bool wxApp::Dispatch()
{
gtk_main_iteration();
+
+ return true;
}
bool wxApp::Initialize(int& argc, wxChar **argv)
return (gtk_events_pending() > 0);
}
-void wxApp::Dispatch()
+bool wxApp::Dispatch()
{
gtk_main_iteration();
+
+ return true;
}
bool wxApp::Initialize(int& argc, wxChar **argv)
}
// Dispatch a message.
-void wxApp::Dispatch()
+bool wxApp::Dispatch()
{
MacDoOneEvent() ;
+
+ return true;
}
void wxApp::OnIdle(wxIdleEvent& event)
}
// Dispatch a message.
-void wxApp::Dispatch()
+bool wxApp::Dispatch()
{
MacDoOneEvent() ;
+
+ return true;
}
void wxApp::OnIdle(wxIdleEvent& event)
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)
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)
#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
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");
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;
#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
//
return;
wxIsInOnIdleFlag = TRUE;
-
+
wxAppBase::OnIdle(event);
#if wxUSE_DC_CACHEING
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS
- if ( !wxTheApp->DoMessage() )
+ if ( !wxTheApp->Dispatch() )
break;
}
// 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
// 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)
// 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());
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;
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;