diff --git a/widget/src/windows/nsToolkit.cpp b/widget/src/windows/nsToolkit.cpp index d31836d282c9..4faf59008fdc 100644 --- a/widget/src/windows/nsToolkit.cpp +++ b/widget/src/windows/nsToolkit.cpp @@ -40,6 +40,9 @@ #include "prmon.h" #include "prtime.h" #include "nsGUIEvent.h" +#include "nsIServiceManager.h" +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" #ifdef MOZ_AIMM #include #include "aimm.h" @@ -63,6 +66,11 @@ NS_RegisterClass nsToolkit::mRegisterClass = &RegisterClassW; #endif +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +// Cached reference to event queue service +static nsCOMPtr gEventQueueService; + NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit) // @@ -438,6 +446,9 @@ nsToolkit::~nsToolkit() // Remove the TLS reference to the toolkit... PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); + // Remove reference to cached event queue + gEventQueueService = nsnull; + #ifdef MOZ_STATIC_COMPONENT_LIBS nsToolkit::Shutdown(); #endif @@ -536,6 +547,23 @@ nsToolkit::Shutdown() ::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance); } +nsIEventQueue* +nsToolkit::GetEventQueue() +{ + if (! gEventQueueService) { + gEventQueueService = do_GetService(kEventQueueServiceCID); + } + + if (gEventQueueService) { + nsCOMPtr eventQueue; + gEventQueueService->GetSpecialEventQueue( + nsIEventQueueService::UI_THREAD_EVENT_QUEUE, + getter_AddRefs(eventQueue)); + return eventQueue; + } + + return nsnull; +} //------------------------------------------------------------------------- // diff --git a/widget/src/windows/nsToolkit.h b/widget/src/windows/nsToolkit.h index 06ae072c8c90..65d961cbc6ca 100644 --- a/widget/src/windows/nsToolkit.h +++ b/widget/src/windows/nsToolkit.h @@ -50,6 +50,8 @@ struct IActiveIMMApp; #endif struct MethodInfo; +class nsIEventQueue; + /** * Wrapper around the thread running the message pump. @@ -72,6 +74,7 @@ class nsToolkit : public nsIToolkit PRThread* GetGuiThread(void) { return mGuiThread; } HWND GetDispatchWindow(void) { return mDispatchWnd; } void CreateInternalWindow(PRThread *aThread); + nsIEventQueue* GetEventQueue(void); private: ~nsToolkit(); diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index 365d0eeeb4bb..36d6b9f60d01 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -63,6 +63,7 @@ #include "nsIScreenManager.h" #include "nsRect.h" #include "nsTransform2D.h" +#include "nsIEventQueue.h" #include //#include @@ -3581,14 +3582,28 @@ BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg) return TRUE; } -// Check for starved paints and dispatch any pending paint +// Check for pending paints and dispatch any pending paint // messages for any nsIWidget which is a descendant of the // top-level window that *this* window is embedded within. -// Note: We do not dispatch pending messages for non nsIWidget -// managed windows. +// Also dispatch pending PL_Events to avoid PL_EventQueue starvation. +// Note: We do not dispatch pending paint messages for non +// nsIWidget managed windows. -void nsWindow::CheckForStarvedPaints() +void nsWindow::DispatchPendingEvents() { + // Need to flush all pending PL_Events before + // painting to prevent reflow events from being starved. + // Note: Unfortunately, The flushing of PL_Events can not done by + // dispatching the native WM_TIMER event that is used for PL_Event + // notification because the timer message will not appear in the + // native msg queue until 10ms after the event is posted. Which is too late. + nsCOMPtr eventQueue; + nsToolkit *toolkit = NS_STATIC_CAST(nsToolkit *, mToolkit); + eventQueue = toolkit->GetEventQueue(); + if (eventQueue) { + eventQueue->ProcessPendingEvents(); + } + // Quickly check to see if there are any // paint events pending. if (::GetQueueStatus(QS_PAINT)) { @@ -3790,7 +3805,6 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT printf("%s\t\twp=%x\tlp=%x\n", (WM_KEYUP==msg)?"WM_KEYUP":"WM_SYSKEYUP" , wParam, lParam); #endif - CheckForStarvedPaints(); mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT); if(WM_SYSKEYUP==msg) { @@ -3817,6 +3831,7 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT // ignore [shift+]alt+space so the OS can handle it if (mIsAltDown && !mIsControlDown && IS_VK_DOWN(NS_VK_SPACE)) { result = PR_FALSE; + DispatchPendingEvents(); break; } @@ -3824,6 +3839,8 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT result = OnKeyUp(wParam, (HIWORD(lParam)), lParam); else result = PR_FALSE; + + DispatchPendingEvents(); break; // Let ths fall through if it isn't a key pad @@ -3833,7 +3850,6 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT printf("%s\t\twp=%4x\tlp=%8x\n", (WM_KEYDOWN==msg)?"WM_KEYDOWN":"WM_SYSKEYDOWN" , wParam, lParam); #endif - CheckForStarvedPaints(); mIsShiftDown = IS_VK_DOWN(NS_VK_SHIFT); if(WM_SYSKEYDOWN==msg) @@ -3860,6 +3876,7 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT // ignore [shift+]alt+space so the OS can handle it if (mIsAltDown && !mIsControlDown && IS_VK_DOWN(NS_VK_SPACE)) { result = PR_FALSE; + DispatchPendingEvents(); break; } @@ -3884,6 +3901,7 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT result = PR_TRUE; *aRetValue = 0; } + DispatchPendingEvents(); break; // say we've dealt with erase background if widget does @@ -3903,20 +3921,24 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT case WM_MOUSEMOVE: //RelayMouseEvent(msg,wParam, lParam); - // Suppress synchronous painting of starved paint - // events when mouse moves are generated by widget + // Suppress dispatch of pending events + // when mouse moves are generated by widget // creation instead of user input. { POINT mp; DWORD pos = ::GetMessagePos(); mp.x = (short)LOWORD(pos); mp.y = (short)HIWORD(pos); + PRBool userMovedMouse = PR_FALSE; if ((gLastMouseMovePoint.x != mp.x) || (gLastMouseMovePoint.y != mp.y)) { - CheckForStarvedPaints(); + userMovedMouse = PR_TRUE; } result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam); + if (userMovedMouse) { + DispatchPendingEvents(); + } } break; @@ -3935,14 +3957,14 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT break; } #endif - CheckForStarvedPaints(); result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_DOWN, wParam); + DispatchPendingEvents(); } break; case WM_LBUTTONUP: //RelayMouseEvent(msg,wParam, lParam); - CheckForStarvedPaints(); result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_UP, wParam); + DispatchPendingEvents(); break; case WM_CONTEXTMENU: @@ -3971,13 +3993,13 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT break; } #endif - CheckForStarvedPaints(); result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_DOWN, wParam); + DispatchPendingEvents(); } break; case WM_MBUTTONUP: - CheckForStarvedPaints(); result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_UP, wParam); + DispatchPendingEvents(); break; case WM_MBUTTONDBLCLK: @@ -3997,13 +4019,13 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT break; } #endif - CheckForStarvedPaints(); result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_DOWN, wParam); + DispatchPendingEvents(); } break; case WM_RBUTTONUP: - CheckForStarvedPaints(); result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_UP, wParam); + DispatchPendingEvents(); break; case WM_RBUTTONDBLCLK: diff --git a/widget/src/windows/nsWindow.h b/widget/src/windows/nsWindow.h index 72ec675dae68..51bea41817af 100644 --- a/widget/src/windows/nsWindow.h +++ b/widget/src/windows/nsWindow.h @@ -401,7 +401,7 @@ protected: static nsWindow * GetNSWindowPtr(HWND aWnd); static BOOL SetNSWindowPtr(HWND aWnd, nsWindow * ptr); - void CheckForStarvedPaints(); + void DispatchPendingEvents(); virtual PRBool ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *aRetValue); virtual PRBool DispatchWindowEvent(nsGUIEvent* event); virtual PRBool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus);