Bug 627084 - Add an app shell native event starvation timeout for cases where our native event pump messages get dropped by 3rd party code. r=roc
authorJim Mathies <jmathies@mozilla.com>
Tue, 09 Aug 2011 09:48:10 -0500
changeset 75237 3015d5cb3a9c493d3d53f828a2a42e1ea7d86419
parent 75236 13d1b63d5a696dafaa9c92391316c4edf7f2858c
child 75238 e9f6607a3990d027d09dcdc3395fe76be4ef9e6b
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs627084
milestone8.0a1
Bug 627084 - Add an app shell native event starvation timeout for cases where our native event pump messages get dropped by 3rd party code. r=roc
widget/src/windows/nsAppShell.cpp
widget/src/windows/nsAppShell.h
--- a/widget/src/windows/nsAppShell.cpp
+++ b/widget/src/windows/nsAppShell.cpp
@@ -49,16 +49,19 @@
 
 // For skidmark code
 #include <windows.h> 
 #include <tlhelp32.h> 
 
 const PRUnichar* kAppShellEventId = L"nsAppShell:EventID";
 const PRUnichar* kTaskbarButtonEventId = L"TaskbarButtonCreated";
 
+// The maximum time we allow before forcing a native event callback
+#define NATIVE_EVENT_STARVATION_LIMIT mozilla::TimeDuration::FromSeconds(1)
+
 static UINT sMsgId;
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
 static UINT sTaskbarButtonCreatedMsg;
 
 /* static */
 UINT nsAppShell::GetTaskbarButtonCreatedMessage() {
 	return sTaskbarButtonCreatedMsg;
@@ -130,16 +133,18 @@ nsAppShell::~nsAppShell()
 
 nsresult
 nsAppShell::Init()
 {
 #ifdef MOZ_CRASHREPORTER
   LSPAnnotate();
 #endif
 
+  mLastNativeEventScheduled = TimeStamp::Now();
+
   if (!sMsgId)
     sMsgId = RegisterWindowMessageW(kAppShellEventId);
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
   sTaskbarButtonCreatedMsg = ::RegisterWindowMessageW(kTaskbarButtonEventId);
   NS_ASSERTION(sTaskbarButtonCreatedMsg, "Could not register taskbar button creation message");
 
   // Global app registration id for Win7 and up. See
@@ -301,16 +306,19 @@ nsAppShell::DoProcessMoreGeckoEvents()
   }
 }
 
 void
 nsAppShell::ScheduleNativeEventCallback()
 {
   // Post a message to the hidden message window
   NS_ADDREF_THIS(); // will be released when the event is processed
+  // Time stamp this event so we can detect cases where the event gets
+  // dropping in sub classes / modal loops we do not control. 
+  mLastNativeEventScheduled = TimeStamp::Now();
   ::PostMessage(mEventWnd, sMsgId, 0, reinterpret_cast<LPARAM>(this));
 }
 
 PRBool
 nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
 {
 #if defined(_MSC_VER) && defined(_M_IX86)
   if (sXPCOMHasLoadedNewDLLs && sLoadedModules) {
@@ -343,10 +351,17 @@ nsAppShell::ProcessNextNativeEvent(PRBoo
     }
   } while (!gotMessage && mayWait);
 
   // See DoProcessNextNativeEvent, mEventloopNestingLevel will be
   // one when a modal loop unwinds.
   if (mNativeCallbackPending && mEventloopNestingLevel == 1)
     DoProcessMoreGeckoEvents();
 
+  // Check for starved native callbacks. If we haven't processed one
+  // of these events in NATIVE_EVENT_STARVATION_LIMIT, fire one off.
+  if ((TimeStamp::Now() - mLastNativeEventScheduled) >
+      NATIVE_EVENT_STARVATION_LIMIT) {
+    ScheduleNativeEventCallback();
+  }
+  
   return gotMessage;
 }
--- a/widget/src/windows/nsAppShell.h
+++ b/widget/src/windows/nsAppShell.h
@@ -35,27 +35,29 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAppShell_h__
 #define nsAppShell_h__
 
 #include "nsBaseAppShell.h"
 #include <windows.h>
+#include "mozilla/TimeStamp.h"
 
 /**
  * Native Win32 Application shell wrapper
  */
 class nsAppShell : public nsBaseAppShell
 {
 public:
   nsAppShell() :
     mEventWnd(NULL),
     mNativeCallbackPending(PR_FALSE)
   {}
+  typedef mozilla::TimeStamp TimeStamp;
 
   nsresult Init();
   void DoProcessMoreGeckoEvents();
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
   static UINT GetTaskbarButtonCreatedMessage();
 #endif
 
@@ -67,11 +69,12 @@ protected:
   virtual PRBool ProcessNextNativeEvent(PRBool mayWait);
   virtual ~nsAppShell();
 
   static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
 
 protected:
   HWND mEventWnd;
   PRBool mNativeCallbackPending;
+  TimeStamp mLastNativeEventScheduled;
 };
 
 #endif // nsAppShell_h__