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