Bug 701760, merge <select> and popup manager rollup handling, so that select elements don't cancel out any popup rollup listeners, r=mats
authorNeil Deakin <neil@mozilla.com>
Fri, 26 Oct 2012 09:15:22 -0400
changeset 120177 6a9691cfc118dc485a8df23c46738c55a4708401
parent 120176 97d5111dfb395b51870fd7e6c247a65d00c2da15
child 120178 4d180e495354298b838ea855cda5bab9389bd145
push id273
push userlsblakk@mozilla.com
push dateThu, 14 Feb 2013 23:19:38 +0000
treeherdermozilla-release@c5e807a3f8b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs701760
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 701760, merge <select> and popup manager rollup handling, so that select elements don't cancel out any popup rollup listeners, r=mats
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsComboboxControlFrame.h
layout/xul/base/public/nsXULPopupManager.h
layout/xul/base/src/nsXULPopupManager.cpp
widget/android/nsWindow.h
widget/cocoa/nsAppShell.mm
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/cocoa/nsMenuX.mm
widget/cocoa/nsToolkit.mm
widget/gonk/nsWindow.h
widget/gtk2/nsWindow.cpp
widget/gtk2/nsWindow.h
widget/nsIRollupListener.h
widget/nsIWidget.h
widget/os2/nsWindow.cpp
widget/os2/os2FrameWindow.cpp
widget/qt/nsWindow.cpp
widget/qt/nsWindow.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
widget/xpwidgets/PuppetWidget.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -420,17 +420,17 @@ nsComboboxControlFrame::ShowList(bool aS
 
   nsIFrame* listFrame = do_QueryFrame(mListControlFrame);
   if (listFrame) {
     nsIView* view = listFrame->GetView();
     NS_ASSERTION(view, "nsComboboxControlFrame view is null");
     if (view) {
       nsIWidget* widget = view->GetWidget();
       if (widget) {
-        widget->CaptureRollupEvents(this, mDroppedDown, mDroppedDown);
+        widget->CaptureRollupEvents(this, mDroppedDown);
 
         if (!aShowList) {
           nsCOMPtr<nsIRunnable> widgetDestroyer =
             new DestroyWidgetRunnable(GetContent());
           NS_DispatchToMainThread(widgetDestroyer);
         }
       }
     }
@@ -1451,17 +1451,17 @@ nsComboboxControlFrame::DestroyFrom(nsIF
     // Get parent view
     nsIFrame * listFrame = do_QueryFrame(mListControlFrame);
     if (listFrame) {
       nsIView* view = listFrame->GetView();
       NS_ASSERTION(view, "nsComboboxControlFrame view is null");
       if (view) {
         nsIWidget* widget = view->GetWidget();
         if (widget)
-          widget->CaptureRollupEvents(this, false, true);
+          widget->CaptureRollupEvents(this, false);
       }
     }
   }
 
   // Cleanup frames in popup child list
   mPopupFrames.DestroyFramesFrom(aDestructRoot);
   nsContentUtils::DestroyAnonymousContent(&mDisplayContent);
   nsContentUtils::DestroyAnonymousContent(&mButtonContent);
@@ -1504,31 +1504,44 @@ nsComboboxControlFrame::SetInitialChildL
     rv = nsBlockFrame::SetInitialChildList(aListID, aChildList);
   }
   return rv;
 }
 
 //----------------------------------------------------------------------
   //nsIRollupListener
 //----------------------------------------------------------------------
-nsIContent*
-nsComboboxControlFrame::Rollup(uint32_t aCount, bool aGetLastRolledUp)
+bool
+nsComboboxControlFrame::Rollup(uint32_t aCount, nsIContent** aLastRolledUp)
 {
-  if (mDroppedDown) {
-    nsWeakFrame weakFrame(this);
-    mListControlFrame->AboutToRollup(); // might destroy us
-    if (!weakFrame.IsAlive())
-      return nullptr;
-    ShowDropDown(false); // might destroy us
-    if (!weakFrame.IsAlive())
-      return nullptr;
+  if (!mDroppedDown)
+    return false;
+
+  nsWeakFrame weakFrame(this);
+  mListControlFrame->AboutToRollup(); // might destroy us
+  if (!weakFrame.IsAlive())
+    return true;
+  ShowDropDown(false); // might destroy us
+  if (weakFrame.IsAlive()) {
     mListControlFrame->CaptureMouseEvents(false);
   }
 
-  return nullptr;
+  return true;
+}
+
+nsIWidget*
+nsComboboxControlFrame::GetRollupWidget()
+{
+  nsIFrame* listFrame = do_QueryFrame(mListControlFrame);
+  if (!listFrame)
+    return nullptr;
+
+  nsIView* view = listFrame->GetView();
+  MOZ_ASSERT(view);
+  return view->GetWidget();
 }
 
 void
 nsComboboxControlFrame::RollupFromList()
 {
   if (ShowList(false))
     mListControlFrame->CaptureMouseEvents(false);
 }
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -163,17 +163,17 @@ public:
   NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) MOZ_OVERRIDE;
   NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE;
 
   //nsIRollupListener
   /**
    * Hide the dropdown menu and stop capturing mouse events.
    * @note This method might destroy |this|.
    */
-  virtual nsIContent* Rollup(uint32_t aCount, bool aGetLastRolledUp = false);
+  virtual bool Rollup(uint32_t aCount, nsIContent** aLastRolledUp);
   virtual void NotifyGeometryChange();
 
   /**
    * A combobox should roll up if a mousewheel event happens outside of
    * the popup area.
    */
   virtual bool ShouldRollupOnMouseWheelEvent()
     { return true; }
@@ -183,16 +183,18 @@ public:
    * (eg. X-mouse).
    */
   virtual bool ShouldRollupOnMouseActivate()
     { return false; }
 
   virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain)
     { return 0; }
 
+  virtual nsIWidget* GetRollupWidget();
+
   //nsIStatefulFrame
   NS_IMETHOD SaveState(SpecialStateID aStateID, nsPresState** aState) MOZ_OVERRIDE;
   NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE;
 
   static bool ToolkitHasNativePopup();
 
 protected:
   friend class RedisplayTextEvent;
--- a/layout/xul/base/public/nsXULPopupManager.h
+++ b/layout/xul/base/public/nsXULPopupManager.h
@@ -281,21 +281,22 @@ public:
   friend class nsXULMenuCommandEvent;
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIDOMEVENTLISTENER
 
   // nsIRollupListener
-  virtual nsIContent* Rollup(uint32_t aCount, bool aGetLastRolledUp = false);
+  virtual bool Rollup(uint32_t aCount, nsIContent** aLastRolledUp);
   virtual bool ShouldRollupOnMouseWheelEvent();
   virtual bool ShouldRollupOnMouseActivate();
   virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain);
   virtual void NotifyGeometryChange() {}
+  virtual nsIWidget* GetRollupWidget();
 
   static nsXULPopupManager* sInstance;
 
   // initialize and shutdown methods called by nsLayoutStatics
   static nsresult Init();
   static void Shutdown();
 
   // returns a weak reference to the popup manager instance, could return null
--- a/layout/xul/base/src/nsXULPopupManager.cpp
+++ b/layout/xul/base/src/nsXULPopupManager.cpp
@@ -159,58 +159,61 @@ nsXULPopupManager::Observe(nsISupports *
   }
 
   return NS_OK;
 }
 
 nsXULPopupManager*
 nsXULPopupManager::GetInstance()
 {
+  MOZ_ASSERT(sInstance);
   return sInstance;
 }
 
-nsIContent*
-nsXULPopupManager::Rollup(uint32_t aCount, bool aGetLastRolledUp)
+bool
+nsXULPopupManager::Rollup(uint32_t aCount, nsIContent** aLastRolledUp)
 {
-  nsIContent* lastRolledUpPopup = nullptr;
+  bool consume = false;
 
   nsMenuChainItem* item = GetTopVisibleMenu();
   if (item) {
-    if (aGetLastRolledUp) {
+    if (aLastRolledUp) {
       // we need to get the popup that will be closed last, so that
       // widget can keep track of it so it doesn't reopen if a mouse
       // down event is going to processed.
       // Keep going up the menu chain to get the first level menu. This will
       // be the one that closes up last. It's possible that this menu doesn't
       // end up closing because the popuphiding event was cancelled, but in
       // that case we don't need to deal with the menu reopening as it will
       // already still be open.
       nsMenuChainItem* first = item;
       while (first->GetParent())
         first = first->GetParent();
-      lastRolledUpPopup = first->Content();
+      *aLastRolledUp = first->Content();
     }
 
+    consume = item->Frame()->ConsumeOutsideClicks();
+
     // if a number of popups to close has been specified, determine the last
     // popup to close
     nsIContent* lastPopup = nullptr;
     if (aCount != UINT32_MAX) {
       nsMenuChainItem* last = item;
       while (--aCount && last->GetParent()) {
         last = last->GetParent();
       }
       if (last) {
         lastPopup = last->Content();
       }
     }
 
     HidePopup(item->Content(), true, true, false, lastPopup);
   }
 
-  return lastRolledUpPopup;
+  return consume;
 }
 
 ////////////////////////////////////////////////////////////////////////
 bool nsXULPopupManager::ShouldRollupOnMouseWheelEvent()
 {
   // should rollup only for autocomplete widgets
   // XXXndeakin this should really be something the popup has more control over
 
@@ -259,16 +262,23 @@ nsXULPopupManager::GetSubmenuWidgetChain
       }
     }
     item = parent;
   }
 
   return sameTypeCount;
 }
 
+nsIWidget*
+nsXULPopupManager::GetRollupWidget()
+{
+  nsMenuChainItem* item = GetTopVisibleMenu();
+  return item ? item->Frame()->GetWidget() : nullptr;
+}
+
 void
 nsXULPopupManager::AdjustPopupsOnWindowChange(nsPIDOMWindow* aWindow)
 {
   // When the parent window is moved, adjust any child popups. Dismissable
   // menus and panels are expected to roll up when a window is moved, so there
   // is no need to check these popups, only the noautohide popups.
   nsMenuChainItem* item = mNoHidePanels;
   while (item) {
@@ -1540,25 +1550,25 @@ nsXULPopupManager::HasContextMenu(nsMenu
 void
 nsXULPopupManager::SetCaptureState(nsIContent* aOldPopup)
 {
   nsMenuChainItem* item = GetTopVisibleMenu();
   if (item && aOldPopup == item->Content())
     return;
 
   if (mWidget) {
-    mWidget->CaptureRollupEvents(this, false, false);
+    mWidget->CaptureRollupEvents(nullptr, false);
     mWidget = nullptr;
   }
 
   if (item) {
     nsMenuPopupFrame* popup = item->Frame();
     mWidget = popup->GetWidget();
     if (mWidget) {
-      mWidget->CaptureRollupEvents(this, true, popup->ConsumeOutsideClicks());
+      mWidget->CaptureRollupEvents(nullptr, true);
       popup->AttachedDismissalListener();
     }
   }
 
   UpdateKeyboardListeners();
 }
 
 void
@@ -2097,17 +2107,17 @@ nsXULPopupManager::KeyDown(nsIDOMKeyEven
         aKeyEvent->GetShiftKey(&shift);
       bool meta=false;
       if (menuAccessKey != nsIDOMKeyEvent::DOM_VK_META)
         aKeyEvent->GetMetaKey(&meta);
       if (!(ctrl || alt || shift || meta)) {
         // The access key just went down and no other
         // modifiers are already down.
         if (mPopups)
-          Rollup(0);
+          Rollup(0, nullptr);
         else if (mActiveMenuBar)
           mActiveMenuBar->MenuClosed();
       }
     }
   }
 
   // Since a menu was open, eat the event to keep other event
   // listeners from becoming confused.
@@ -2174,17 +2184,17 @@ nsXULPopupManager::KeyPress(nsIDOMKeyEve
   }
   else if (theChar == NS_VK_TAB
 #ifndef XP_MACOSX
            || theChar == NS_VK_F10
 #endif
   ) {
     // close popups or deactivate menubar when Tab or F10 are pressed
     if (item)
-      Rollup(0);
+      Rollup(0, nullptr);
     else if (mActiveMenuBar)
       mActiveMenuBar->MenuClosed();
   }
   else if (theChar == NS_VK_ENTER ||
            theChar == NS_VK_RETURN) {
     // If there is a popup open, check if the current item needs to be opened.
     // Otherwise, tell the active menubar, if any, to activate the menu. The
     // Enter method will return a menu if one needs to be opened as a result.
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -117,18 +117,17 @@ public:
     NS_IMETHOD GetHasTransparentBackground(bool& aTransparent) { aTransparent = false; return NS_OK; }
     NS_IMETHOD HideWindowChrome(bool aShouldHide) { return NS_ERROR_NOT_IMPLEMENTED; }
     virtual void* GetNativeData(uint32_t aDataType);
     NS_IMETHOD SetTitle(const nsAString& aTitle) { return NS_OK; }
     NS_IMETHOD SetIcon(const nsAString& aIconSpec) { return NS_OK; }
     NS_IMETHOD EnableDragDrop(bool aEnable) { return NS_OK; }
     NS_IMETHOD CaptureMouse(bool aCapture) { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD CaptureRollupEvents(nsIRollupListener *aListener,
-                                   bool aDoCapture,
-                                   bool aConsumeRollupEvent) { return NS_ERROR_NOT_IMPLEMENTED; }
+                                   bool aDoCapture) { return NS_ERROR_NOT_IMPLEMENTED; }
 
     NS_IMETHOD GetAttention(int32_t aCycleCount) { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, int32_t aHorizontal, int32_t aVertical) { return NS_ERROR_NOT_IMPLEMENTED; }
 
     NS_IMETHOD ResetInputState();
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction);
     NS_IMETHOD_(InputContext) GetInputContext();
--- a/widget/cocoa/nsAppShell.mm
+++ b/widget/cocoa/nsAppShell.mm
@@ -33,20 +33,16 @@
 #include "TextInputHandler.h"
 #include "mozilla/HangMonitor.h"
 #include "sampler.h"
 
 #include "npapi.h"
 
 using namespace mozilla::widget;
 
-// defined in nsChildView.mm
-extern nsIRollupListener * gRollupListener;
-extern nsIWidget         * gRollupWidget;
-
 // defined in nsCocoaWindow.mm
 extern int32_t             gXULModalLevel;
 
 static bool gAppShellMethodsSwizzled = false;
 // List of current Cocoa app-modal windows (nested if more than one).
 nsCocoaAppModalWindowList *gCocoaAppModalWindowList = NULL;
 
 // Push a Cocoa app-modal window onto the top of our list.
@@ -958,18 +954,20 @@ nsAppShell::AfterProcessNextEvent(nsIThr
 // any sort of menu.  But make sure we don't do this for notifications we
 // send ourselves (whose 'sender' will be @"org.mozilla.gecko.PopupWindow").
 - (void)beginMenuTracking:(NSNotification*)aNotification
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   NSString *sender = [aNotification object];
   if (!sender || ![sender isEqualToString:@"org.mozilla.gecko.PopupWindow"]) {
-    if (gRollupListener && gRollupWidget)
-      gRollupListener->Rollup(0);
+    nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+    nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+    if (rollupWidget)
+      rollupListener->Rollup(0, nullptr);
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 @end
 
 // We hook beginModalSessionForWindow: and endModalSession: in order to
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -414,17 +414,17 @@ public:
   NS_IMETHOD              DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus);
 
   virtual bool            GetShouldAccelerate();
   virtual bool            UseOffMainThreadCompositing();
 
   NS_IMETHOD        SetCursor(nsCursor aCursor);
   NS_IMETHOD        SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY);
 
-  NS_IMETHOD        CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture, bool aConsumeRollupEvent);
+  NS_IMETHOD        CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture);
   NS_IMETHOD        SetTitle(const nsAString& title);
 
   NS_IMETHOD        GetAttention(int32_t aCycleCount);
 
   virtual bool HasPendingInputEvent();
 
   NS_IMETHOD        ActivateNativeMenuItemAt(const nsAString& indexString);
   NS_IMETHOD        ForceUpdateNativeMenuAt(const nsAString& indexString);
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -88,36 +88,30 @@ extern "C" {
   CG_EXTERN void CGContextResetCTM(CGContextRef);
   CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
   CG_EXTERN void CGContextResetClip(CGContextRef);
 }
 
 // defined in nsMenuBarX.mm
 extern NSMenu* sApplicationMenu; // Application menu shared by all menubars
 
-// these are defined in nsCocoaWindow.mm
-extern bool gConsumeRollupEvent;
-
 bool gChildViewMethodsSwizzled = false;
 
 extern nsISupportsArray *gDraggedTransferables;
 
 ChildView* ChildViewMouseTracker::sLastMouseEventView = nil;
 NSEvent* ChildViewMouseTracker::sLastMouseMoveEvent = nil;
 NSWindow* ChildViewMouseTracker::sWindowUnderMouse = nil;
 NSPoint ChildViewMouseTracker::sLastScrollEventScreenLocation = NSZeroPoint;
 
 #ifdef INVALIDATE_DEBUGGING
 static void blinkRect(Rect* r);
 static void blinkRgn(RgnHandle rgn);
 #endif
 
-nsIRollupListener * gRollupListener = nullptr;
-nsIWidget         * gRollupWidget   = nullptr;
-
 bool gUserCancelledDrag = false;
 
 uint32_t nsChildView::sLastInputEventCount = 0;
 
 @interface ChildView(Private)
 
 // sets up our view, attaching it to its owning gecko view
 - (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild;
@@ -811,17 +805,17 @@ NS_IMETHODIMP nsChildView::Move(int32_t 
   mBounds.x = aX;
   mBounds.y = aY;
 
   [mView setFrame:DevPixelsToCocoaPoints(mBounds)];
 
   if (mVisible)
     [mView setNeedsDisplay:YES];
 
-  NotifyRollupGeometryChange(gRollupListener);
+  NotifyRollupGeometryChange();
   ReportMoveEvent();
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP nsChildView::Resize(int32_t aWidth, int32_t aHeight, bool aRepaint)
@@ -834,17 +828,17 @@ NS_IMETHODIMP nsChildView::Resize(int32_
   mBounds.width  = aWidth;
   mBounds.height = aHeight;
 
   [mView setFrame:DevPixelsToCocoaPoints(mBounds)];
 
   if (mVisible && aRepaint)
     [mView setNeedsDisplay:YES];
 
-  NotifyRollupGeometryChange(gRollupListener);
+  NotifyRollupGeometryChange();
   ReportSizeEvent();
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP nsChildView::Resize(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, bool aRepaint)
@@ -865,17 +859,17 @@ NS_IMETHODIMP nsChildView::Resize(int32_
     mBounds.height = aHeight;
   }
 
   [mView setFrame:DevPixelsToCocoaPoints(mBounds)];
 
   if (mVisible && aRepaint)
     [mView setNeedsDisplay:YES];
 
-  NotifyRollupGeometryChange(gRollupListener);
+  NotifyRollupGeometryChange();
   if (isMoving) {
     ReportMoveEvent();
     if (mOnDestroyCalled)
       return NS_OK;
   }
   if (isResizing)
     ReportSizeEvent();
 
@@ -1485,19 +1479,18 @@ nsIntPoint nsChildView::WidgetToScreenOf
   FlipCocoaScreenCoordinate(origin);
 
   // convert to device pixels
   return CocoaPointsToDevPixels(origin);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntPoint(0,0));
 }
 
-NS_IMETHODIMP nsChildView::CaptureRollupEvents(nsIRollupListener * aListener, 
-                                               bool aDoCapture, 
-                                               bool aConsumeRollupEvent)
+NS_IMETHODIMP nsChildView::CaptureRollupEvents(nsIRollupListener * aListener,
+                                               bool aDoCapture)
 {
   // this never gets called, only top-level windows can be rollup widgets
   return NS_OK;
 }
 
 NS_IMETHODIMP nsChildView::SetTitle(const nsAString& title)
 {
   // child views don't have titles
@@ -2646,24 +2639,26 @@ NSEvent* gLastDragMouseDownEvent = nil;
 // such and let the OS (and other programs) know when it opens and closes
 // (this is how the OS knows to close other programs' context menus when
 // ours open).  We send the initial notification here, but others are sent
 // in nsCocoaWindow::Show().
 - (void)maybeInitContextMenuTracking
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
-  if (!gRollupWidget)
-    return;
-
 #ifdef MOZ_USE_NATIVE_POPUP_WINDOWS
   return;
 #endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */
 
-  NSWindow *popupWindow = (NSWindow*)gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> widget = rollupListener->GetRollupWidget();
+  if (!widget)
+    return;
+
+  NSWindow *popupWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
   if (!popupWindow || ![popupWindow isKindOfClass:[PopupWindow class]])
     return;
 
   [[NSDistributedNotificationCenter defaultCenter]
     postNotificationName:@"com.apple.HIToolbox.beginMenuTrackingNotification"
                   object:@"org.mozilla.gecko.PopupWindow"];
   [(PopupWindow*)popupWindow setIsContextMenu:YES];
 
@@ -2673,58 +2668,57 @@ NSEvent* gLastDragMouseDownEvent = nil;
 // Returns true if the event should no longer be processed, false otherwise.
 // This does not return whether or not anything was rolled up.
 - (BOOL)maybeRollup:(NSEvent*)theEvent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   BOOL consumeEvent = NO;
 
-  if (gRollupWidget && gRollupListener) {
-    NSWindow* currentPopup = static_cast<NSWindow*>(gRollupWidget->GetNativeData(NS_NATIVE_WINDOW));
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (rollupWidget) {
+    NSWindow* currentPopup = static_cast<NSWindow*>(rollupWidget->GetNativeData(NS_NATIVE_WINDOW));
     if (!nsCocoaUtils::IsEventOverWindow(theEvent, currentPopup)) {
       // event is not over the rollup window, default is to roll up
       bool shouldRollup = true;
 
       // check to see if scroll events should roll up the popup
       if ([theEvent type] == NSScrollWheel) {
-        shouldRollup = gRollupListener->ShouldRollupOnMouseWheelEvent();
+        shouldRollup = rollupListener->ShouldRollupOnMouseWheelEvent();
         // always consume scroll events that aren't over the popup
         consumeEvent = YES;
       }
 
       // if we're dealing with menus, we probably have submenus and
       // we don't want to rollup if the click is in a parent menu of
       // the current submenu
       uint32_t popupsToRollup = UINT32_MAX;
-      if (gRollupListener) {
-        nsAutoTArray<nsIWidget*, 5> widgetChain;
-        uint32_t sameTypeCount = gRollupListener->GetSubmenuWidgetChain(&widgetChain);
-        for (uint32_t i = 0; i < widgetChain.Length(); i++) {
-          nsIWidget* widget = widgetChain[i];
-          NSWindow* currWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
-          if (nsCocoaUtils::IsEventOverWindow(theEvent, currWindow)) {
-            // don't roll up if the mouse event occurred within a menu of the
-            // same type. If the mouse event occurred in a menu higher than
-            // that, roll up, but pass the number of popups to Rollup so
-            // that only those of the same type close up.
-            if (i < sameTypeCount) {
-              shouldRollup = false;
-            }
-            else {
-              popupsToRollup = sameTypeCount;
-            }
-            break;
+      nsAutoTArray<nsIWidget*, 5> widgetChain;
+      uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
+      for (uint32_t i = 0; i < widgetChain.Length(); i++) {
+        nsIWidget* widget = widgetChain[i];
+        NSWindow* currWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
+        if (nsCocoaUtils::IsEventOverWindow(theEvent, currWindow)) {
+          // don't roll up if the mouse event occurred within a menu of the
+          // same type. If the mouse event occurred in a menu higher than
+          // that, roll up, but pass the number of popups to Rollup so
+          // that only those of the same type close up.
+          if (i < sameTypeCount) {
+            shouldRollup = false;
           }
+          else {
+            popupsToRollup = sameTypeCount;
+          }
+          break;
         }
       }
 
       if (shouldRollup) {
-        gRollupListener->Rollup(popupsToRollup);
-        consumeEvent = (BOOL)gConsumeRollupEvent;
+        consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, nullptr);
       }
     }
   }
 
   return consumeEvent;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -250,17 +250,17 @@ public:
 
     NS_IMETHOD Invalidate(const nsIntRect &aRect);
     virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
     virtual LayerManager* GetLayerManager(PLayersChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nullptr);
     NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus) ;
-    NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture, bool aConsumeRollupEvent);
+    NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture);
     NS_IMETHOD GetAttention(int32_t aCycleCount);
     virtual bool HasPendingInputEvent();
     virtual nsTransparencyMode GetTransparencyMode();
     virtual void SetTransparencyMode(nsTransparencyMode aMode);
     NS_IMETHOD SetWindowShadowStyle(int32_t aStyle);
     virtual void SetShowsToolbarButton(bool aShow);
     virtual void SetShowsFullScreenButton(bool aShow);
     virtual void SetWindowAnimationType(WindowAnimationType aType);
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -52,24 +52,20 @@ int32_t gXULModalLevel = 0;
 
 // In principle there should be only one app-modal window at any given time.
 // But sometimes, despite our best efforts, another window appears above the
 // current app-modal window.  So we need to keep a linked list of app-modal
 // windows.  (A non-sheet window that appears above an app-modal window is
 // also made app-modal.)  See nsCocoaWindow::SetModal().
 nsCocoaWindowList *gGeckoAppModalWindowList = NULL;
 
-bool gConsumeRollupEvent;
-
 // defined in nsMenuBarX.mm
 extern NSMenu* sApplicationMenu; // Application menu shared by all menubars
 
 // defined in nsChildView.mm
-extern nsIRollupListener * gRollupListener;
-extern nsIWidget         * gRollupWidget;
 extern BOOL                gSomeMenuBarPainted;
 
 extern "C" {
   // CGSPrivate.h
   typedef NSInteger CGSConnection;
   typedef NSInteger CGSWindow;
   typedef NSUInteger CGSWindowFilterRef;
   extern CGSConnection _CGSDefaultConnection(void);
@@ -85,21 +81,22 @@ extern "C" {
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsCocoaWindow, Inherited, nsPIWidgetCocoa)
 
 // A note on testing to see if your object is a sheet...
 // |mWindowType == eWindowType_sheet| is true if your gecko nsIWidget is a sheet
 // widget - whether or not the sheet is showing. |[mWindow isSheet]| will return
 // true *only when the sheet is actually showing*. Choose your test wisely.
 
-// roll up any popup windows
 static void RollUpPopups()
 {
-  if (gRollupListener && gRollupWidget)
-    gRollupListener->Rollup(0);
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (rollupWidget)
+    rollupListener->Rollup(0, nullptr);
 }
 
 nsCocoaWindow::nsCocoaWindow()
 : mParent(nullptr)
 , mWindow(nil)
 , mDelegate(nil)
 , mSheetWindowParent(nil)
 , mPopupContentView(nil)
@@ -1744,39 +1741,31 @@ nsIntSize nsCocoaWindow::ClientToWindowS
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntSize(0,0));
 }
 
 nsMenuBarX* nsCocoaWindow::GetMenuBar()
 {
   return mMenuBar;
 }
 
-NS_IMETHODIMP nsCocoaWindow::CaptureRollupEvents(nsIRollupListener * aListener,
-                                                 bool aDoCapture,
-                                                 bool aConsumeRollupEvent)
+NS_IMETHODIMP nsCocoaWindow::CaptureRollupEvents(nsIRollupListener* aListener, bool aDoCapture)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   gRollupListener = nullptr;
-  NS_IF_RELEASE(gRollupWidget);
   
   if (aDoCapture) {
     gRollupListener = aListener;
-    gRollupWidget = this;
-    NS_ADDREF(this);
-
-    gConsumeRollupEvent = aConsumeRollupEvent;
 
     // Sometimes more than one popup window can be visible at the same time
     // (e.g. nested non-native context menus, or the test case (attachment
-    // 276885) for bmo bug 392389, which displays a non-native combo-box in
-    // a non-native popup window).  In these cases the "active" popup window
-    // (the one that corresponds to the current gRollupWidget) should be the
-    // topmost -- the (nested) context menu the mouse is currently over, or
-    // the combo-box's drop-down list (when it's displayed).  But (among
+    // 276885) for bmo bug 392389, which displays a non-native combo-box in a
+    // non-native popup window).  In these cases the "active" popup window should
+    // be the topmost -- the (nested) context menu the mouse is currently over,
+    // or the combo-box's drop-down list (when it's displayed).  But (among
     // windows that have the same "level") OS X makes topmost the window that
     // last received a mouse-down event, which may be incorrect (in the combo-
     // box case, it makes topmost the window containing the combo-box).  So
     // here we fiddle with a non-native popup window's level to make sure the
     // "active" one is always above any other non-native popup windows that
     // may be visible.
     if (mWindow && (mWindowType == eWindowType_popup))
       SetPopupWindowLevel();
--- a/widget/cocoa/nsMenuX.mm
+++ b/widget/cocoa/nsMenuX.mm
@@ -20,16 +20,17 @@
 #include "prinrval.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "plstr.h"
 #include "nsGkAtoms.h"
 #include "nsGUIEvent.h"
 #include "nsCRT.h"
+#include "nsBaseWidget.h"
 
 #include "nsIDocument.h"
 #include "nsIContent.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocumentObserver.h"
 #include "nsIComponentManager.h"
 #include "nsIRollupListener.h"
 #include "nsIDOMElement.h"
@@ -37,20 +38,16 @@
 #include "nsIServiceManager.h"
 #include "nsXULPopupManager.h"
 
 #include "jsapi.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
 
-// externs defined in nsChildView.mm
-extern nsIRollupListener * gRollupListener;
-extern nsIWidget         * gRollupWidget;
-
 static bool gConstructingMenu = false;
 static bool gMenuMethodsSwizzled = false;
 
 int32_t nsMenuX::sIndexingMenuLevel = 0;
 
 
 //
 // Objective-C class used for representedObject
@@ -822,18 +819,20 @@ nsresult nsMenuX::SetupIcon()
     return;
 
   // Don't do anything while the OS is (re)indexing our menus (on Leopard and
   // higher).  This stops the Help menu from being able to search in our
   // menus, but it also resolves many other problems.
   if (nsMenuX::sIndexingMenuLevel > 0)
     return;
 
-  if (gRollupListener && gRollupWidget) {
-    gRollupListener->Rollup(0);
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (rollupWidget) {
+    rollupListener->Rollup(0, nullptr);
     [menu cancelTracking];
     return;
   }
   mGeckoMenu->MenuOpened();
 }
 
 - (void)menuDidClose:(NSMenu *)menu
 {
--- a/widget/cocoa/nsToolkit.mm
+++ b/widget/cocoa/nsToolkit.mm
@@ -27,28 +27,25 @@ extern "C" {
 #import <IOKit/IOMessage.h>
 
 #include "nsCocoaUtils.h"
 #include "nsObjCExceptions.h"
 
 #include "nsGkAtoms.h"
 #include "nsIRollupListener.h"
 #include "nsIWidget.h"
+#include "nsBaseWidget.h"
 
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
-// defined in nsChildView.mm
-extern nsIRollupListener * gRollupListener;
-extern nsIWidget         * gRollupWidget;
-
 static io_connect_t gRootPort = MACH_PORT_NULL;
 
 nsToolkit* nsToolkit::gToolkit = nullptr;
 
 nsToolkit::nsToolkit()
 : mSleepWakeNotificationRLS(nullptr)
 , mEventTapPort(nullptr)
 , mEventTapRLS(nullptr)
@@ -162,34 +159,40 @@ static NSPoint ConvertCGGlobalToCocoaScr
 // they've already been processed.
 static CGEventRef EventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   if ((type == kCGEventTapDisabledByUserInput) ||
       (type == kCGEventTapDisabledByTimeout))
     return event;
-  if (!gRollupWidget || !gRollupListener || [NSApp isActive])
+  if ([NSApp isActive])
     return event;
+
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (!rollupWidget)
+    return event;
+
   // Don't bother with rightMouseDown events here -- because of the delay,
   // we'll end up closing browser context menus that we just opened.  Since
   // these events usually raise a context menu, we'll handle them by hooking
   // the @"com.apple.HIToolbox.beginMenuTrackingNotification" distributed
   // notification (in nsAppShell.mm's AppShellDelegate).
   if (type == kCGEventRightMouseDown)
     return event;
-  NSWindow *ctxMenuWindow = (NSWindow*) gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
+  NSWindow *ctxMenuWindow = (NSWindow*) rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
   if (!ctxMenuWindow)
     return event;
   NSPoint screenLocation = ConvertCGGlobalToCocoaScreen(CGEventGetLocation(event));
   // Don't roll up the rollup widget if our mouseDown happens over it (doing
   // so would break the corresponding context menu).
   if (NSPointInRect(screenLocation, [ctxMenuWindow frame]))
     return event;
-  gRollupListener->Rollup(0);
+  rollupListener->Rollup(0, nullptr);
   return event;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NULL);
 }
 
 // Cocoa Firefox's use of custom context menus requires that we explicitly
 // handle mouse events from other processes that the OS handles
 // "automatically" for native context menus -- mouseMoved events so that
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -79,18 +79,17 @@ public:
     virtual void* GetNativeData(uint32_t aDataType);
     NS_IMETHOD SetTitle(const nsAString& aTitle)
     {
         return NS_OK;
     }
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus);
     NS_IMETHOD CaptureRollupEvents(nsIRollupListener *aListener,
-                                   bool aDoCapture,
-                                   bool aConsumeRollupEvent)
+                                   bool aDoCapture)
     {
         return NS_ERROR_NOT_IMPLEMENTED;
     }
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
 
     NS_IMETHOD MakeFullScreen(bool aFullScreen) /*MOZ_OVERRIDE*/;
 
     virtual float GetDPI();
--- a/widget/gtk2/nsWindow.cpp
+++ b/widget/gtk2/nsWindow.cpp
@@ -129,18 +129,16 @@ const gint kEvents = GDK_EXPOSURE_MASK |
                      GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
                      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
 #ifdef MOZ_PLATFORM_MAEMO
                      GDK_POINTER_MOTION_HINT_MASK |
 #endif
                      GDK_POINTER_MOTION_MASK;
 
 /* utility functions */
-static bool       check_for_rollup(gdouble aMouseX, gdouble aMouseY,
-                                   bool aIsWheel, bool aAlwaysRollup);
 static bool       is_mouse_in_window(GdkWindow* aWindow,
                                      gdouble aMouseX, gdouble aMouseY);
 static nsWindow  *get_window_for_gtk_widget(GtkWidget *widget);
 static nsWindow  *get_window_for_gdk_window(GdkWindow *window);
 static GtkWidget *get_gtk_widget_for_gdk_window(GdkWindow *window);
 static GdkCursor *get_gtk_cursor(nsCursor aCursor);
 
 static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
@@ -253,20 +251,16 @@ static NS_DEFINE_IID(kCDragServiceCID,  
 
 // The window from which the focus manager asks us to dispatch key events.
 static nsWindow         *gFocusWindow          = NULL;
 static bool              gBlockActivateEvent   = false;
 static bool              gGlobalsInitialized   = false;
 static bool              gRaiseWindows         = true;
 static nsWindow         *gPluginFocusWindow    = NULL;
 
-static nsIRollupListener*          gRollupListener;
-static nsWeakPtr                   gRollupWindow;
-static bool                        gConsumeRollupEvent;
-
 
 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
 
 // If after selecting profile window, the startup fail, please refer to
 // http://bugzilla.gnome.org/show_bug.cgi?id=88940
 
 // needed for imgIContainer cursors
 // GdkDisplay* was added in 2.2
@@ -635,23 +629,20 @@ nsWindow::Destroy(void)
     DestroyCompositor();
 
     ClearCachedResources();
 
     g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
                                          FuncToGpointer(theme_changed_cb),
                                          this);
 
-    // ungrab if required
-    nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
-    if (static_cast<nsIWidget *>(this) == rollupWidget.get()) {
-        if (gRollupListener)
-            gRollupListener->Rollup(0);
-        gRollupWindow = nullptr;
-        gRollupListener = nullptr;
+    nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+    nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+    if (static_cast<nsIWidget *>(this) == rollupWidget) {
+        rollupListener->Rollup(0, nullptr);
     }
 
     // dragService will be null after shutdown of the service manager.
     nsDragService *dragService = nsDragService::GetInstance();
     if (dragService && this == dragService->GetMostRecentDestWindow()) {
         dragService->ScheduleLeaveEvent();
     }
 
@@ -1077,17 +1068,17 @@ nsWindow::Resize(int32_t aWidth, int32_t
             // dunno why, but apparently we're lame like that.
             NativeResize(aWidth, aHeight, aRepaint);
         }
         else {
             mNeedsResize = true;
         }
     }
 
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
 
     // send a resize notification if this is a toplevel
     if (mIsTopLevel || mListenForResizes) {
         DispatchResized(aWidth, aHeight);
     }
 
     return NS_OK;
 }
@@ -1143,17 +1134,17 @@ nsWindow::Resize(int32_t aX, int32_t aY,
             // dunno why, but apparently we're lame like that.
             NativeResize(aX, aY, aWidth, aHeight, aRepaint);
         }
         else {
             mNeedsResize = true;
         }
     }
 
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
 
     if (mIsTopLevel || mListenForResizes) {
         DispatchResized(aWidth, aHeight);
     }
 
     return NS_OK;
 }
 
@@ -1203,17 +1194,17 @@ nsWindow::Move(int32_t aX, int32_t aY)
 
     if (mIsTopLevel) {
         gtk_window_move(GTK_WINDOW(mShell), aX, aY);
     }
     else if (mGdkWindow) {
         gdk_window_move(mGdkWindow, aX, aY);
     }
 
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement  aPlacement,
                       nsIWidget                  *aWidget,
                       bool                        aActivate)
 {
@@ -1835,49 +1826,44 @@ nsWindow::CaptureMouse(bool aCapture)
         gtk_grab_remove(widget);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
-                              bool               aDoCapture,
-                              bool               aConsumeRollupEvent)
+                              bool               aDoCapture)
 {
     if (!mGdkWindow)
         return NS_OK;
 
     GtkWidget *widget = GetMozContainerWidget();
     if (!widget)
         return NS_ERROR_FAILURE;
 
     LOG(("CaptureRollupEvents %p\n", (void *)this));
 
     if (aDoCapture) {
-        gConsumeRollupEvent = aConsumeRollupEvent;
         gRollupListener = aListener;
-        gRollupWindow = do_GetWeakReference(static_cast<nsIWidget*>
-                                                       (this));
         // real grab is only done when there is no dragging
         if (!nsWindow::DragInProgress()) {
             gtk_grab_add(widget);
             GrabPointer(GetLastUserInputTime());
         }
     }
     else {
         if (!nsWindow::DragInProgress()) {
             ReleaseGrabs();
         }
         // There may not have been a drag in process when aDoCapture was set,
         // so make sure to remove any added grab.  This is a no-op if the grab
         // was not added to this widget.
         gtk_grab_remove(widget);
         gRollupListener = nullptr;
-        gRollupWindow = nullptr;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::GetAttention(int32_t aCycleCount)
 {
@@ -2315,17 +2301,17 @@ nsWindow::OnConfigureEvent(GtkWidget *aW
     nsIntRect screenBounds;
     GetScreenBounds(screenBounds);
 
     if (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) {
         // This check avoids unwanted rollup on spurious configure events from
         // Cygwin/X (bug 672103).
         if (mBounds.x != screenBounds.x ||
             mBounds.y != screenBounds.y) {
-            check_for_rollup(0, 0, false, true);
+            CheckForRollup(0, 0, false, true);
         }
     }
 
     // This event indicates that the window position may have changed.
     // mBounds.Size() is updated in OnSizeAllocate().
 
     // (The gtk_window_get_window_type() function is only available from
     // version 2.20.)
@@ -2698,19 +2684,17 @@ nsWindow::OnButtonPressEvent(GdkEventBut
     }
 
     nsWindow *containerWindow = GetContainerWindow();
     if (!gFocusWindow && containerWindow) {
         containerWindow->DispatchActivateEvent();
     }
 
     // check to see if we should rollup
-    bool rolledUp =
-        check_for_rollup(aEvent->x_root, aEvent->y_root, false, false);
-    if (gConsumeRollupEvent && rolledUp)
+    if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false))
         return;
 
     gdouble pressure = 0;
     gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
     mLastMotionPressure = pressure;
 
     uint16_t domButton;
     switch (aEvent->button) {
@@ -2848,17 +2832,17 @@ nsWindow::OnContainerFocusOutEvent(GdkEv
         if (!shouldRollup) {
             // we also roll up when a drag is from a different application
             nsCOMPtr<nsIDOMNode> sourceNode;
             dragSession->GetSourceNode(getter_AddRefs(sourceNode));
             shouldRollup = (sourceNode == nullptr);
         }
 
         if (shouldRollup) {
-            check_for_rollup(0, 0, false, true);
+            CheckForRollup(0, 0, false, true);
         }
     }
 
 #if defined(MOZ_WIDGET_GTK2) && defined(MOZ_X11)
     // plugin lose focus
     if (gPluginFocusWindow) {
         nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
         gPluginFocusWindow->LoseNonXEmbedPluginFocus();
@@ -3084,19 +3068,17 @@ nsWindow::OnKeyReleaseEvent(GdkEventKey 
 
     return FALSE;
 }
 
 void
 nsWindow::OnScrollEvent(GdkEventScroll *aEvent)
 {
     // check to see if we should rollup
-    bool rolledUp =
-        check_for_rollup(aEvent->x_root, aEvent->y_root, true, false);
-    if (gConsumeRollupEvent && rolledUp)
+    if (CheckForRollup(aEvent->x_root, aEvent->y_root, true, false))
         return;
 
     WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
     wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
     switch (aEvent->direction) {
     case GDK_SCROLL_UP:
         wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = -3;
         break;
@@ -4470,17 +4452,17 @@ nsWindow::GrabPointer(guint32 aTime)
     if (retval == GDK_GRAB_NOT_VIEWABLE) {
         LOG(("GrabPointer: window not viewable; will retry\n"));
         mRetryPointerGrab = true;
     } else if (retval != GDK_GRAB_SUCCESS) {
         LOG(("GrabPointer: pointer grab failed: %i\n", retval));
         // A failed grab indicates that another app has grabbed the pointer.
         // Check for rollup now, because, without the grab, we likely won't
         // get subsequent button press events.
-        check_for_rollup(0, 0, false, true);
+        CheckForRollup(0, 0, false, true);
     }
 }
 
 void
 nsWindow::ReleaseGrabs(void)
 {
     LOG(("ReleaseGrabs\n"));
 
@@ -4781,39 +4763,39 @@ nsWindow::HideWindowChrome(bool aShouldH
     XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) , False);
 #else
     gdk_flush ();
 #endif /* MOZ_X11 */
 
     return NS_OK;
 }
 
-static bool
-check_for_rollup(gdouble aMouseX, gdouble aMouseY,
-                 bool aIsWheel, bool aAlwaysRollup)
+bool
+nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY,
+                         bool aIsWheel, bool aAlwaysRollup)
 {
     bool retVal = false;
-    nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
-
-    if (rollupWidget && gRollupListener) {
+    nsIRollupListener* rollupListener = GetActiveRollupListener();
+    nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+    if (rollupWidget) {
         GdkWindow *currentPopup =
             (GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
         if (aAlwaysRollup || !is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
             bool rollup = true;
             if (aIsWheel) {
-                rollup = gRollupListener->ShouldRollupOnMouseWheelEvent();
+                rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
                 retVal = true;
             }
             // if we're dealing with menus, we probably have submenus and
             // we don't want to rollup if the click is in a parent menu of
             // the current submenu
             uint32_t popupsToRollup = UINT32_MAX;
             if (!aAlwaysRollup) {
                 nsAutoTArray<nsIWidget*, 5> widgetChain;
-                uint32_t sameTypeCount = gRollupListener->GetSubmenuWidgetChain(&widgetChain);
+                uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
                 for (uint32_t i=0; i<widgetChain.Length(); ++i) {
                     nsIWidget* widget = widgetChain[i];
                     GdkWindow* currWindow =
                         (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
                     if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
                       // don't roll up if the mouse event occurred within a
                       // menu of the same type. If the mouse event occurred
                       // in a menu higher than that, roll up, but pass the
@@ -4826,26 +4808,24 @@ check_for_rollup(gdouble aMouseX, gdoubl
                         popupsToRollup = sameTypeCount;
                       }
                       break;
                     }
                 } // foreach parent menu widget
             } // if rollup listener knows about menus
 
             // if we've determined that we should still rollup, do it.
-            if (rollup) {
-                gRollupListener->Rollup(popupsToRollup);
+            if (rollup && rollupListener->Rollup(popupsToRollup, nullptr)) {
                 if (popupsToRollup == UINT32_MAX) {
                     retVal = true;
                 }
             }
         }
     } else {
-        gRollupWindow = nullptr;
-        gRollupListener = nullptr;
+        nsBaseWidget::gRollupListener = nullptr;
     }
 
     return retVal;
 }
 
 /* static */
 bool
 nsWindow::DragInProgress(void)
--- a/widget/gtk2/nsWindow.h
+++ b/widget/gtk2/nsWindow.h
@@ -139,18 +139,17 @@ public:
     virtual void*      GetNativeData(uint32_t aDataType);
     NS_IMETHOD         SetTitle(const nsAString& aTitle);
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec);
     NS_IMETHOD         SetWindowClass(const nsAString& xulWinType);
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD         EnableDragDrop(bool aEnable);
     NS_IMETHOD         CaptureMouse(bool aCapture);
     NS_IMETHOD         CaptureRollupEvents(nsIRollupListener *aListener,
-                                           bool aDoCapture,
-                                           bool aConsumeRollupEvent);
+                                           bool aDoCapture);
     NS_IMETHOD         GetAttention(int32_t aCycleCount);
 
     virtual bool       HasPendingInputEvent();
 
     NS_IMETHOD         MakeFullScreen(bool aFullScreen);
     NS_IMETHOD         HideWindowChrome(bool aShouldHide);
 
     /**
@@ -332,16 +331,18 @@ private:
     void               SetUrgencyHint(GtkWidget *top_window, bool state);
     void              *SetupPluginPort(void);
     void               SetDefaultIcon(void);
     void               InitButtonEvent(nsMouseEvent &aEvent, GdkEventButton *aGdkEvent);
     bool               DispatchCommandEvent(nsIAtom* aCommand);
     bool               DispatchContentCommandEvent(int32_t aMsg);
     void               SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
                                            bool aIntersectWithExisting);
+    bool               CheckForRollup(gdouble aMouseX, gdouble aMouseY,
+                                      bool aIsWheel, bool aAlwaysRollup);
     bool               GetDragInfo(nsMouseEvent* aMouseEvent,
                                    GdkWindow** aWindow, gint* aButton,
                                    gint* aRootX, gint* aRootY);
     void               ClearCachedResources();
 
     GtkWidget          *mShell;
     MozContainer       *mContainer;
     GdkWindow          *mGdkWindow;
--- a/widget/nsIRollupListener.h
+++ b/widget/nsIRollupListener.h
@@ -16,20 +16,22 @@ class nsIRollupListener {
  public: 
 
   /**
    * Notifies the object to rollup, optionally returning the node that
    * was just rolled up.
    *
    * aCount is the number of popups in a chain to close. If this is
    * UINT32_MAX, then all popups are closed.
-   * If aGetLastRolledUp is true, then return the last rolled up popup,
-   * if this is supported.
+   * If aLastRolledUp is non-null, it will be set to the last rolled up popup,
+   * if this is supported. aLastRolledUp is not addrefed.
+   *
+   * Returns true if the event that the caller is processing should be consumed.
    */
-  virtual nsIContent* Rollup(uint32_t aCount, bool aGetLastRolledUp = false) = 0;
+  virtual bool Rollup(uint32_t aCount, nsIContent** aLastRolledUp) = 0;
 
   /**
    * Asks the RollupListener if it should rollup on mousevents
    */
   virtual bool ShouldRollupOnMouseWheelEvent() = 0;
 
   /**
    * Asks the RollupListener if it should rollup on mouse activate, eg. X-Mouse
@@ -45,11 +47,13 @@ class nsIRollupListener {
    * the same number of widgets added to aWidgetChain.
    */
   virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) = 0;
 
   /**
    * Notify the RollupListener that the widget did a Move or Resize.
    */
   virtual void NotifyGeometryChange() = 0;
+
+  virtual nsIWidget* GetRollupWidget() = 0;
 };
 
 #endif /* __nsIRollupListener_h__ */
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -85,18 +85,18 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-  { 0x4e05b167, 0x475b, 0x422b, \
-    { 0x88, 0xc0, 0xa5, 0xb1, 0x61, 0xcf, 0x87, 0x79 } }
+  { 0x8181a08f, 0xaa37, 0x4fd0, \
+    { 0x94, 0x32, 0x27, 0x74, 0xe2, 0xce, 0x02, 0xc8 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -1193,24 +1193,22 @@ class nsIWidget : public nsISupports {
 
     /**
      * Classify the window for the window manager. Mostly for X11.
      */
     NS_IMETHOD SetWindowClass(const nsAString& xulWinType) = 0;
 
     /**
      * Enables/Disables system capture of any and all events that would cause a
-     * dropdown to be rolled up, This method ignores the aConsumeRollupEvent 
-     * parameter when aDoCapture is FALSE
+     * popup to be rolled up. aListener should be set to a non-null value for
+     * any popups that are not managed by the popup manager.
      * @param aDoCapture true enables capture, false disables capture 
-     * @param aConsumeRollupEvent true consumes the rollup event, false dispatches rollup event
      *
      */
-    NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture,
-                                   bool aConsumeRollupEvent) = 0;
+    NS_IMETHOD CaptureRollupEvents(nsIRollupListener* aListener, bool aDoCapture) = 0;
 
     /**
      * Bring this window to the user's attention.  This is intended to be a more
      * gentle notification than popping the window to the top or putting up an
      * alert.  See, for example, Win32 FlashWindow or the NotificationManager on
      * the Mac.  The notification should be suppressed if the window is already
      * in the foreground and should be dismissed when the user brings this window
      * to the foreground.
--- a/widget/os2/nsWindow.cpp
+++ b/widget/os2/nsWindow.cpp
@@ -141,21 +141,16 @@ using namespace mozilla::widget;
 #else
   #define DEBUGFOCUS(what)
 #endif
 
 //=============================================================================
 //  Variables & Forward declarations
 //=============================================================================
 
-// Rollup Listener - used by nsWindow & os2FrameWindow
-nsIRollupListener*  gRollupListener           = 0;
-nsIWidget*          gRollupWidget             = 0;
-bool                gRollupConsumeRollupEvent = false;
-
 // Miscellaneous global flags
 uint32_t            gOS2Flags = 0;
 
 // Mouse pointers
 static HPOINTER     sPtrArray[IDC_COUNT];
 
 // location of last MB1 down - used for mouse-based copy/paste
 static POINTS       sLastButton1Down = {0,0};
@@ -489,20 +484,20 @@ NS_METHOD nsWindow::Destroy()
   // avoid calling into other objects if we're being deleted, 'cos
   // they must have no references to us.
   if ((mWindowState & nsWindowState_eLive) && mParent) {
     nsBaseWidget::Destroy();
   }
 
   // just to be safe. If we're going away and for some reason we're still
   // the rollup widget, rollup and turn off capture.
-  if (this == gRollupWidget) {
-    if (gRollupListener) {
-      gRollupListener->Rollup(UINT32_MAX);
-    }
+  nsIRollupListener* rollupListener = GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (this == rollupWidget) {
+    rollupListener->Rollup(UINT32_MAX);
     CaptureRollupEvents(nullptr, false, true);
   }
 
   HWND hMain = GetMainWindow();
   if (hMain) {
     DEBUGFOCUS(Destroy);
     if (hMain == WinQueryFocus(HWND_DESKTOP)) {
       WinSetFocus(HWND_DESKTOP, WinQueryWindow(hMain, QW_PARENT));
@@ -807,44 +802,44 @@ void nsWindow::NS2PM_PARENT(POINTL& ptl)
 }
 
 //-----------------------------------------------------------------------------
 
 NS_METHOD nsWindow::Move(int32_t aX, int32_t aY)
 {
   if (mFrame) {
     nsresult rv = mFrame->Move(aX, aY);
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return rv;
   }
   Resize(aX, aY, mBounds.width, mBounds.height, false);
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
 NS_METHOD nsWindow::Resize(int32_t aWidth, int32_t aHeight, bool aRepaint)
 {
   if (mFrame) {
     nsresult rv = mFrame->Resize(aWidth, aHeight, aRepaint);
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return rv;
   }
   Resize(mBounds.x, mBounds.y, aWidth, aHeight, aRepaint);
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
 NS_METHOD nsWindow::Resize(int32_t aX, int32_t aY,
                            int32_t aWidth, int32_t aHeight, bool aRepaint)
 {
   if (mFrame) {
     nsresult rv = mFrame->Resize(aX, aY, aWidth, aHeight, aRepaint);
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return rv;
   }
 
   // For mWnd & eWindowType_child set the cached values upfront, see bug 286555.
   // For other mWnd types we defer transfer of values to mBounds to
   // WinSetWindowPos(), see bug 391421.
 
   if (!mWnd ||
@@ -873,17 +868,17 @@ NS_METHOD nsWindow::Resize(int32_t aX, i
     }
 
     if (!WinSetWindowPos(mWnd, 0, ptl.x, ptl.y, aWidth, aHeight,
                          SWP_MOVE | SWP_SIZE) && aRepaint) {
       WinInvalidateRect(mWnd, 0, FALSE);
     }
   }
 
-  NotifyRollupGeometryChange(gRollupListener);
+  NotifyRollupGeometryChange();
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
 NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
                                 nsIWidget* aWidget, bool aActivate)
 {
@@ -1524,34 +1519,19 @@ HBITMAP nsWindow::CreateTransparencyMask
   return hAlpha;
 }
 
 //=============================================================================
 //  Rollup Event Handlers
 //=============================================================================
 
 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener* aListener,
-                                            bool aDoCapture,
-                                            bool aConsumeRollupEvent)
+                                            bool aDoCapture)
 {
-  // We haven't bothered carrying a weak reference to gRollupWidget
-  // because we believe lifespan is properly scoped.  The first
-  // assertion helps assure that remains true.
-  if (aDoCapture) {
-    NS_ASSERTION(!gRollupWidget, "rollup widget reassigned before release");
-    gRollupConsumeRollupEvent = aConsumeRollupEvent;
-    NS_IF_RELEASE(gRollupWidget);
-    gRollupListener = aListener;
-    gRollupWidget = this;
-    NS_ADDREF(this);
- } else {
-    gRollupListener = nullptr;
-    NS_IF_RELEASE(gRollupWidget);
-  }
-
+  gRollupListener = aDoCapture ? aListener : nullptr;
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
 // static
 bool nsWindow::EventIsInsideWindow(nsWindow* aWindow)
 {
@@ -1573,75 +1553,80 @@ bool nsWindow::EventIsInsideWindow(nsWin
 }
 
 //-----------------------------------------------------------------------------
 // Handle events that would cause a popup (combobox, menu, etc) to rollup.
 
 // static
 bool nsWindow::RollupOnButtonDown(ULONG aMsg)
 {
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+
   // Exit if the event is inside the most recent popup.
-  if (EventIsInsideWindow((nsWindow*)gRollupWidget)) {
+  if (EventIsInsideWindow((nsWindow*)rollupWidget)) {
     return false;
   }
 
   // See if we're dealing with a menu.  If so, exit if the
   // event was inside a parent of the current submenu.
   uint32_t popupsToRollup = UINT32_MAX;
 
-  if (gRollupListener) {
+  if (rollupListener) {
     nsAutoTArray<nsIWidget*, 5> widgetChain;
-    uint32_t sameTypeCount = gRollupListener->GetSubmenuWidgetChain(&widgetChain);
+    uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
     for (uint32_t i = 0; i < widgetChain.Length(); ++i) {
       nsIWidget* widget = widgetChain[i];
       if (EventIsInsideWindow((nsWindow*)widget)) {
         if (i < sameTypeCount) {
           return false;
         }
         popupsToRollup = sameTypeCount;
         break;
       }
     } // for each parent menu widget
   } // if rollup listener knows about menus
 
   // We only need to deal with the last rollup for left mouse down events.
   NS_ASSERTION(!mLastRollup, "mLastRollup is null");
-  mLastRollup = gRollupListener->Rollup(popupsToRollup, aMsg == WM_BUTTON1DOWN);
+  bool consumeRollupEvent =
+    rollupListener->Rollup(popupsToRollup, aMsg == WM_LBUTTONDOWN ? &mLastRollup : nullptr);
   NS_IF_ADDREF(mLastRollup);
 
   // If true, the buttondown event won't be passed on to the wndproc.
-  return gRollupConsumeRollupEvent;
+  return consumeRollupEvent;
 }
 
 //-----------------------------------------------------------------------------
 
 // static
 void nsWindow::RollupOnFocusLost(HWND aFocus)
 {
-  HWND hRollup = ((nsWindow*)gRollupWidget)->mWnd;
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  HWND hRollup = ((nsWindow*)rollupWidget)->mWnd;
 
   // Exit if focus was lost to the most recent popup.
   if (hRollup == aFocus) {
     return;
   }
 
   // Exit if focus was lost to a parent of the current submenu.
-  if (gRollupListener) {
+  if (rollupListener) {
     nsAutoTArray<nsIWidget*, 5> widgetChain;
-    gRollupListener->GetSubmenuWidgetChain(&widgetChain);
+    rollupListener->GetSubmenuWidgetChain(&widgetChain);
     for (uint32_t i = 0; i < widgetChain.Length(); ++i) {
       if (((nsWindow*)widgetChain[i])->mWnd == aFocus) {
         return;
       }
     }
+
+    // Rollup all popups.
+    rollupListener->Rollup(UINT32_MAX);
   }
-
-  // Rollup all popups.
-  gRollupListener->Rollup(UINT32_MAX);
-  return;
 }
 
 //=============================================================================
 //  nsWindow's Window Procedure
 //=============================================================================
 
 // This is the actual wndproc;  it does some preprocessing then passes
 // the msgs to the ProcessMessage() method which does most of the work.
@@ -1661,32 +1646,31 @@ MRESULT EXPENTRY fnwpNSWindow(HWND hwnd,
   // life of this method, in case it gets deleted during processing.
   // Yes, it's a double hack since someWindow is not really an interface.
   nsCOMPtr<nsISupports> kungFuDeathGrip;
   if (!wnd->mIsDestroying) {
     kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)wnd);
   }
 
   // Pre-process msgs that may cause a rollup.
-  if (gRollupListener && gRollupWidget) {
-    switch (msg) {
-      case WM_BUTTON1DOWN:
-      case WM_BUTTON2DOWN:
-      case WM_BUTTON3DOWN:
-        if (nsWindow::RollupOnButtonDown(msg)) {
-          return (MRESULT)true;
-        }
-        break;
-
-      case WM_SETFOCUS:
-        if (!mp2) {
-          nsWindow::RollupOnFocusLost((HWND)mp1);
-        }
-        break;
-    }
+  }
+  switch (msg) {
+    case WM_BUTTON1DOWN:
+    case WM_BUTTON2DOWN:
+    case WM_BUTTON3DOWN:
+      if (nsWindow::RollupOnButtonDown(msg)) {
+        return (MRESULT)true;
+      }
+      break;
+
+    case WM_SETFOCUS:
+      if (!mp2) {
+        nsWindow::RollupOnFocusLost((HWND)mp1);
+      }
+      break;
   }
 
   return wnd->ProcessMessage(msg, mp1, mp2);
 }
 
 //-----------------------------------------------------------------------------
 // In effect, nsWindow's real wndproc.
 
--- a/widget/os2/os2FrameWindow.cpp
+++ b/widget/os2/os2FrameWindow.cpp
@@ -16,19 +16,16 @@
 #include "os2FrameWindow.h"
 #include "nsIRollupListener.h"
 #include "nsIScreenManager.h"
 #include "nsOS2Uni.h"
 
 //-----------------------------------------------------------------------------
 // External Variables (in nsWindow.cpp)
 
-extern nsIRollupListener*  gRollupListener;
-extern nsIWidget*          gRollupWidget;
-extern bool                gRollupConsumeRollupEvent;
 extern uint32_t            gOS2Flags;
 
 #ifdef DEBUG_FOCUS
   extern int currentWindowIdentifier;
 #endif
 
 //-----------------------------------------------------------------------------
 // Debug
@@ -586,23 +583,25 @@ nsresult os2FrameWindow::ConstrainPositi
 //  os2FrameWindow's Window Procedure
 //=============================================================================
 
 // Subclass for frame window
 
 MRESULT EXPENTRY fnwpFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
 {
   // check to see if we have a rollup listener registered
-  if (gRollupListener && gRollupWidget) {
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (rollupListener) {
     if (msg == WM_TRACKFRAME || msg == WM_MINMAXFRAME ||
         msg == WM_BUTTON1DOWN || msg == WM_BUTTON2DOWN ||
         msg == WM_BUTTON3DOWN) {
       // Rollup if the event is outside the popup
-      if (!nsWindow::EventIsInsideWindow((nsWindow*)gRollupWidget)) {
-        gRollupListener->Rollup(UINT32_MAX);
+      if (!nsWindow::EventIsInsideWindow((nsWindow*)rollupWidget)) {
+        rollupListener->Rollup(UINT32_MAX);
       }
     }
   }
 
   os2FrameWindow* pFrame = (os2FrameWindow*)WinQueryWindowPtr(hwnd, QWL_USER);
   return pFrame->ProcessFrameMessage(msg, mp1, mp2);
 }
 
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -137,22 +137,16 @@ static NS_DEFINE_IID(kCDragServiceCID,  
 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
 
 #define kWindowPositionSlop 20
 
 // Qt
 static const int WHEEL_DELTA = 120;
 static bool gGlobalsInitialized = false;
 
-static nsIRollupListener*          gRollupListener;
-static nsWeakPtr                   gRollupWindow;
-static bool                        gConsumeRollupEvent;
-
-static bool       check_for_rollup(double aMouseX, double aMouseY,
-                                   bool aIsWheel);
 static bool
 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY);
 
 static bool sAltGrModifier = false;
 
 #ifdef MOZ_ENABLE_QTMOBILITY
 static QOrientationSensor *gOrientation = nullptr;
 static MozQOrientationSensorFilter gOrientationFilter;
@@ -379,22 +373,20 @@ nsWindow::Destroy(void)
             gOrientation->removeFilter(&gOrientationFilter);
             gOrientation->stop();
             delete gOrientation;
             gOrientation = nullptr;
         }
 #endif
     }
 
-    nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
-    if (static_cast<nsIWidget *>(this) == rollupWidget.get()) {
-        if (gRollupListener)
-            gRollupListener->Rollup(0);
-        gRollupWindow = nullptr;
-        gRollupListener = nullptr;
+    nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+    nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+    if (static_cast<nsIWidget *>(this) == rollupWidget)
+        rollupListener->Rollup(0, nullptr);
     }
 
     if (mLayerManager) {
         mLayerManager->Destroy();
     }
     mLayerManager = nullptr;
 
     Show(false);
@@ -540,17 +532,17 @@ nsWindow::Move(int32_t aX, int32_t aY)
         pos = mWidget->mapFromScene(pos);
         pos = mWidget->mapToParent(pos);
         mWidget->setPos(pos);
     }
 
     mBounds.x = pos.x();
     mBounds.y = pos.y();
 
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement  aPlacement,
                       nsIWidget                  *aWidget,
                       bool                        aActivate)
 {
@@ -883,61 +875,51 @@ nsWindow::CaptureMouse(bool aCapture)
     else
         widget->releaseMouse();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
-                              bool               aDoCapture,
-                              bool               aConsumeRollupEvent)
+                              bool               aDoCapture)
 {
     if (!mWidget)
         return NS_OK;
 
     LOG(("CaptureRollupEvents %p\n", (void *)this));
 
-    if (aDoCapture) {
-        gConsumeRollupEvent = aConsumeRollupEvent;
-        gRollupListener = aListener;
-        gRollupWindow = do_GetWeakReference(static_cast<nsIWidget*>(this));
-    }
-    else {
-        gRollupListener = nullptr;
-        gRollupWindow = nullptr;
-    }
-
+    gRollupListener = aDoCapture ? aListener : nullptr;
     return NS_OK;
 }
 
 bool
-check_for_rollup(double aMouseX, double aMouseY,
-                 bool aIsWheel)
+nsWindow::CheckForRollup(double aMouseX, double aMouseY,
+                         bool aIsWheel)
 {
     bool retVal = false;
-    nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
-
-    if (rollupWidget && gRollupListener) {
+    nsIRollupListener* rollupListener = GetActiveRollupListener();
+    nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+    if (rollupWidget) {
         MozQWidget *currentPopup =
             (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
 
         if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
             bool rollup = true;
             if (aIsWheel) {
-                rollup = gRollupListener->ShouldRollupOnMouseWheelEvent();
+                rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
                 retVal = true;
             }
             // if we're dealing with menus, we probably have submenus and
             // we don't want to rollup if the clickis in a parent menu of
             // the current submenu
             uint32_t popupsToRollup = UINT32_MAX;
-            if (gRollupListener) {
+            if (rollupListener) {
                 nsAutoTArray<nsIWidget*, 5> widgetChain;
-                uint32_t sameTypeCount = gRollupListener->GetSubmenuWidgetChain(&widgetChain);
+                uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
                 for (uint32_t i=0; i<widgetChain.Length(); ++i) {
                     nsIWidget* widget =  widgetChain[i];
                     MozQWidget* currWindow =
                         (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW);
                     if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
                       if (i < sameTypeCount) {
                         rollup = false;
                       }
@@ -946,23 +928,21 @@ check_for_rollup(double aMouseX, double 
                       }
                       break;
                     }
                 } // foreach parent menu widget
             } // if rollup listener knows about menus
 
             // if we've determined that we should still rollup, do it.
             if (rollup) {
-                gRollupListener->Rollup(popupsToRollup);
-                retVal = true;
+                retVal = rollupListener->Rollup(popupsToRollup, nullptr);
             }
         }
     } else {
-        gRollupWindow = nullptr;
-        gRollupListener = nullptr;
+        nsBaseWidget::gRollupListener = nullptr;
     }
 
     return retVal;
 }
 
 /* static */
 bool
 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY)
@@ -1313,18 +1293,17 @@ nsWindow::OnButtonPressEvent(QGraphicsSc
 
     QPointF pos = aEvent->pos();
 
     // we check against the widgets geometry, so use parent coordinates
     // for the check
     if (mWidget)
         pos = mWidget->mapToParent(pos);
 
-    bool rolledUp = check_for_rollup( pos.x(), pos.y(), false);
-    if (gConsumeRollupEvent && rolledUp)
+    if (CheckForRollup( pos.x(), pos.y(), false))
         return nsEventStatus_eIgnore;
 
     uint16_t      domButton;
     switch (aEvent->button()) {
     case Qt::MidButton:
         domButton = nsMouseEvent::eMiddleButton;
         break;
     case Qt::RightButton:
@@ -2970,17 +2949,17 @@ nsWindow::Resize(int32_t aWidth, int32_t
 
     // synthesize a resize event if this isn't a toplevel
     if (mIsTopLevel || mListenForResizes) {
         nsIntRect rect(mBounds.x, mBounds.y, aWidth, aHeight);
         nsEventStatus status;
         DispatchResizeEvent(rect, status);
     }
 
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Resize(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
                  bool aRepaint)
 {
     mBounds.x = aX;
@@ -3034,17 +3013,17 @@ nsWindow::Resize(int32_t aX, int32_t aY,
         nsIntRect rect(aX, aY, aWidth, aHeight);
         nsEventStatus status;
         DispatchResizeEvent(rect, status);
     }
 
     if (aRepaint)
         mWidget->update();
 
-    NotifyRollupGeometryChange(gRollupListener);
+    NotifyRollupGeometryChange();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Enable(bool aState)
 {
     mEnabled = aState;
 
--- a/widget/qt/nsWindow.h
+++ b/widget/qt/nsWindow.h
@@ -148,18 +148,17 @@ public:
     NS_IMETHOD         SetTitle(const nsAString& aTitle);
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec);
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD         DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus);
 
     NS_IMETHOD         EnableDragDrop(bool aEnable);
     NS_IMETHOD         CaptureMouse(bool aCapture);
     NS_IMETHOD         CaptureRollupEvents(nsIRollupListener *aListener,
-                                           bool aDoCapture,
-                                           bool aConsumeRollupEvent);
+                                           bool aDoCapture);
 
     NS_IMETHOD         SetWindowClass(const nsAString& xulWinType);
 
     NS_IMETHOD         GetAttention(int32_t aCycleCount);
     NS_IMETHOD         BeginResizeDrag   (nsGUIEvent* aEvent, int32_t aHorizontal, int32_t aVertical);
 
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction);
@@ -301,16 +300,17 @@ private:
     } MozCachedTouchEvent;
 
     typedef struct {
         QPointF pos;
         Qt::KeyboardModifiers modifiers;
         bool needDispatch;
     } MozCachedMoveEvent;
 
+    bool               CheckForRollup(double aMouseX, double aMouseY, bool aIsWheel);
     void*              SetupPluginPort(void);
     nsresult           SetWindowIconList(const nsTArray<nsCString> &aIconList);
     void               SetDefaultIcon(void);
     void               InitButtonEvent(nsMouseEvent &event, QGraphicsSceneMouseEvent *aEvent, int aClickCount = 1);
     nsEventStatus      DispatchCommandEvent(nsIAtom* aCommand);
     nsEventStatus      DispatchContentCommandEvent(int32_t aMsg);
     MozQWidget*        createQWidget(MozQWidget* parent,
                                      nsNativeWidget nativeParent,
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -207,21 +207,16 @@ TriStateBool    nsWindow::sCanQuit      
 HHOOK           nsWindow::sMsgFilterHook          = NULL;
 HHOOK           nsWindow::sCallProcHook           = NULL;
 HHOOK           nsWindow::sCallMouseHook          = NULL;
 bool            nsWindow::sProcessHook            = false;
 UINT            nsWindow::sRollupMsgId            = 0;
 HWND            nsWindow::sRollupMsgWnd           = NULL;
 UINT            nsWindow::sHookTimerId            = 0;
 
-// Rollup Listener
-nsIRollupListener* nsWindow::sRollupListener      = nullptr;
-nsIWidget*      nsWindow::sRollupWidget           = nullptr;
-bool            nsWindow::sRollupConsumeEvent     = false;
-
 // Mouse Clicks - static variable definitions for figuring
 // out 1 - 3 Clicks.
 POINT           nsWindow::sLastMousePoint         = {0};
 POINT           nsWindow::sLastMouseMovePoint     = {0};
 LONG            nsWindow::sLastMouseDownTime      = 0L;
 LONG            nsWindow::sLastClickCount         = 0L;
 BYTE            nsWindow::sLastMouseButton        = 0;
 
@@ -1367,17 +1362,17 @@ NS_METHOD nsWindow::Move(int32_t aX, int
         mClipRects &&
         (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(nsIntRect(0, 0, mBounds.width, mBounds.height)))) {
       flags |= SWP_NOCOPYBITS;
     }
     VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0, flags));
 
     SetThemeRegion();
   }
-  NotifyRollupGeometryChange(sRollupListener);
+  NotifyRollupGeometryChange();
   return NS_OK;
 }
 
 // Resize this component
 NS_METHOD nsWindow::Resize(int32_t aWidth, int32_t aHeight, bool aRepaint)
 {
   NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
   NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
@@ -1410,17 +1405,17 @@ NS_METHOD nsWindow::Resize(int32_t aWidt
     ClearThemeRegion();
     VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
     SetThemeRegion();
   }
 
   if (aRepaint)
     Invalidate();
 
-  NotifyRollupGeometryChange(sRollupListener);
+  NotifyRollupGeometryChange();
   return NS_OK;
 }
 
 // Resize this component
 NS_METHOD nsWindow::Resize(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, bool aRepaint)
 {
   NS_ASSERTION((aWidth >=0 ),  "Negative width passed to nsWindow::Resize");
   NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
@@ -1455,17 +1450,17 @@ NS_METHOD nsWindow::Resize(int32_t aX, i
     ClearThemeRegion();
     VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
     SetThemeRegion();
   }
 
   if (aRepaint)
     Invalidate();
 
-  NotifyRollupGeometryChange(sRollupListener);
+  NotifyRollupGeometryChange();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, int32_t aHorizontal, int32_t aVertical)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
 
@@ -3056,36 +3051,26 @@ NS_METHOD nsWindow::CaptureMouse(bool aC
  *
  * Dealing with event rollup on destroy for popups. Enables &
  * Disables system capture of any and all events that would
  * cause a dropdown to be rolled up.
  *
  **************************************************************/
 
 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
-                                            bool aDoCapture,
-                                            bool aConsumeRollupEvent)
+                                            bool aDoCapture)
 {
   if (aDoCapture) {
-    /* we haven't bothered carrying a weak reference to sRollupWidget because
-       we believe lifespan is properly scoped. this next assertion helps
-       assure that remains true. */
-    NS_ASSERTION(!sRollupWidget, "rollup widget reassigned before release");
-    sRollupConsumeEvent = aConsumeRollupEvent;
-    NS_IF_RELEASE(sRollupWidget);
-    sRollupListener = aListener;
-    sRollupWidget = this;
-    NS_ADDREF(this);
+    gRollupListener = aListener;
     if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) {
       RegisterSpecialDropdownHooks();
     }
     sProcessHook = true;
   } else {
-    sRollupListener = nullptr;
-    NS_IF_RELEASE(sRollupWidget);
+    gRollupListener = nullptr;
     sProcessHook = false;
     UnregisterSpecialDropdownHooks();
   }
 
   return NS_OK;
 }
 
 /**************************************************************
@@ -7084,20 +7069,22 @@ void nsWindow::OnDestroy()
   //SetParent(nullptr);
   mParent = nullptr;
 
   // We have to destroy the native drag target before we null out our window pointer.
   EnableDragDrop(false);
 
   // If we're going away and for some reason we're still the rollup widget, rollup and
   // turn off capture.
-  if ( this == sRollupWidget ) {
-    if ( sRollupListener )
-      sRollupListener->Rollup(0);
-    CaptureRollupEvents(nullptr, false, true);
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if ( this == rollupWidget ) {
+    if ( rollupListener )
+      rollupListener->Rollup(0, nullptr);
+    CaptureRollupEvents(nullptr, false);
   }
 
   // Restore the IM context.
   AssociateDefaultIMC(true);
 
   // Turn off mouse trails if enabled.
   MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
   if (mtrailer) {
@@ -7851,18 +7838,17 @@ VOID CALLBACK nsWindow::HookTimerForPopu
   if (sHookTimerId != 0) {
     // if the window is NULL then we need to use the ID to kill the timer
     BOOL status = ::KillTimer(NULL, sHookTimerId);
     NS_ASSERTION(status, "Hook Timer was not killed.");
     sHookTimerId = 0;
   }
 
   if (sRollupMsgId != 0) {
-    // Note: DealWithPopups does the check to make sure that
-    // sRollupListener and sRollupWidget are not NULL
+    // Note: DealWithPopups does the check to make sure that the rollup widget is set.
     LRESULT popupHandlingResult;
     nsAutoRollup autoRollup;
     DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult);
     sRollupMsgId = 0;
     sRollupMsgWnd = NULL;
   }
 }
 
@@ -7912,64 +7898,64 @@ nsWindow::EventIsInsideWindow(UINT Msg, 
   // was the event inside this window?
   return (bool) PtInRect(&r, mp);
 }
 
 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
 BOOL
 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
 {
-  if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
+  nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
+  if (rollupWidget && ::IsWindowVisible(inWnd)) {
 
     inMsg = WinUtils::GetNativeMessage(inMsg);
     if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
         inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
         (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam)) ||
         inMsg == WM_NCRBUTTONDOWN ||
         inMsg == WM_MOVING ||
         inMsg == WM_SIZING ||
         inMsg == WM_NCLBUTTONDOWN ||
         inMsg == WM_NCMBUTTONDOWN ||
         inMsg == WM_MOUSEACTIVATE ||
         inMsg == WM_ACTIVATEAPP ||
         inMsg == WM_MENUSELECT)
     {
       // Rollup if the event is outside the popup.
-      bool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)sRollupWidget);
+      bool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)(rollupWidget.get()));
 
       if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL))
       {
-        rollup = sRollupListener->ShouldRollupOnMouseWheelEvent();
+        rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
         *outResult = true;
       }
 
       // If we're dealing with menus, we probably have submenus and we don't
       // want to rollup if the click is in a parent menu of the current submenu.
       uint32_t popupsToRollup = UINT32_MAX;
       if (rollup) {
-        if ( sRollupListener ) {
-          nsAutoTArray<nsIWidget*, 5> widgetChain;
-          uint32_t sameTypeCount = sRollupListener->GetSubmenuWidgetChain(&widgetChain);
-          for ( uint32_t i = 0; i < widgetChain.Length(); ++i ) {
-            nsIWidget* widget = widgetChain[i];
-            if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
-              // don't roll up if the mouse event occurred within a menu of the
-              // same type. If the mouse event occurred in a menu higher than
-              // that, roll up, but pass the number of popups to Rollup so
-              // that only those of the same type close up.
-              if (i < sameTypeCount) {
-                rollup = false;
-              }
-              else {
-                popupsToRollup = sameTypeCount;
-              }
-              break;
+        nsAutoTArray<nsIWidget*, 5> widgetChain;
+        uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
+        for ( uint32_t i = 0; i < widgetChain.Length(); ++i ) {
+          nsIWidget* widget = widgetChain[i];
+          if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
+            // don't roll up if the mouse event occurred within a menu of the
+            // same type. If the mouse event occurred in a menu higher than
+            // that, roll up, but pass the number of popups to Rollup so
+            // that only those of the same type close up.
+            if (i < sameTypeCount) {
+              rollup = false;
             }
-          } // foreach parent menu widget
-        } // if rollup listener knows about menus
+            else {
+              popupsToRollup = sameTypeCount;
+            }
+            break;
+          }
+        } // foreach parent menu widget
       }
 
       if (inMsg == WM_MOUSEACTIVATE && popupsToRollup == UINT32_MAX) {
         // Prevent the click inside the popup from causing a change in window
         // activation. Since the popup is shown non-activated, we need to eat
         // any requests to activate the window while it is displayed. Windows
         // will automatically activate the popup on the mousedown otherwise.
         if (!rollup) {
@@ -7978,33 +7964,31 @@ nsWindow::DealWithPopups(HWND inWnd, UIN
         }
         else
         {
           UINT uMsg = HIWORD(inLParam);
           if (uMsg == WM_MOUSEMOVE)
           {
             // WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
             // must be enabled in Windows.
-            rollup = sRollupListener->ShouldRollupOnMouseActivate();
+            rollup = rollupListener->ShouldRollupOnMouseActivate();
             if (!rollup)
             {
               *outResult = MA_NOACTIVATE;
               return true;
             }
           }
         }
       }
       // if we've still determined that we should still rollup everything, do it.
       else if (rollup) {
-        // sRollupConsumeEvent may be modified by
-        // nsIRollupListener::Rollup.
-        bool consumeRollupEvent = sRollupConsumeEvent;
         // only need to deal with the last rollup for left mouse down events.
         NS_ASSERTION(!mLastRollup, "mLastRollup is null");
-        mLastRollup = sRollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN);
+        bool consumeRollupEvent =
+          rollupListener->Rollup(popupsToRollup, inMsg == WM_LBUTTONDOWN ? &mLastRollup : nullptr);
         NS_IF_ADDREF(mLastRollup);
 
         // Tell hook to stop processing messages
         sProcessHook = false;
         sRollupMsgId = 0;
         sRollupMsgWnd = NULL;
 
         // return TRUE tells Windows that the event is consumed,
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -124,17 +124,17 @@ public:
   NS_IMETHOD              SetTitle(const nsAString& aTitle);
   NS_IMETHOD              SetIcon(const nsAString& aIconSpec);
   virtual nsIntPoint      WidgetToScreenOffset();
   virtual nsIntSize       ClientToWindowSize(const nsIntSize& aClientSize);
   NS_IMETHOD              DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus);
   NS_IMETHOD              EnableDragDrop(bool aEnable);
   NS_IMETHOD              CaptureMouse(bool aCapture);
   NS_IMETHOD              CaptureRollupEvents(nsIRollupListener * aListener,
-                                              bool aDoCapture, bool aConsumeRollupEvent);
+                                              bool aDoCapture);
   NS_IMETHOD              GetAttention(int32_t aCycleCount);
   virtual bool            HasPendingInputEvent();
   virtual LayerManager*   GetLayerManager(PLayersChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nullptr);
   gfxASurface             *GetThebesSurface();
   NS_IMETHOD              OnDefaultButtonLoaded(const nsIntRect &aButtonRect);
@@ -525,21 +525,16 @@ protected:
   static HHOOK          sMsgFilterHook;
   static HHOOK          sCallProcHook;
   static HHOOK          sCallMouseHook;
   static bool           sProcessHook;
   static UINT           sRollupMsgId;
   static HWND           sRollupMsgWnd;
   static UINT           sHookTimerId;
 
-  // Rollup Listener
-  static nsIWidget*     sRollupWidget;
-  static bool           sRollupConsumeEvent;
-  static nsIRollupListener* sRollupListener;
-
   // Mouse Clicks - static variable definitions for figuring
   // out 1 - 3 Clicks.
   static POINT          sLastMousePoint;
   static POINT          sLastMouseMovePoint;
   static LONG           sLastMouseDownTime;
   static LONG           sLastClickCount;
   static BYTE           sLastMouseButton;
 
--- a/widget/xpwidgets/PuppetWidget.h
+++ b/widget/xpwidgets/PuppetWidget.h
@@ -121,17 +121,17 @@ public:
   virtual nsIntPoint WidgetToScreenOffset()
   { return nsIntPoint(0, 0); }
 
   void InitEvent(nsGUIEvent& event, nsIntPoint* aPoint = nullptr);
 
   NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus);
 
   NS_IMETHOD CaptureRollupEvents(nsIRollupListener* aListener,
-                                 bool aDoCapture, bool aConsumeRollupEvent)
+                                 bool aDoCapture)
   { return NS_ERROR_UNEXPECTED; }
 
   //
   // nsBaseWidget methods we override
   //
 
   // Documents loaded in child processes are always subdocuments of
   // other docs in an ancestor process.  To ensure that the
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -19,16 +19,17 @@
 #include "nsIContent.h"
 #include "nsIServiceManager.h"
 #include "mozilla/Preferences.h"
 #include "BasicLayers.h"
 #include "LayerManagerOGL.h"
 #include "nsIXULRuntime.h"
 #include "nsIXULWindow.h"
 #include "nsIBaseWindow.h"
+#include "nsXULPopupManager.h"
 #include "nsEventStateManager.h"
 #include "nsIWidgetListener.h"
 #include "nsIGfxInfo.h"
 #include "npapi.h"
 #include "base/thread.h"
 #include "prenv.h"
 #include "mozilla/Attributes.h"
 
@@ -43,16 +44,18 @@ static void debug_RegisterPrefCallbacks(
 
 static bool debug_InSecureKeyboardInputMode = false;
 #endif
 
 #ifdef NOISY_WIDGET_LEAKS
 static int32_t gNumWidgets;
 #endif
 
+nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
+
 using namespace mozilla::layers;
 using namespace mozilla;
 using base::Thread;
 using mozilla::ipc::AsyncChannel;
 
 nsIContent* nsBaseWidget::mLastRollup = nullptr;
 // Global user preference for disabling native theme. Used
 // in NativeWindowTheme.
@@ -1292,16 +1295,27 @@ void nsBaseWidget::SetSizeConstraints(co
   // probably in the middle of a reflow.
 }
 
 const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
 {
   return mSizeConstraints;
 }
 
+// static
+nsIRollupListener*
+nsBaseWidget::GetActiveRollupListener()
+{
+  // If set, then this is likely an <html:select> dropdown.
+  if (gRollupListener)
+    return gRollupListener;
+
+  return nsXULPopupManager::GetInstance();
+}
+
 void
 nsBaseWidget::NotifyWindowDestroyed()
 {
   if (!mWidgetListener)
     return;
 
   nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
   nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -226,16 +226,19 @@ public:
   private:
     nsBaseWidget* mWidget;
   };
   friend class AutoUseBasicLayerManager;
 
   nsWindowType            GetWindowType() { return mWindowType; }
 
   virtual bool            UseOffMainThreadCompositing();
+
+  static nsIRollupListener* GetActiveRollupListener();
+
 protected:
 
   virtual void            ResolveIconName(const nsAString &aIconName,
                                           const nsAString &aIconSuffix,
                                           nsIFile **aResult);
   virtual void            OnDestroy();
   virtual void            BaseCreate(nsIWidget *aParent,
                                      const nsIntRect &aRect,
@@ -282,20 +285,22 @@ protected:
     nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
     return widget.forget();
   }
 
   BasicLayerManager* CreateBasicLayerManager();
 
   nsPopupType PopupType() const { return mPopupType; }
 
-  void NotifyRollupGeometryChange(nsIRollupListener* aRollupListener)
+  void NotifyRollupGeometryChange()
   {
-    if (aRollupListener) {
-      aRollupListener->NotifyGeometryChange();
+    // XULPopupManager isn't interested in this notification, so only
+    // send it if gRollupListener is set.
+    if (gRollupListener) {
+      gRollupListener->NotifyGeometryChange();
     }
   }
 
   /**
    * Apply the current size constraints to the given size.
    *
    * @param aWidth width to constrain
    * @param aHeight height to constrain
@@ -345,16 +350,18 @@ protected:
   nsAutoArrayPtr<nsIntRect> mClipRects;
   uint32_t          mClipRectCount;
   int32_t           mZIndex;
   nsSizeMode        mSizeMode;
   nsPopupLevel      mPopupLevel;
   nsPopupType       mPopupType;
   SizeConstraints   mSizeConstraints;
 
+  static nsIRollupListener* gRollupListener;
+
   // the last rolled up popup. Only set this when an nsAutoRollup is in scope,
   // so it can be cleared automatically.
   static nsIContent* mLastRollup;
 
 #ifdef DEBUG
 protected:
   static nsAutoString debug_GuiEventToString(nsGUIEvent * aGuiEvent);
   static bool debug_WantPaintFlashing();