diff --git a/include/wx/msw/app.h b/include/wx/msw/app.h index 90a612d06c..79431e92be 100644 --- a/include/wx/msw/app.h +++ b/include/wx/msw/app.h @@ -77,10 +77,25 @@ public: static void CleanUp(); static bool RegisterWindowClasses(); + // Convert Windows to argc, argv style void ConvertToStandardCommandArgs(char* p); + + // 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 + // --------------- + void DeletePendingObjects(); bool ProcessIdle(); diff --git a/src/msw/app.cpp b/src/msw/app.cpp index ed4d736788..5cbf84c3b7 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -957,16 +957,21 @@ bool wxApp::DoMessage() #endif // wxUSE_THREADS // Process the message - if ( !ProcessMessage((WXMSG *)&s_currentMsg) ) - { - ::TranslateMessage(&s_currentMsg); - ::DispatchMessage(&s_currentMsg); - } + 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. diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 7b171f9f7c..faf7da6136 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1484,6 +1484,23 @@ void wxWindow::GetCaretPos(int *x, int *y) const // popup menu // --------------------------------------------------------------------------- +// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue +// immediately, without waiting for the next event loop iteration +// +// NB: this function should probably be made public later as it can almost +// surely replace wxYield() elsewhere as well +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 ) + { + wxTheApp->DoMessage((WXMSG *)&msg); + } +} + bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) { menu->SetInvokingWindow(this); @@ -1497,7 +1514,16 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) ::ClientToScreen(hWnd, &point); wxCurrentPopupMenu = menu; ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); - wxYieldIfNeeded(); + + // we need to do it righ now as otherwise the events are never going to be + // sent to wxCurrentPopupMenu from HandleCommand() + // + // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't + // help and we'd still need wxYieldForCommandsOnly() as the menu may be + // destroyed as soon as we return (it can be a local variable in the caller + // for example) and so we do need to process the event immediately + wxYieldForCommandsOnly(); + wxCurrentPopupMenu = NULL; menu->SetInvokingWindow(NULL);