diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index 79c3d6dbba4..e5d68d9834b 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -60,6 +60,7 @@ #include "nsIPresShell.h" #include "nsIPresContext.h" #include "nsIViewManager.h" +#include "nsIWidget.h" #include "nsIContentViewer.h" #include "nsIMarkupDocumentViewer.h" #include "nsINodeInfo.h" @@ -4054,7 +4055,15 @@ HTMLContentSink::DidProcessAToken(void) shell->GetViewManager(getter_AddRefs(vm)); NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE); PRUint32 eventTime; - nsresult rv = vm->GetLastUserEventTime(eventTime); + nsCOMPtr widget; + nsresult rv = vm->GetWidget(getter_AddRefs(widget)); + if (!widget || NS_FAILED(widget->GetLastInputEventTime(eventTime))) { + // If we can't get the last input time from the widget + // then we will get it from the viewmanager. + rv = vm->GetLastUserEventTime(eventTime); + NS_ENSURE_TRUE(NS_SUCCEEDED(rv), NS_ERROR_FAILURE); + } + NS_ENSURE_TRUE(NS_SUCCEEDED(rv), NS_ERROR_FAILURE); if ((!(mFlags & NS_SINK_FLAG_DYNAMIC_LOWER_VALUE)) && diff --git a/mozilla/widget/public/nsIWidget.h b/mozilla/widget/public/nsIWidget.h index 1e11a3010f9..ccdaebfeed0 100644 --- a/mozilla/widget/public/nsIWidget.h +++ b/mozilla/widget/public/nsIWidget.h @@ -894,6 +894,18 @@ class nsIWidget : public nsISupports { */ NS_IMETHOD GetAttention() = 0; + /** + * Get the last user input event time in milliseconds. If there are any pending + * native toolkit input events it returns the current time. All input events are + * included (ie. it is *not* limited to events targeted at this nsIWidget instance. + * + * @param aTime Last user input time in milliseconds. This value can be used to compare + * durations but can not be used for determining wall clock time. The value returned + * is platform dependent, but is compatible with the expression + * PR_IntervalToMicroseconds(PR_IntervalNow()). + */ + NS_IMETHOD GetLastInputEventTime(PRUint32& aTime) = 0; + }; #endif // nsIWidget_h__ diff --git a/mozilla/widget/src/windows/nsToolkit.cpp b/mozilla/widget/src/windows/nsToolkit.cpp index 4faf59008fd..b6d40f19b19 100644 --- a/mozilla/widget/src/windows/nsToolkit.cpp +++ b/mozilla/widget/src/windows/nsToolkit.cpp @@ -40,6 +40,7 @@ #include "prmon.h" #include "prtime.h" #include "nsGUIEvent.h" +#include "plevent.h" #include "nsIServiceManager.h" #include "nsIEventQueueService.h" #include "nsIEventQueue.h" @@ -73,12 +74,20 @@ static nsCOMPtr gEventQueueService; NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit) +// If PR_TRUE the user is currently moving a top level window. +static PRBool gIsMovingWindow = PR_FALSE; + +// Message filter used to determine if the user is currently +// moving a top-level window. +static HHOOK nsMsgFilterHook = NULL; + // // Static thread local storage index of the Toolkit // object associated with a given thread... // static PRUintn gToolkitTLSIndex = 0; + HINSTANCE nsToolkit::mDllInstance = 0; PRBool nsToolkit::mIsNT = PR_FALSE; PRBool nsToolkit::mUseImeApiW = PR_FALSE; @@ -171,6 +180,37 @@ void RunPump(void* arg) #endif } +/* Detect when the user is moving a top-level window */ + +LRESULT CALLBACK DetectWindowMove(int code, WPARAM wParam, LPARAM lParam) +{ + /* This msg filter is required to determine when the user has + * clicked in the window title bar and is moving the window. + */ + + CWPSTRUCT* sysMsg = (CWPSTRUCT*)lParam; + if (sysMsg) { + if (sysMsg->message == WM_ENTERSIZEMOVE) { + gIsMovingWindow = PR_TRUE; + // Notify xpcom that it should favor interactivity + // over performance because the user is moving a + // window + PL_FavorPerformanceHint(PR_FALSE, 0); + } else if (sysMsg->message == WM_EXITSIZEMOVE) { + gIsMovingWindow = PR_FALSE; + // Notify xpcom that it should go back to its + // previous performance setting which may favor + // performance over interactivity + PL_FavorPerformanceHint(PR_TRUE, 0); + } + } + + return CallNextHookEx(nsMsgFilterHook, code, wParam, lParam); +} + + + + #ifdef MOZ_UNICODE #define MAX_CLASS_NAME 128 @@ -449,6 +489,13 @@ nsToolkit::~nsToolkit() // Remove reference to cached event queue gEventQueueService = nsnull; + // Unhook the filter used to determine when + // the user is moving a top-level window. + if (nsMsgFilterHook != NULL) { + UnhookWindowsHookEx(nsMsgFilterHook); + nsMsgFilterHook = NULL; + } + #ifdef MOZ_STATIC_COMPONENT_LIBS nsToolkit::Shutdown(); #endif @@ -648,9 +695,21 @@ NS_METHOD nsToolkit::Init(PRThread *aThread) // create a thread where the message pump will run CreateUIThread(); } + + // Hook window move messages so the toolkit can report when + // the user is moving a top-level window. + if (nsMsgFilterHook == NULL) { + nsMsgFilterHook = SetWindowsHookEx(WH_CALLWNDPROC, DetectWindowMove, + NULL, GetCurrentThreadId()); + } + return NS_OK; } +PRBool nsToolkit::UserIsMovingWindow(void) +{ + return gIsMovingWindow; +} //------------------------------------------------------------------------- // @@ -897,3 +956,4 @@ void CALLBACK MouseTrailer::TimerProc(HWND hWnd, UINT msg, UINT event, DWORD tim } + diff --git a/mozilla/widget/src/windows/nsToolkit.h b/mozilla/widget/src/windows/nsToolkit.h index 65d961cbc6c..0b6af04e214 100644 --- a/mozilla/widget/src/windows/nsToolkit.h +++ b/mozilla/widget/src/windows/nsToolkit.h @@ -74,6 +74,8 @@ class nsToolkit : public nsIToolkit PRThread* GetGuiThread(void) { return mGuiThread; } HWND GetDispatchWindow(void) { return mDispatchWnd; } void CreateInternalWindow(PRThread *aThread); + // Return whether the user is currently moving any application window + PRBool UserIsMovingWindow(void); nsIEventQueue* GetEventQueue(void); private: diff --git a/mozilla/widget/src/windows/nsWindow.cpp b/mozilla/widget/src/windows/nsWindow.cpp index 0ea666a3def..3c6684d5685 100644 --- a/mozilla/widget/src/windows/nsWindow.cpp +++ b/mozilla/widget/src/windows/nsWindow.cpp @@ -51,6 +51,7 @@ #endif #include "nsWindow.h" +#include "plevent.h" #include "nsIAppShell.h" #include "nsIFontMetrics.h" #include "nsIFontEnumerator.h" @@ -185,6 +186,7 @@ UINT nsWindow::uWM_MSIME_MOUSE = 0; // mouse messge for MSIME UINT nsWindow::uWM_ATOK_RECONVERT = 0; // reconvert messge for ATOK UINT nsWindow::uWM_HEAP_DUMP = 0; // Heap Dump to a file + #ifdef ACCESSIBILITY BOOL nsWindow::gIsAccessibilityOn = FALSE; #endif @@ -222,6 +224,11 @@ static LONG gLastMouseDownTime = 0L; static LONG gLastClickCount = 0L; //////////////////////////////////////////////////// +// The last user input event time in milliseconds. If there are any pending +// native toolkit input events it returns the current time. The value is +// compatible with PR_IntervalToMicroseconds(PR_IntervalNow()). +static PRUint32 gLastInputEventTime = 0; + #if 0 static PRBool is_vk_down(int vk) { @@ -3608,6 +3615,8 @@ BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg) void nsWindow::DispatchPendingEvents() { + gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow()); + // 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 @@ -6811,6 +6820,26 @@ nsWindow::GetAttention() { return NS_OK; } +NS_IMETHODIMP +nsWindow::GetLastInputEventTime(PRUint32& aTime) +{ + WORD qstatus = HIWORD(GetQueueStatus(QS_INPUT)); + + // If there is pending input or the user is currently + // moving the window then return the current time. + // Note: When the user is moving the window WIN32 spins + // a separate event loop and input events are not + // reported to the application. + nsToolkit* toolkit = (nsToolkit *)mToolkit; + if (qstatus || (toolkit && toolkit->UserIsMovingWindow())) { + gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow()); + } + + aTime = gLastInputEventTime; + + return NS_OK; +} + //------------------------------------------------------------------------- //------------------------------------------------------------------------- //-- NOTE!!! These hook functions can be removed when we migrate to diff --git a/mozilla/widget/src/windows/nsWindow.h b/mozilla/widget/src/windows/nsWindow.h index b1403583104..0d62f7f7332 100644 --- a/mozilla/widget/src/windows/nsWindow.h +++ b/mozilla/widget/src/windows/nsWindow.h @@ -369,6 +369,7 @@ public: NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent); NS_IMETHOD GetAttention(); + NS_IMETHOD GetLastInputEventTime(PRUint32& aTime); // nsIKBStateControl interface diff --git a/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp b/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp index 5071e255619..5a8024b6967 100644 --- a/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp @@ -823,6 +823,11 @@ nsBaseWidget::GetAttention() { return NS_OK; } +NS_IMETHODIMP +nsBaseWidget::GetLastInputEventTime(PRUint32& aTime) { + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP nsBaseWidget::SetIcon(const nsAString&) { diff --git a/mozilla/widget/src/xpwidgets/nsBaseWidget.h b/mozilla/widget/src/xpwidgets/nsBaseWidget.h index 62d64e5cb18..f4fd102e61f 100644 --- a/mozilla/widget/src/xpwidgets/nsBaseWidget.h +++ b/mozilla/widget/src/xpwidgets/nsBaseWidget.h @@ -124,6 +124,7 @@ public: NS_IMETHOD ScrollWidgets(PRInt32 aDx, PRInt32 aDy); NS_IMETHOD EnableDragDrop(PRBool aEnable); NS_IMETHOD GetAttention(); + NS_IMETHOD GetLastInputEventTime(PRUint32& aTime); NS_IMETHOD SetIcon(const nsAString &anIconSpec); virtual void ConvertToDeviceCoordinates(nscoord &aX,nscoord &aY) {} virtual void FreeNativeData(void * data, PRUint32 aDataType) {}//~~~ diff --git a/mozilla/xpcom/threads/plevent.c b/mozilla/xpcom/threads/plevent.c index 6ea2ef4f296..738f51ea053 100644 --- a/mozilla/xpcom/threads/plevent.c +++ b/mozilla/xpcom/threads/plevent.c @@ -99,10 +99,8 @@ #define WIN9X_PAINT_STARVATION_LIMIT 3000 #define TIMER_ID 0 -static HHOOK _md_MouseMsgFilterHook = NULL; -static PRBool _md_MovingWindow = PR_FALSE; -static PRInt32 _md_WindowCount = 0; -static PRBool _md_FavorPerformance = PR_FALSE; +/* If _md_PerformanceSetting <=0 then no event starvation otherwise events will be starved */ +static PRInt32 _md_PerformanceSetting = 0; static PRUint32 _md_StarvationDelay = 0; static PRUint32 _md_SwitchTime = 0; #endif @@ -721,12 +719,23 @@ PR_IMPLEMENT(void) PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay) { #if defined(_WIN32) - _md_FavorPerformance = favorPerformanceOverEventStarvation; - _md_StarvationDelay = starvationDelay; - if (! favorPerformanceOverEventStarvation) { - _md_SwitchTime = PR_IntervalToMilliseconds(PR_IntervalNow()); + _md_StarvationDelay = starvationDelay; + + if (favorPerformanceOverEventStarvation) { + _md_PerformanceSetting++; + return; } + + _md_PerformanceSetting--; + + if (_md_PerformanceSetting == 0) { + /* Switched from allowing event starvation to no event starvation so grab + the current time to determine when to actually switch to using timers + instead of posted WM_APP messages. */ + _md_SwitchTime = PR_IntervalToMilliseconds(PR_IntervalNow()); + } + #endif } @@ -890,11 +899,6 @@ _pl_CleanupNativeNotifier(PLEventQueue* self) } RemoveProp(self->eventReceiverWindow, _md_GetEventQueuePropName()); DestroyWindow(self->eventReceiverWindow); - _md_WindowCount--; - if ((_md_WindowCount <= 0) && (_md_MouseMsgFilterHook != NULL)) { - UnhookWindowsHookEx(_md_MouseMsgFilterHook); - _md_MouseMsgFilterHook = NULL; - } #elif defined(XP_OS2) WinDestroyWindow(self->eventReceiverWindow); #endif @@ -1048,14 +1052,16 @@ _pl_NativeNotify(PLEventQueue* self) PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow()); - if (_md_MovingWindow || - (! _md_FavorPerformance) && + /* Since calls to set the _md_PerformanceSetting can be nested + * only performance setting values <= 0 will potentially trigger + * the use of a timer. + */ + if ((_md_PerformanceSetting <= 0) && ((now - _md_SwitchTime) > _md_StarvationDelay)) { SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); self->timerSet = PR_TRUE; _md_WasInputPending = PR_FALSE; _md_WasPaintPending = PR_FALSE; - return PR_SUCCESS; } @@ -1360,29 +1366,6 @@ static PRStatus InitEventLib( void ) #if defined(_WIN32) -/* Detect when the user is moving a top-level window */ - -LRESULT CALLBACK _md_DetectWindowMove(int code, WPARAM wParam, LPARAM lParam) -{ - /* This msg filter is required to determine when the user has - * clicked in the window title bar and is moving the window. - * This is necessary because there aren't any pending - * input events reported while Windows spins the modal message loop - * used when moving a top-level window. - */ - - CWPSTRUCT* sysMsg = (CWPSTRUCT*)lParam; - if (sysMsg) { - if (sysMsg->message == WM_ENTERSIZEMOVE) { - _md_MovingWindow = PR_TRUE; - } else if (sysMsg->message == WM_EXITSIZEMOVE) { - _md_MovingWindow = PR_FALSE; - } - } - - return CallNextHookEx(_md_MouseMsgFilterHook, code, wParam, lParam); -} - /* ** _md_CreateEventQueue() -- ModelDependent initializer */ @@ -1431,15 +1414,6 @@ static void _md_CreateEventQueue( PLEventQueue *eventQueue ) SetProp(eventQueue->eventReceiverWindow, _md_GetEventQueuePropName(), (HANDLE)eventQueue); - /* Setup a message hook to detect when the user is moving - * a top level window - */ - _md_WindowCount++; - if (_md_MouseMsgFilterHook == NULL) { - _md_MouseMsgFilterHook = SetWindowsHookEx(WH_CALLWNDPROC, _md_DetectWindowMove, - NULL, GetCurrentThreadId()); - } - return; } /* end _md_CreateEventQueue() */ #endif /* Winxx */ diff --git a/mozilla/xpcom/threads/plevent.h b/mozilla/xpcom/threads/plevent.h index 58bdc00ff1b..5b9eb465cd2 100644 --- a/mozilla/xpcom/threads/plevent.h +++ b/mozilla/xpcom/threads/plevent.h @@ -463,7 +463,12 @@ PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); * Give hint to native PL_Event notification mechanism. If the native * platform needs to tradeoff performance vs. native event starvation * this hint tells the native dispatch code which to favor. - * The default is to prevent event starvation. + * The default is to prevent event starvation. + * + * Calls to this function may be nested. When the number of calls that + * pass PR_TRUE is subtracted from the number of calls that pass PR_FALSE + * is greater than 0, performance is given precedence over preventing + * event starvation. * * The starvationDelay arg is only used when * favorPerformanceOverEventStarvation is PR_FALSE. It is the @@ -524,7 +529,6 @@ PR_EXTERN(HWND) PL_GetNativeEventReceiverWindow( PLEventQueue *eqp ); - #endif /* XP_PC */ #ifdef XP_UNIX