Bug 743975 - use a widget listener interface instead of the remaining events that don't need an event, r=tn,jmathies,netzen,smichaud,karlt,blassey,chrisjones
authorNeil Deakin <neil@mozilla.com>
Wed, 15 Aug 2012 14:52:42 -0400
changeset 105578 448410c2035ef7bce315bb6b3c46f60fb909145e
parent 105577 481e19da0409a2979bf4a17449ae6f1b066274f6
child 105579 4aca82dc0d41007d1fdf231d1c3be86705132d73
push id1989
push userakeybl@mozilla.com
push dateTue, 28 Aug 2012 00:20:43 +0000
treeherdermozilla-aurora@a8e95ae10ea7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, jmathies, netzen, smichaud, karlt, blassey, chrisjones
bugs743975
milestone17.0a1
Bug 743975 - use a widget listener interface instead of the remaining events that don't need an event, r=tn,jmathies,netzen,smichaud,karlt,blassey,chrisjones
dom/base/nsGlobalWindow.cpp
embedding/browser/webBrowser/nsWebBrowser.cpp
embedding/browser/webBrowser/nsWebBrowser.h
view/src/nsView.cpp
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/Makefile.in
widget/android/nsWindow.cpp
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/gonk/nsWindow.cpp
widget/gtk2/nsWindow.cpp
widget/gtk2/nsWindow.h
widget/nsIWidget.h
widget/nsIWidgetListener.h
widget/qt/nsWindow.cpp
widget/qt/nsWindow.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
widget/windows/nsWindowGfx.cpp
widget/xpwidgets/PuppetWidget.cpp
widget/xpwidgets/PuppetWidget.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
xpfe/appshell/src/nsWebShellWindow.cpp
xpfe/appshell/src/nsWebShellWindow.h
xpfe/appshell/src/nsXULWindow.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -65,16 +65,17 @@
 #include "mozilla/dom/workers/Workers.h"
 #include "nsJSPrincipals.h"
 #include "mozilla/Attributes.h"
 
 // Interfaces Needed
 #include "nsIFrame.h"
 #include "nsCanvasFrame.h"
 #include "nsIWidget.h"
+#include "nsIWidgetListener.h"
 #include "nsIBaseWindow.h"
 #include "nsDeviceSensors.h"
 #include "nsIContent.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
@@ -7703,20 +7704,21 @@ nsGlobalWindow::ActivateOrDeactivate(boo
   nsCOMPtr<nsIDOMWindow> topLevelWindow;
   if (topLevelWidget == mainWidget) {
     topLevelWindow = static_cast<nsIDOMWindow*>(this);
   } else {
     // This is a workaround for the following problem:
     // When a window with an open sheet loses focus, only the sheet window
     // receives the NS_DEACTIVATE event. However, it's not the sheet that
     // should lose the active styling, but the containing top level window.
-    void* clientData;
-    topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
-    nsISupports* data = static_cast<nsISupports*>(clientData);
-    nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
+
+    // widgetListener should be a nsXULWindow
+    nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
+    nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
+    nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
     topLevelWindow = do_GetInterface(req);
   }
   if (topLevelWindow) {
     nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
     piWin->SetActive(aActivate);
   }
 }
 
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -87,17 +87,17 @@ nsWebBrowser::~nsWebBrowser()
 {
    InternalDestroy();
 }
 
 NS_IMETHODIMP nsWebBrowser::InternalDestroy()
 {
 
    if (mInternalWidget) {
-     mInternalWidget->SetClientData(0);
+     mInternalWidget->SetWidgetListener(nullptr);
      mInternalWidget->Destroy();
      mInternalWidget = nullptr; // Force release here.
    }
 
    SetDocShell(nullptr);
 
    if(mDocShellTreeOwner)
       {
@@ -1113,18 +1113,18 @@ NS_IMETHODIMP nsWebBrowser::Create()
       docShellParentWidget = mInternalWidget;
       nsWidgetInitData  widgetInit;
 
       widgetInit.clipChildren = true;
 
       widgetInit.mWindowType = eWindowType_child;
       nsIntRect bounds(mInitInfo->x, mInitInfo->y, mInitInfo->cx, mInitInfo->cy);
       
-      mInternalWidget->SetClientData(static_cast<nsWebBrowser *>(this));
-      mInternalWidget->Create(nullptr, mParentNativeWindow, bounds, nsWebBrowser::HandleEvent,
+      mInternalWidget->SetWidgetListener(this);
+      mInternalWidget->Create(nullptr, mParentNativeWindow, bounds, nullptr,
                               nullptr, &widgetInit);  
       }
 
     nsCOMPtr<nsIDocShell> docShell(do_CreateInstance("@mozilla.org/docshell;1", &rv));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = SetDocShell(docShell);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1654,79 +1654,55 @@ static void DrawThebesLayer(ThebesLayer*
   nscolor* color = static_cast<nscolor*>(aCallbackData);
   aContext->NewPath();
   aContext->SetColor(gfxRGBA(*color));
   nsIntRect dirtyRect = aRegionToDraw.GetBounds();
   aContext->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
   aContext->Fill();  
 }
 
-/* static */
-nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
+void nsWebBrowser::WindowRaised(nsIWidget* aWidget)
 {
-  nsWebBrowser  *browser = nullptr;
-  void          *data = nullptr;
-  nsIWidget     *widget = aEvent->widget;
-
-  if (!widget)
-    return nsEventStatus_eIgnore;
-
-  widget->GetClientData(data);
-  if (!data)
-    return nsEventStatus_eIgnore;
-
-  browser = static_cast<nsWebBrowser *>(data);
-
-  switch(aEvent->message) {
-
-  case NS_PAINT: {
-      LayerManager* layerManager = widget->GetLayerManager();
-      NS_ASSERTION(layerManager, "Must be in paint event");
+#if defined(DEBUG_smaug)
+  nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(mDocShell);
+  nsAutoString documentURI;
+  domDocument->GetDocumentURI(documentURI);
+  printf("nsWebBrowser::NS_ACTIVATE %p %s\n", (void*)browser,
+         NS_ConvertUTF16toUTF8(documentURI).get());
+#endif
+  Activate();
+}
 
-      layerManager->BeginTransaction();
-      nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
-      nsPaintEvent* paintEvent = static_cast<nsPaintEvent*>(aEvent);
-      nsIntRect dirtyRect = paintEvent->region.GetBounds();
-      if (root) {
-          root->SetVisibleRegion(dirtyRect);
-          layerManager->SetRoot(root);
-      }
-      layerManager->EndTransaction(DrawThebesLayer, &browser->mBackgroundColor);
-      return nsEventStatus_eConsumeDoDefault;
-    }
+void nsWebBrowser::WindowLowered(nsIWidget* aWidget)
+{
+#if defined(DEBUG_smaug)
+  nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(mDocShell);
+  nsAutoString documentURI;
+  domDocument->GetDocumentURI(documentURI);
+  printf("nsWebBrowser::NS_DEACTIVATE %p %s\n", (void*)browser,
+         NS_ConvertUTF16toUTF8(documentURI).get());
+#endif
+  Deactivate();
+}
 
-  case NS_ACTIVATE: {
-#if defined(DEBUG_smaug)
-    nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(browser->mDocShell);
-    nsAutoString documentURI;
-    domDocument->GetDocumentURI(documentURI);
-    printf("nsWebBrowser::NS_ACTIVATE %p %s\n", (void*)browser,
-           NS_ConvertUTF16toUTF8(documentURI).get());
-#endif
-    browser->Activate();
-    break;
+bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, bool isRequest, nsIntRegion aRegion, bool aWillSendDidPaint)
+{
+  LayerManager* layerManager = aWidget->GetLayerManager();
+  NS_ASSERTION(layerManager, "Must be in paint event");
+
+  layerManager->BeginTransaction();
+  nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
+  if (root) {
+    nsIntRect dirtyRect = aRegion.GetBounds();
+    root->SetVisibleRegion(dirtyRect);
+    layerManager->SetRoot(root);
   }
 
-  case NS_DEACTIVATE: {
-#if defined(DEBUG_smaug)
-    nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(browser->mDocShell);
-    nsAutoString documentURI;
-    domDocument->GetDocumentURI(documentURI);
-    printf("nsWebBrowser::NS_DEACTIVATE %p %s\n", (void*)browser,
-           NS_ConvertUTF16toUTF8(documentURI).get());
-#endif
-    browser->Deactivate();
-    break;
-  }
-
-  default:
-    break;
-  }
-
-  return nsEventStatus_eIgnore;
+  layerManager->EndTransaction(DrawThebesLayer, &mBackgroundColor);
+  return true;
 }
 
 NS_IMETHODIMP nsWebBrowser::GetPrimaryContentWindow(nsIDOMWindow** aDOMWindow)
 {
   *aDOMWindow = 0;
 
   nsCOMPtr<nsIDocShellTreeItem> item;
   NS_ENSURE_TRUE(mDocShellTreeOwner, NS_ERROR_FAILURE);
--- a/embedding/browser/webBrowser/nsWebBrowser.h
+++ b/embedding/browser/webBrowser/nsWebBrowser.h
@@ -31,16 +31,17 @@
 #include "nsIWebNavigation.h"
 #include "nsIWebBrowserSetup.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIWebBrowserStream.h"
 #include "nsIWindowWatcher.h"
 #include "nsIPrintSettings.h"
 #include "nsEmbedStream.h"
+#include "nsIWidgetListener.h"
 
 #include "nsTArray.h"
 #include "nsWeakPtr.h"
 
 class nsIContentViewerFile;
 
 class nsWebBrowserInitInfo
 {
@@ -79,16 +80,17 @@ class nsWebBrowser : public nsIWebBrowse
                      public nsIBaseWindow,
                      public nsIScrollable, 
                      public nsITextScroll, 
                      public nsIInterfaceRequestor,
                      public nsIWebBrowserPersist,
                      public nsIWebBrowserFocus,
                      public nsIWebProgressListener,
                      public nsIWebBrowserStream,
+                     public nsIWidgetListener,
                      public nsSupportsWeakReference
 {
 friend class nsDocShellTreeOwner;
 public:
     nsWebBrowser();
 
     NS_DECL_ISUPPORTS
 
@@ -114,17 +116,20 @@ protected:
     // XXXbz why are these NS_IMETHOD?  They're not interface methods!
     NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
     NS_IMETHOD EnsureDocShellTreeOwner();
     NS_IMETHOD GetPrimaryContentWindow(nsIDOMWindow **aDomWindow);
     NS_IMETHOD BindListener(nsISupports *aListener, const nsIID& aIID);
     NS_IMETHOD UnBindListener(nsISupports *aListener, const nsIID& aIID);
     NS_IMETHOD EnableGlobalHistory(bool aEnable);
 
-    static nsEventStatus HandleEvent(nsGUIEvent *aEvent);
+    // nsIWidgetListener
+    virtual void WindowRaised(nsIWidget* aWidget);
+    virtual void WindowLowered(nsIWidget* aWidget);
+    virtual bool PaintWindow(nsIWidget* aWidget, bool isRequest, nsIntRegion aRegion, bool aWillSendDidPaint);
 
 protected:
    nsDocShellTreeOwner*       mDocShellTreeOwner;
    nsCOMPtr<nsIDocShell>      mDocShell;
    nsCOMPtr<nsIInterfaceRequestor> mDocShellAsReq;
    nsCOMPtr<nsIBaseWindow>    mDocShellAsWin;
    nsCOMPtr<nsIDocShellTreeItem> mDocShellAsItem;
    nsCOMPtr<nsIWebNavigation> mDocShellAsNav;
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -2,48 +2,124 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsView.h"
 #include "nsIWidget.h"
 #include "nsWidgetsCID.h"
 #include "nsViewManager.h"
+#include "nsIFrame.h"
 #include "nsGUIEvent.h"
 #include "nsIComponentManager.h"
 #include "nsGfxCIID.h"
 #include "nsIInterfaceRequestor.h"
 #include "mozilla/Attributes.h"
-
-//mmptemp
+#include "nsXULPopupManager.h"
+#include "nsIWidgetListener.h"
 
 static nsEventStatus HandleEvent(nsGUIEvent *aEvent);
 
-
-//#define SHOW_VIEW_BORDERS
-
 #define VIEW_WRAPPER_IID \
   { 0xbf4e1841, 0xe9ec, 0x47f2, \
     { 0xb4, 0x77, 0x0f, 0xf6, 0x0f, 0x5a, 0xac, 0xbd } }
 
+static bool
+IsPopupWidget(nsIWidget* aWidget)
+{
+  nsWindowType type;
+  aWidget->GetWindowType(type);
+  return (type == eWindowType_popup);
+}
+
 /**
  * nsISupports-derived helper class that allows to store and get a view
  */
-class ViewWrapper MOZ_FINAL : public nsIInterfaceRequestor
+class ViewWrapper MOZ_FINAL : public nsIInterfaceRequestor,
+                              public nsIWidgetListener
 {
   public:
     NS_DECLARE_STATIC_IID_ACCESSOR(VIEW_WRAPPER_IID)
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINTERFACEREQUESTOR
 
     ViewWrapper(nsView* aView) : mView(aView) {}
 
     nsView* GetView() { return mView; }
   private:
     nsView* mView;
+
+  public:
+
+    bool WindowMoved(nsIWidget* aWidget, PRInt32 x, PRInt32 y)
+    {
+      nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+      if (pm && IsPopupWidget(aWidget)) {
+        pm->PopupMoved(mView->GetFrame(), nsIntPoint(x, y));
+        return true;
+      }
+
+      return false;
+    }
+
+    bool WindowResized(nsIWidget* aWidget, PRInt32 aWidth, PRInt32 aHeight)
+    {
+      nsIViewManager* viewManager = mView->GetViewManager();
+
+      // The root view may not be set if this is the resize associated with
+      // window creation
+      if (mView == viewManager->GetRootView()) {
+        nsRefPtr<nsDeviceContext> devContext;
+        viewManager->GetDeviceContext(*getter_AddRefs(devContext));
+        PRInt32 p2a = devContext->AppUnitsPerDevPixel();
+        viewManager->SetWindowDimensions(NSIntPixelsToAppUnits(aWidth, p2a),
+                                         NSIntPixelsToAppUnits(aHeight, p2a));
+        return true;
+      }
+      else if (IsPopupWidget(aWidget)) {
+        nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+        if (pm) {
+          pm->PopupResized(mView->GetFrame(), nsIntSize(aWidth, aHeight));
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    bool RequestWindowClose(nsIWidget* aWidget)
+    {
+      nsIFrame* frame = mView->GetFrame();
+      if (frame && IsPopupWidget(aWidget) &&
+          frame->GetType() == nsGkAtoms::menuPopupFrame) {
+        nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+        if (pm) {
+          pm->HidePopup(frame->GetContent(), false, true, false);
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    void WillPaintWindow(nsIWidget* aWidget, bool aWillSendPaint)
+    {
+      mView->GetViewManager()->WillPaintWindow(aWidget, aWillSendPaint);
+    }
+
+    bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion, bool aSentWillPaint, bool aWillSendDidPaint)
+    {
+      nsCOMPtr<nsViewManager> vm = mView->GetViewManager();
+      return vm->PaintWindow(aWidget, aRegion, aSentWillPaint, aWillSendDidPaint);
+    }
+
+    void DidPaintWindow()
+    {
+      mView->GetViewManager()->DidPaintWindow();
+    }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(ViewWrapper, VIEW_WRAPPER_IID)
 
 NS_IMPL_ADDREF(ViewWrapper)
 NS_IMPL_RELEASE(ViewWrapper)
 #ifndef DEBUG
 NS_IMPL_QUERY_INTERFACE2(ViewWrapper, ViewWrapper, nsIInterfaceRequestor)
@@ -88,33 +164,17 @@ NS_IMETHODIMP ViewWrapper::GetInterface(
 }
 
 /**
  * Given a widget, returns the stored ViewWrapper on it, or NULL if no
  * ViewWrapper is there.
  */
 static ViewWrapper* GetWrapperFor(nsIWidget* aWidget)
 {
-  // The widget's client data points back to the owning view
-  if (aWidget) {
-    void* clientData;
-    aWidget->GetClientData(clientData);
-    nsISupports* data = (nsISupports*)clientData;
-    
-    if (data) {
-      ViewWrapper* wrapper;
-      CallQueryInterface(data, &wrapper);
-      // Give a weak reference to the caller. There will still be at least one
-      // reference left, since the wrapper was addrefed when set on the widget.
-      if (wrapper)
-        wrapper->Release();
-      return wrapper;
-    }
-  }
-  return nullptr;
+  return aWidget ? static_cast<ViewWrapper *>(aWidget->GetWidgetListener()) : nullptr;
 }
 
 // Main events handler
 static nsEventStatus HandleEvent(nsGUIEvent *aEvent)
 {
 #if 0
   printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->message);
 #endif
@@ -251,17 +311,17 @@ void nsView::DestroyWidget()
     // Destroy. Just clear our event view ptr and free our reference to it. 
     if (mWidgetIsTopLevel) {
       ViewWrapper* wrapper = GetAttachedWrapperFor(mWindow);
       NS_IF_RELEASE(wrapper);
 
       mWindow->SetAttachedViewPtr(nullptr);
     }
     else {
-      mWindow->SetClientData(nullptr);
+      mWindow->SetWidgetListener(nullptr);
       mWindow->Destroy();
     }
 
     NS_RELEASE(mWindow);
   }
 }
 
 nsresult nsView::QueryInterface(const nsIID& aIID, void** aInstancePtr)
@@ -783,17 +843,17 @@ nsresult nsView::CreateWidgetForPopup(ns
 
 void
 nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility)
 {
   NS_ABORT_IF_FALSE(mWindow, "Must have a window to initialize");
 
   ViewWrapper* wrapper = new ViewWrapper(this);
   NS_ADDREF(wrapper); // Will be released in ~nsView
-  mWindow->SetClientData(wrapper);
+  mWindow->SetWidgetListener(wrapper);
 
   if (aEnableDragDrop) {
     mWindow->EnableDragDrop(true);
   }
       
   // propagate the z-index to the widget.
   UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
 
@@ -874,47 +934,45 @@ void nsView::SetZIndex(bool aAuto, PRInt
 
 void nsView::AssertNoWindow()
 {
   // XXX: it would be nice to make this a strong assert
   if (NS_UNLIKELY(mWindow)) {
     NS_ERROR("We already have a window for this view? BAD");
     ViewWrapper* wrapper = GetWrapperFor(mWindow);
     NS_IF_RELEASE(wrapper);
-    mWindow->SetClientData(nullptr);
+    mWindow->SetWidgetListener(nullptr);
     mWindow->Destroy();
     NS_RELEASE(mWindow);
   }
 }
 
 //
 // internal window creation functions
 //
 EVENT_CALLBACK nsIView::AttachWidgetEventHandler(nsIWidget* aWidget)
 {
 #ifdef DEBUG
-  void* data = nullptr;
-  aWidget->GetClientData(data);
-  NS_ASSERTION(!data, "Already got client data");
+  NS_ASSERTION(!aWidget->GetWidgetListener(), "Already have a widget listener");
 #endif
 
   ViewWrapper* wrapper = new ViewWrapper(Impl());
   if (!wrapper)
     return nullptr;
   NS_ADDREF(wrapper); // Will be released in DetachWidgetEventHandler
-  aWidget->SetClientData(wrapper);
+  aWidget->SetWidgetListener(wrapper);
   return ::HandleEvent;
 }
 
 void nsIView::DetachWidgetEventHandler(nsIWidget* aWidget)
 {
   ViewWrapper* wrapper = GetWrapperFor(aWidget);
   NS_ASSERTION(!wrapper || wrapper->GetView() == this, "Wrong view");
   NS_IF_RELEASE(wrapper);
-  aWidget->SetClientData(nullptr);
+  aWidget->SetWidgetListener(nullptr);
 }
 
 #ifdef DEBUG
 void nsIView::List(FILE* out, PRInt32 aIndent) const
 {
   PRInt32 i;
   for (i = aIndent; --i >= 0; ) fputs("  ", out);
   fprintf(out, "%p ", (void*)this);
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -640,262 +640,135 @@ void nsViewManager::InvalidateViews(nsVi
   // Invalidate all children as well.
   nsView* childView = aView->GetFirstChild();
   while (nullptr != childView)  {
     childView->GetViewManager()->InvalidateViews(childView);
     childView = childView->GetNextSibling();
   }
 }
 
-static bool
-IsViewForPopup(nsIView* aView)
+void nsViewManager::WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint)
 {
-  nsIWidget* widget = aView->GetWidget();
-  if (widget) {
-    nsWindowType type;
-    widget->GetWindowType(type);
-    return (type == eWindowType_popup);
+  if (IsRefreshDriverPaintingEnabled())
+    return;
+
+  if (!aWidget || !mContext)
+    return;
+
+  // If an ancestor widget was hidden and then shown, we could
+  // have a delayed resize to handle.
+  for (nsViewManager *vm = this; vm;
+       vm = vm->mRootView->GetParent()
+              ? vm->mRootView->GetParent()->GetViewManager()
+              : nullptr) {
+    if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+        vm->mRootView->IsEffectivelyVisible() &&
+        mPresShell && mPresShell->IsVisible()) {
+      vm->FlushDelayedResize(true);
+      vm->InvalidateView(vm->mRootView);
+    }
+  }
+
+  // Flush things like reflows and plugin widget geometry updates by
+  // calling WillPaint on observer presShells.
+  nsRefPtr<nsViewManager> rootVM = RootViewManager();
+  if (mPresShell) {
+    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);
+  }
+
+  // Flush view widget geometry updates and invalidations.
+  rootVM->ProcessPendingUpdates();
+}
+
+bool nsViewManager::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion,
+                                bool aSentWillPaint, bool aWillSendDidPaint)
+ {
+  if (!aWidget || !mContext)
+    return false;
+
+  NS_ASSERTION(IsPaintingAllowed(),
+               "shouldn't be receiving paint events while painting is disallowed!");
+
+  if (!aSentWillPaint && !IsRefreshDriverPaintingEnabled()) {
+    WillPaintWindow(aWidget, aWillSendDidPaint);
+  }
+
+  // Get the view pointer here since NS_WILL_PAINT might have
+  // destroyed it during CallWillPaintOnObservers (bug 378273).
+  nsView* view = nsView::GetViewFor(aWidget);
+  if (view && !aRegion.IsEmpty()) {
+    Refresh(view, aRegion, aWillSendDidPaint);
   }
 
-  return false;
+  return true;
+}
+
+void nsViewManager::DidPaintWindow()
+{
+  if (!IsRefreshDriverPaintingEnabled()) {
+    mRootViewManager->CallDidPaintOnObserver();
+  }
 }
 
-NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
-                                           nsIView* aView, nsEventStatus *aStatus)
+nsresult nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsIView* aView, nsEventStatus* aStatus)
 {
-  NS_ASSERTION(!aView || static_cast<nsView*>(aView)->GetViewManager() == this,
-               "wrong view manager");
+  SAMPLE_LABEL("event", "nsViewManager::DispatchEvent");
+
+  if ((NS_IS_MOUSE_EVENT(aEvent) &&
+       // Ignore mouse events that we synthesize.
+       static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal &&
+       // Ignore mouse exit and enter (we'll get moves if the user
+       // is really moving the mouse) since we get them when we
+       // create and destroy widgets.
+       aEvent->message != NS_MOUSE_EXIT &&
+       aEvent->message != NS_MOUSE_ENTER) ||
+      NS_IS_KEY_EVENT(aEvent) ||
+      NS_IS_IME_EVENT(aEvent) ||
+      aEvent->message == NS_PLUGIN_INPUT_EVENT) {
+    gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
+  }
+
+  // Find the view whose coordinates system we're in.
+  nsIView* view = aView;
+  bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
+  if (dispatchUsingCoordinates) {
+    // Will dispatch using coordinates. Pretty bogus but it's consistent
+    // with what presshell does.
+    view = GetDisplayRootFor(view);
+  }
 
-  SAMPLE_LABEL("event", "nsViewManager::DispatchEvent");
+  // If the view has no frame, look for a view that does.
+  nsIFrame* frame = view->GetFrame();
+  if (!frame &&
+      (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) ||
+       NS_IS_IME_RELATED_EVENT(aEvent) ||
+       NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent) ||
+       aEvent->message == NS_PLUGIN_ACTIVATE ||
+       aEvent->message == NS_PLUGIN_FOCUS)) {
+    while (view && !view->GetFrame()) {
+      view = view->GetParent();
+    }
+
+    if (view) {
+      frame = view->GetFrame();
+    }
+  }
+
+  if (nullptr != frame) {
+    // Hold a refcount to the presshell. The continued existence of the
+    // presshell will delay deletion of this view hierarchy should the event
+    // want to cause its destruction in, say, some JavaScript event handler.
+    nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
+    if (shell) {
+      return shell->HandleEvent(frame, aEvent, false, aStatus);
+    }
+  }
 
   *aStatus = nsEventStatus_eIgnore;
 
-  switch(aEvent->message)
-    {
-    case NS_SIZE:
-      {
-        if (aView)
-          {
-            // client area dimensions are set on the view
-            nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width;
-            nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height;
-
-            // The root view may not be set if this is the resize associated with
-            // window creation
-
-            if (aView == mRootView)
-              {
-                PRInt32 p2a = AppUnitsPerDevPixel();
-                SetWindowDimensions(NSIntPixelsToAppUnits(width, p2a),
-                                    NSIntPixelsToAppUnits(height, p2a));
-                *aStatus = nsEventStatus_eConsumeNoDefault;
-              }
-            else if (IsViewForPopup(aView))
-              {
-                nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-                if (pm)
-                  {
-                    pm->PopupResized(aView->GetFrame(), nsIntSize(width, height));
-                    *aStatus = nsEventStatus_eConsumeNoDefault;
-                  }
-              }
-          }
-        }
-
-        break;
-
-    case NS_MOVE:
-      {
-        // A popup's parent view is the root view for the parent window, so when
-        // a popup moves, the popup's frame and view position must be updated
-        // to match.
-        if (aView && IsViewForPopup(aView))
-          {
-            nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-            if (pm)
-              {
-                pm->PopupMoved(aView->GetFrame(), aEvent->refPoint);
-                *aStatus = nsEventStatus_eConsumeNoDefault;
-              }
-          }
-        break;
-      }
-
-    case NS_XUL_CLOSE:
-      {
-        // if this is a popup, make a request to hide it. Note that a popuphidden
-        // event listener may cancel the event and the popup will not be hidden.
-        nsIWidget* widget = aView->GetWidget();
-        if (widget) {
-          nsWindowType type;
-          widget->GetWindowType(type);
-          if (type == eWindowType_popup) {
-            nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-            if (pm) {
-              pm->HidePopup(aView->GetFrame());
-              *aStatus = nsEventStatus_eConsumeNoDefault;
-            }
-          }
-        }
-      }
-      break;
-
-    case NS_WILL_PAINT:
-      {
-        if (!aView || !mContext)
-          break;
-
-        *aStatus = nsEventStatus_eConsumeNoDefault;
-    
-        if (!IsRefreshDriverPaintingEnabled()) {
-
-          nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
-
-          NS_ASSERTION(static_cast<nsView*>(aView) ==
-                         nsView::GetViewFor(event->widget),
-                       "view/widget mismatch");
-
-          // If an ancestor widget was hidden and then shown, we could
-          // have a delayed resize to handle.
-          for (nsViewManager *vm = this; vm;
-               vm = vm->mRootView->GetParent()
-                      ? vm->mRootView->GetParent()->GetViewManager()
-                      : nullptr) {
-            if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-                vm->mRootView->IsEffectivelyVisible() &&
-                mPresShell && mPresShell->IsVisible()) {
-              vm->FlushDelayedResize(true);
-              vm->InvalidateView(vm->mRootView);
-            }
-          }
-
-          // Flush things like reflows and plugin widget geometry updates by
-          // calling WillPaint on observer presShells.
-          nsRefPtr<nsViewManager> rootVM = RootViewManager();
-          if (mPresShell) {
-            rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
-          }
-          // Flush view widget geometry updates and invalidations.
-          rootVM->ProcessPendingUpdates();
-        }
-      }
-      break;
-
-    case NS_PAINT:
-      {
-        if (!aView || !mContext)
-          break;
-
-        *aStatus = nsEventStatus_eConsumeNoDefault;
-        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
-        nsView* view = static_cast<nsView*>(aView);
-        NS_ASSERTION(view == nsView::GetViewFor(event->widget),
-                     "view/widget mismatch");
-        NS_ASSERTION(IsPaintingAllowed(),
-                     "shouldn't be receiving paint events while painting is "
-                     "disallowed!");
-
-        if (!event->didSendWillPaint && !IsRefreshDriverPaintingEnabled()) {
-          // Send NS_WILL_PAINT event ourselves.
-          nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget);
-          willPaintEvent.willSendDidPaint = event->willSendDidPaint;
-          DispatchEvent(&willPaintEvent, view, aStatus);
-
-          // Get the view pointer again since NS_WILL_PAINT might have
-          // destroyed it during CallWillPaintOnObservers (bug 378273).
-          view = nsView::GetViewFor(event->widget);
-        }
-
-        if (!view || event->region.IsEmpty())
-          break;
-
-        // Paint.
-        Refresh(view, event->region, event->willSendDidPaint);
-
-        break;
-      }
-
-    case NS_DID_PAINT: {
-      if (!IsRefreshDriverPaintingEnabled()) {
-        nsRefPtr<nsViewManager> rootVM = RootViewManager();
-        rootVM->CallDidPaintOnObserver();
-      }
-      break;
-    }
-
-    case NS_SETZLEVEL:
-      /* Don't pass these events through. Passing them through
-         causes performance problems on pages with lots of views/frames 
-         @see bug 112861 */
-      *aStatus = nsEventStatus_eConsumeNoDefault;
-      break;
-
-    default:
-      {
-        if ((NS_IS_MOUSE_EVENT(aEvent) &&
-             // Ignore mouse events that we synthesize.
-             static_cast<nsMouseEvent*>(aEvent)->reason ==
-               nsMouseEvent::eReal &&
-             // Ignore mouse exit and enter (we'll get moves if the user
-             // is really moving the mouse) since we get them when we
-             // create and destroy widgets.
-             aEvent->message != NS_MOUSE_EXIT &&
-             aEvent->message != NS_MOUSE_ENTER) ||
-            NS_IS_KEY_EVENT(aEvent) ||
-            NS_IS_IME_EVENT(aEvent) ||
-            aEvent->message == NS_PLUGIN_INPUT_EVENT) {
-          gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
-        }
-
-        if (aEvent->message == NS_DEACTIVATE) {
-          // if a window is deactivated, clear the mouse capture regardless
-          // of what is capturing
-          nsIPresShell::ClearMouseCapture(nullptr);
-        }
-
-        // Find the view whose coordinates system we're in.
-        nsIView* view = aView;
-        bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
-        if (dispatchUsingCoordinates) {
-          // Will dispatch using coordinates. Pretty bogus but it's consistent
-          // with what presshell does.
-          view = GetDisplayRootFor(view);
-        }
-  
-        // If the view has no frame, look for a view that does.
-        nsIFrame* frame = view->GetFrame();
-        if (!frame &&
-            (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) ||
-             NS_IS_IME_RELATED_EVENT(aEvent) ||
-             NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent) ||
-             aEvent->message == NS_PLUGIN_ACTIVATE ||
-             aEvent->message == NS_PLUGIN_FOCUS)) {
-          while (view && !view->GetFrame()) {
-            view = view->GetParent();
-          }
-
-          if (view) {
-            frame = view->GetFrame();
-          }
-        }
-
-        if (nullptr != frame) {
-          // Hold a refcount to the presshell. The continued existence of the
-          // presshell will delay deletion of this view hierarchy should the event
-          // want to cause its destruction in, say, some JavaScript event handler.
-          nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
-          if (shell) {
-            shell->HandleEvent(frame, aEvent, false, aStatus);
-          }
-        }
-    
-        break;
-      }
-    }
-
   return NS_OK;
 }
 
 // Recursively reparent widgets if necessary 
 
 void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)
 {
   NS_PRECONDITION(aNewWidget, "");
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -163,16 +163,21 @@ public: // NOT in nsIViewManager, so pri
   nsViewManager* RootViewManager() const { return mRootViewManager; }
   bool IsRootVM() const { return this == RootViewManager(); }
 
   // Whether synchronous painting is allowed at the moment. For example,
   // widget geometry changes can cause synchronous painting, so they need to
   // be deferred while refresh is disabled.
   bool IsPaintingAllowed() { return RootViewManager()->mRefreshDisableCount == 0; }
 
+  void WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint);
+  bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion,
+                   bool aSentWillPaint, bool aWillSendDidPaint);
+  void DidPaintWindow();
+
   // Call this when you need to let the viewmanager know that it now has
   // pending updates.
   void PostPendingUpdate();
 
   PRUint32 AppUnitsPerDevPixel() const
   {
     return mContext->AppUnitsPerDevPixel();
   }
--- a/widget/Makefile.in
+++ b/widget/Makefile.in
@@ -67,16 +67,17 @@ EXPORTS		= \
 		nsEvent.h \
 		nsNativeWidget.h \
 		nsWidgetInitData.h \
 		nsWidgetsCID.h \
 		nsIPluginWidget.h \
 		nsINativeKeyBindings.h \
 		nsIDeviceContextSpec.h \
 		nsIRollupListener.h \
+		nsIWidgetListener.h \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 EXPORTS		+= \
 		nsINativeMenuService.h \
 		nsIPrintDialogService.h \
 		$(NULL)
 endif
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -17,16 +17,17 @@ using mozilla::dom::ContentParent;
 using mozilla::dom::ContentChild;
 using mozilla::unused;
 
 #include "nsAppShell.h"
 #include "nsIdleService.h"
 #include "nsWindow.h"
 #include "nsIObserverService.h"
 #include "nsFocusManager.h"
+#include "nsIWidgetListener.h"
 
 #include "nsRenderingContext.h"
 #include "nsIDOMSimpleGestureEvent.h"
 #include "nsDOMTouchEvent.h"
 
 #include "nsGkAtoms.h"
 #include "nsWidgetsCID.h"
 #include "nsGfxCIID.h"
@@ -565,31 +566,34 @@ nsWindow::BringToFront()
     nsWindow *newTop = this;
     if (!gTopLevelWindows.IsEmpty())
         oldTop = gTopLevelWindows[0];
 
     gTopLevelWindows.RemoveElement(this);
     gTopLevelWindows.InsertElementAt(0, this);
 
     if (oldTop) {
-        nsGUIEvent event(true, NS_DEACTIVATE, oldTop);
-        DispatchEvent(&event);
+      nsIWidgetListener* listener = oldTop->GetWidgetListener();
+      if (listener) {
+          listener->WindowDeactivated();
+      }
     }
 
     if (Destroyed()) {
         // somehow the deactivate event handler destroyed this window.
         // try to recover by grabbing the next window in line and activating
         // that instead
         if (gTopLevelWindows.IsEmpty())
             return;
         newTop = gTopLevelWindows[0];
     }
 
-    nsGUIEvent event(true, NS_ACTIVATE, newTop);
-    DispatchEvent(&event);
+    if (mWidgetListener) {
+        mWidgetListener->WindowActivated();
+    }
 
     // force a window resize
     nsAppShell::gAppShell->ResendLastResizeEvent(newTop);
     RedrawAll();
 }
 
 NS_IMETHODIMP
 nsWindow::GetScreenBounds(nsIntRect &aRect)
@@ -959,70 +963,69 @@ nsWindow::DrawTo(gfxASurface *targetSurf
     nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
     return DrawTo(targetSurface, boundsRect);
 }
 
 bool
 nsWindow::DrawTo(gfxASurface *targetSurface, const nsIntRect &invalidRect)
 {
     mozilla::layers::RenderTraceScope trace("DrawTo", "717171");
-    if (!mIsVisible)
+    if (!mIsVisible || !mWidgetListener)
         return false;
 
     nsRefPtr<nsWindow> kungFuDeathGrip(this);
-    nsEventStatus status;
     nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
 
     // Figure out if any of our children cover this widget completely
     PRInt32 coveringChildIndex = -1;
     for (PRUint32 i = 0; i < mChildren.Length(); ++i) {
         if (mChildren[i]->mBounds.IsEmpty())
             continue;
 
         if (mChildren[i]->mBounds.Contains(boundsRect)) {
             coveringChildIndex = PRInt32(i);
         }
     }
 
     // If we have no covering child, then we need to render this.
     if (coveringChildIndex == -1) {
-        nsPaintEvent event(true, NS_PAINT, this);
-        event.region = invalidRect;
+        bool painted = false;
+        nsIntRegion region = invalidRect;
 
         switch (GetLayerManager(nullptr)->GetBackendType()) {
             case mozilla::layers::LAYERS_BASIC: {
 
                 nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
 
                 {
                     mozilla::layers::RenderTraceScope trace2("Basic DrawTo", "727272");
                     AutoLayerManagerSetup
                       setupLayerManager(this, ctx, mozilla::layers::BUFFER_NONE);
 
-                    status = DispatchEvent(&event);
+                    painted = mWidgetListener->PaintWindow(this, region, false, false);
                 }
 
                 // XXX uhh.. we can't just ignore this because we no longer have
                 // what we needed before, but let's keep drawing the children anyway?
 #if 0
-                if (status == nsEventStatus_eIgnore)
+                if (!painted)
                     return false;
 #endif
 
                 // XXX if we got an ignore for the parent, do we still want to draw the children?
                 // We don't really have a good way not to...
                 break;
             }
 
             case mozilla::layers::LAYERS_OPENGL: {
 
                 static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
                     SetClippingRegion(nsIntRegion(boundsRect));
 
-                status = DispatchEvent(&event);
+                painted = mWidgetListener->PaintWindow(this, region, false, false);
                 break;
             }
 
             default:
                 NS_ERROR("Invalid layer manager");
         }
 
         // We had no covering child, so make sure we draw all the children,
@@ -1222,34 +1225,24 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
 
         sview.EndDrawing();
     }
 }
 
 void
 nsWindow::OnSizeChanged(const gfxIntSize& aSize)
 {
-    int w = aSize.width;
-    int h = aSize.height;
-
-    ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, w, h);
-
-    nsRefPtr<nsWindow> kungFuDeathGrip(this);
-    nsSizeEvent event(true, NS_SIZE, this);
-    InitEvent(event);
+    ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, aSize.width, aSize.height);
 
-    nsIntRect wsz(0, 0, w, h);
-    event.windowSize = &wsz;
-    event.mWinWidth = w;
-    event.mWinHeight = h;
+    mBounds.width = aSize.width;
+    mBounds.height = aSize.height;
 
-    mBounds.width = w;
-    mBounds.height = h;
-
-    DispatchEvent(&event);
+    if (mWidgetListener) {
+        mWidgetListener->WindowResized(this, aSize.width, aSize.height);
+    }
 }
 
 void
 nsWindow::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
 {
     if (aPoint) {
         event.refPoint.x = aPoint->x;
         event.refPoint.y = aPoint->y;
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -474,17 +474,19 @@ public:
                                               PRUint32 aModifierFlags);
 
   virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint)
   { return SynthesizeNativeMouseEvent(aPoint, NSMouseMoved, 0); }
 
   // Mac specific methods
   
   virtual bool      DispatchWindowEvent(nsGUIEvent& event);
-  
+
+  bool PaintWindow(nsIntRegion aRegion);
+
 #ifdef ACCESSIBILITY
   already_AddRefed<Accessible> GetDocumentAccessible();
 #endif
 
   virtual void CreateCompositor();
   virtual gfxASurface* GetThebesSurface();
   virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect);
 
@@ -514,18 +516,18 @@ public:
 
   mozilla::widget::TextInputHandler* GetTextInputHandler()
   {
     return mTextInputHandler;
   }
 
 protected:
 
-  bool              ReportMoveEvent();
-  bool              ReportSizeEvent();
+  void              ReportMoveEvent();
+  void              ReportSizeEvent();
 
   // override to create different kinds of child views. Autoreleases, so
   // caller must retain.
   virtual NSView*   CreateCocoaView(NSRect inFrame);
   void              TearDownView();
 
   virtual already_AddRefed<nsIWidget>
   AllocateChildPopupWidget()
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -26,16 +26,17 @@
 #include "nsIViewManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIFile.h"
 #include "nsILocalFileMac.h"
 #include "nsGfxCIID.h"
 #include "nsIDOMSimpleGestureEvent.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsThemeConstants.h"
+#include "nsIWidgetListener.h"
 
 #include "nsDragService.h"
 #include "nsClipboard.h"
 #include "nsCursorManager.h"
 #include "nsWindowMap.h"
 #include "nsCocoaFeatures.h"
 #include "nsCocoaUtils.h"
 #include "nsMenuUtilsX.h"
@@ -1461,62 +1462,76 @@ NS_IMETHODIMP nsChildView::DispatchEvent
 
   aStatus = nsEventStatus_eIgnore;
 
   nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(mParentWidget ? mParentWidget : this);
   if (mParentWidget) {
     nsWindowType type;
     mParentWidget->GetWindowType(type);
     if (type == eWindowType_popup) {
-      // use the parent popup's widget if there is no view
-      void* clientData = nullptr;
+      // use the parent popup's widget if there is no listener
+      nsIWidgetListener* listener = nullptr;
       if (event->widget)
-        event->widget->GetClientData(clientData);
-      if (!clientData)
+        listener = event->widget->GetWidgetListener();
+      if (!listener)
         event->widget = mParentWidget;
     }
   }
 
-  bool restoreIsDispatchPaint = mIsDispatchPaint;
-  mIsDispatchPaint = mIsDispatchPaint || event->eventStructType == NS_PAINT_EVENT;
-
   if (mEventCallback)
     aStatus = (*mEventCallback)(event);
 
-  mIsDispatchPaint = restoreIsDispatchPaint;
-
   return NS_OK;
 }
 
 bool nsChildView::DispatchWindowEvent(nsGUIEvent &event)
 {
   nsEventStatus status;
   DispatchEvent(&event, status);
   return ConvertStatus(status);
 }
 
+bool nsChildView::PaintWindow(nsIntRegion aRegion)
+{
+  nsIWidget* widget = this;
+  nsIWidgetListener* listener = mWidgetListener;
+
+  // If there is no listener, use the parent popup's listener if that exists.
+  if (!listener && mParentWidget) {
+    nsWindowType type;
+    mParentWidget->GetWindowType(type);
+    if (type == eWindowType_popup) {
+      widget = mParentWidget;
+      listener = mParentWidget->GetWidgetListener();
+    }
+  }
+
+  if (!listener)
+    return false;
+
+  bool returnValue = false;
+  bool oldDispatchPaint = mIsDispatchPaint;
+  mIsDispatchPaint = true;
+  returnValue = listener->PaintWindow(widget, aRegion, true, false);
+  mIsDispatchPaint = oldDispatchPaint;
+  return returnValue;
+}
+
 #pragma mark -
 
-bool nsChildView::ReportMoveEvent()
-{
-  nsGUIEvent moveEvent(true, NS_MOVE, this);
-  moveEvent.refPoint.x = mBounds.x;
-  moveEvent.refPoint.y = mBounds.y;
-  moveEvent.time       = PR_IntervalNow();
-  return DispatchWindowEvent(moveEvent);
-}
-
-bool nsChildView::ReportSizeEvent()
-{
-  nsSizeEvent sizeEvent(true, NS_SIZE, this);
-  sizeEvent.time        = PR_IntervalNow();
-  sizeEvent.windowSize  = &mBounds;
-  sizeEvent.mWinWidth   = mBounds.width;
-  sizeEvent.mWinHeight  = mBounds.height;
-  return DispatchWindowEvent(sizeEvent);
+void nsChildView::ReportMoveEvent()
+{
+  if (mWidgetListener)
+    mWidgetListener->WindowMoved(this, mBounds.x, mBounds.y);
+}
+
+void nsChildView::ReportSizeEvent()
+{
+  if (mWidgetListener)
+    mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
 }
 
 #pragma mark -
 
 //    Return the offset between this child view and the screen.
 //    @return       -- widget origin in screen coordinates
 nsIntPoint nsChildView::WidgetToScreenOffset()
 {
@@ -2488,69 +2503,65 @@ NSEvent* gLastDragMouseDownEvent = nil;
   fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n  gecko bounds: [%d %d %d %d]\n",
            self, mGeckoChild,
            aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height, aContext,
            geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height);
 
   CGAffineTransform xform = CGContextGetCTM(aContext);
   fprintf (stderr, "  xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
 #endif
-  // Create the event so we can fill in its region
-  nsPaintEvent paintEvent(true, NS_PAINT, mGeckoChild);
-  paintEvent.didSendWillPaint = true;
+  nsIntRegion region;
 
   nsIntRect boundingRect =
     nsIntRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
   const NSRect *rects;
   NSInteger count, i;
   [[NSView focusView] getRectsBeingDrawn:&rects count:&count];
   if (count < MAX_RECTS_IN_REGION) {
     for (i = 0; i < count; ++i) {
       // Add the rect to the region.
       const NSRect& r = [self convertRect:rects[i] fromView:[NSView focusView]];
-      paintEvent.region.Or(paintEvent.region,
-        nsIntRect(r.origin.x, r.origin.y, r.size.width, r.size.height));
+      region.Or(region, nsIntRect(r.origin.x, r.origin.y, r.size.width, r.size.height));
     }
-    paintEvent.region.And(paintEvent.region, boundingRect);
+    region.And(region, boundingRect);
   } else {
-    paintEvent.region = boundingRect;
+    region = boundingRect;
   }
 
 #ifndef NP_NO_QUICKDRAW
   // Subtract quickdraw plugin rectangles from the region
   NSArray* subviews = [self subviews];
   for (int i = 0; i < int([subviews count]); ++i) {
     NSView* view = [subviews objectAtIndex:i];
     if (![view isKindOfClass:[ChildView class]] || [view isHidden])
       continue;
     ChildView* cview = (ChildView*) view;
     if ([cview isPluginView] && [cview pluginDrawingModel] == NPDrawingModelQuickDraw) {
       NSRect frame = [view frame];
-      paintEvent.region.Sub(paintEvent.region,
-        nsIntRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height));
+      region.Sub(region, nsIntRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height));
     }
   }
 #endif
 
   LayerManager *layerManager = mGeckoChild->GetLayerManager(nullptr);
   if (layerManager->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
     NSOpenGLContext *glContext;
 
     LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(layerManager);
-    manager->SetClippingRegion(paintEvent.region);
+    manager->SetClippingRegion(region);
     glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
 
     if (!mGLContext) {
       [self setGLContext:glContext];
     }
 
     [glContext setView:self];
     [glContext update];
 
-    mGeckoChild->DispatchWindowEvent(paintEvent);
+    mGeckoChild->PaintWindow(region);
 
     // Force OpenGL to refresh the very first time we draw. This works around a
     // Mac OS X bug that stops windows updating on OS X when we use OpenGL.
     if (!mDidForceRefreshOpenGL) {
       [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
       mDidForceRefreshOpenGL = YES;
     }
 
@@ -2561,32 +2572,32 @@ NSEvent* gLastDragMouseDownEvent = nil;
   NSSize bufferSize = [self bounds].size;
   nsRefPtr<gfxQuartzSurface> targetSurface =
     new gfxQuartzSurface(aContext, gfxSize(bufferSize.width, bufferSize.height));
   targetSurface->SetAllowUseAsSource(false);
 
   nsRefPtr<gfxContext> targetContext = new gfxContext(targetSurface);
 
   // Set up the clip region.
-  nsIntRegionRectIterator iter(paintEvent.region);
+  nsIntRegionRectIterator iter(region);
   targetContext->NewPath();
   for (;;) {
     const nsIntRect* r = iter.Next();
     if (!r)
       break;
     targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
   }
   targetContext->Clip();
 
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
   bool painted;
   {
     nsBaseWidget::AutoLayerManagerSetup
       setupLayerManager(mGeckoChild, targetContext, BUFFER_NONE);
-    painted = mGeckoChild->DispatchWindowEvent(paintEvent);
+    painted = mGeckoChild->PaintWindow(region);
   }
 
   // Force OpenGL to refresh the very first time we draw. This works around a
   // Mac OS X bug that stops windows updating on OS X when we use OpenGL.
   if (painted && !mDidForceRefreshOpenGL &&
       layerManager->AsShadowManager() && mUsingOMTCompositor) {
     if (!mDidForceRefreshOpenGL) {
       [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
@@ -2636,17 +2647,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   }
 }
 
 - (void)viewWillDraw
 {
   if (mGeckoChild) {
     // The OS normally *will* draw our NSWindow, no matter what we do here.
     // But Gecko can delete our parent widget(s) (along with mGeckoChild)
-    // while processing an NS_WILL_PAINT event, which closes our NSWindow and
+    // while processing a paint request, which closes our NSWindow and
     // makes the OS throw an NSInternalInconsistencyException assertion when
     // it tries to draw it.  Sometimes the OS also aborts the browser process.
     // So we need to retain our parent(s) here and not release it/them until
     // the next time through the main thread's run loop.  When we do this we
     // also need to retain and release mGeckoChild, which holds a strong
     // reference to us (otherwise we might have been deleted by the time
     // releaseWidgets: is called on us).  See bug 550392.
     nsIWidget* parent = mGeckoChild->GetParent();
@@ -2658,18 +2669,21 @@ NSEvent* gLastDragMouseDownEvent = nil;
         parent = parent->GetParent();
       }
       NS_ADDREF(mGeckoChild);
       [widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)mGeckoChild]];
       [self performSelector:@selector(releaseWidgets:)
                  withObject:widgetArray
                  afterDelay:0];
     }
-    nsPaintEvent paintEvent(true, NS_WILL_PAINT, mGeckoChild);
-    mGeckoChild->DispatchWindowEvent(paintEvent);
+
+    nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
+    if (listener) {
+      listener->WillPaintWindow(mGeckoChild, false);
+    }
   }
   [super viewWillDraw];
 }
 
 // Allows us to turn off setting up the clip region
 // before each drawRect. We already clip within gecko.
 - (BOOL)wantsDefaultClipping
 {
@@ -4283,32 +4297,36 @@ static PRInt32 RoundUp(double aDouble)
   // check to see if the window implements the mozWindow protocol. This
   // allows embedders to avoid re-entrant calls to -makeKeyAndOrderFront,
   // which can happen because these activate calls propagate out
   // to the embedder via nsIEmbeddingSiteWindow::SetFocus().
   BOOL isMozWindow = [[self window] respondsToSelector:@selector(setSuppressMakeKeyFront:)];
   if (isMozWindow)
     [[self window] setSuppressMakeKeyFront:YES];
 
-  [self sendFocusEvent:NS_ACTIVATE];
+  nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
+  if (listener)
+    listener->WindowActivated();
 
   if (isMozWindow)
     [[self window] setSuppressMakeKeyFront:NO];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (void)viewsWindowDidResignKey
 {
   if (!mGeckoChild)
     return;
 
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
 
-  [self sendFocusEvent:NS_DEACTIVATE];
+  nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
+  if (listener)
+    listener->WindowDeactivated();
 }
 
 // If the call to removeFromSuperview isn't delayed from nsChildView::
 // TearDownView(), the NSView hierarchy might get changed during calls to
 // [ChildView drawRect:], which leads to "beyond bounds" exceptions in
 // NSCFArray.  For more info see bmo bug 373122.  Apple's docs claim that
 // removeFromSuperviewWithoutNeedingDisplay "can be safely invoked during
 // display" (whatever "display" means).  But it's _not_ true that it can be
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -146,17 +146,16 @@ typedef struct _nsCocoaWindowList {
   // NS_DEACTIVATE to Gecko for toplevel widgets.  Starts out
   // false.
   bool mToplevelActiveState;
   BOOL mHasEverBeenZoomed;
 }
 + (void)paintMenubarForWindow:(NSWindow*)aWindow;
 - (id)initWithGeckoWindow:(nsCocoaWindow*)geckoWind;
 - (void)windowDidResize:(NSNotification*)aNotification;
-- (void)sendFocusEvent:(PRUint32)eventType;
 - (nsCocoaWindow*)geckoWidget;
 - (bool)toplevelActiveState;
 - (void)sendToplevelActivateEvents;
 - (void)sendToplevelDeactivateEvents;
 @end
 
 @class ToolbarWindow;
 
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -24,16 +24,17 @@
 #include "nsThreadUtils.h"
 #include "nsMenuBarX.h"
 #include "nsMenuUtilsX.h"
 #include "nsStyleConsts.h"
 #include "nsNativeThemeColors.h"
 #include "nsChildView.h"
 #include "nsCocoaFeatures.h"
 #include "nsIScreenManager.h"
+#include "nsIWidgetListener.h"
 
 #include "gfxPlatform.h"
 #include "qcms.h"
 
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace layers {
@@ -1402,27 +1403,20 @@ NS_IMETHODIMP nsCocoaWindow::Invalidate(
 // knows about it.
 bool nsCocoaWindow::DragEvent(unsigned int aMessage, Point aMouseGlobal, UInt16 aKeyModifiers)
 {
   return false;
 }
 
 NS_IMETHODIMP nsCocoaWindow::SendSetZLevelEvent()
 {
-  nsZLevelEvent event(true, NS_SETZLEVEL, this);
-
-  event.refPoint.x = mBounds.x;
-  event.refPoint.y = mBounds.y;
-  event.time = PR_IntervalNow();
-
-  event.mImmediate = true;
-
-  nsEventStatus status = nsEventStatus_eIgnore;
-  DispatchEvent(&event, status);
-
+  nsWindowZ placement = nsWindowZTop;
+  nsIWidget* actualBelow;
+  if (mWidgetListener)
+    mWidgetListener->ZLevelChanged(true, &placement, nullptr, &actualBelow);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsCocoaWindow::GetChildSheet(bool aShown, nsCocoaWindow** _retval)
 {
   nsIWidget* child = GetFirstChild();
 
   while (child) {
@@ -1512,22 +1506,18 @@ nsCocoaWindow::ReportMoveEvent()
   if (mInReportMoveEvent) {
     return;
   }
   mInReportMoveEvent = true;
 
   UpdateBounds();
 
   // Dispatch the move event to Gecko
-  nsGUIEvent guiEvent(true, NS_MOVE, this);
-  guiEvent.refPoint.x = mBounds.x;
-  guiEvent.refPoint.y = mBounds.y;
-  guiEvent.time = PR_IntervalNow();
-  nsEventStatus status = nsEventStatus_eIgnore;
-  DispatchEvent(&guiEvent, status);
+  if (mWidgetListener)
+    mWidgetListener->WindowMoved(this, mBounds.x, mBounds.y);
 
   mInReportMoveEvent = false;
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 void
 nsCocoaWindow::DispatchSizeModeEvent()
@@ -1541,42 +1531,33 @@ nsCocoaWindow::DispatchSizeModeEvent()
   // Don't dispatch a sizemode event if:
   // 1. the window is transitioning to fullscreen
   // 2. the new sizemode is the same as the current sizemode
   if (mInFullScreenTransition || mSizeMode == newMode) {
     return;
   }
 
   mSizeMode = newMode;
-  nsSizeModeEvent event(true, NS_SIZEMODE, this);
-  event.mSizeMode = mSizeMode;
-  event.time = PR_IntervalNow();
-
-  nsEventStatus status = nsEventStatus_eIgnore;
-  DispatchEvent(&event, status);
+  if (mWidgetListener) {
+    mWidgetListener->SizeModeChanged(newMode);
+  }
 }
 
 void
 nsCocoaWindow::ReportSizeEvent()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   UpdateBounds();
 
-  nsSizeEvent sizeEvent(true, NS_SIZE, this);
-  sizeEvent.time = PR_IntervalNow();
-
-  nsIntRect innerBounds;
-  GetClientBounds(innerBounds);
-  sizeEvent.windowSize = &innerBounds;
-  sizeEvent.mWinWidth  = mBounds.width;
-  sizeEvent.mWinHeight = mBounds.height;
-
-  nsEventStatus status = nsEventStatus_eIgnore;
-  DispatchEvent(&sizeEvent, status);
+  if (mWidgetListener) {
+    nsIntRect innerBounds;
+    GetClientBounds(innerBounds);
+    mWidgetListener->WindowResized(this, innerBounds.width, innerBounds.height);
+  }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 void nsCocoaWindow::SetMenuBar(nsMenuBarX *aMenuBar)
 {
   if (mMenuBar)
     mMenuBar->SetParent(nullptr);
@@ -2131,21 +2112,19 @@ bool nsCocoaWindow::ShouldFocusPlugin()
 - (void)windowDidMove:(NSNotification *)aNotification
 {
   if (mGeckoWindow)
     mGeckoWindow->ReportMoveEvent();
 }
 
 - (BOOL)windowShouldClose:(id)sender
 {
-  // We only want to send NS_XUL_CLOSE and let gecko close the window
-  nsGUIEvent guiEvent(true, NS_XUL_CLOSE, mGeckoWindow);
-  guiEvent.time = PR_IntervalNow();
-  nsEventStatus status = nsEventStatus_eIgnore;
-  mGeckoWindow->DispatchEvent(&guiEvent, status);
+  nsIWidgetListener* listener = mGeckoWindow ? mGeckoWindow->GetWidgetListener() : nullptr;
+  if (listener)
+    listener->RequestWindowClose(mGeckoWindow);
   return NO; // gecko will do it
 }
 
 - (void)windowWillClose:(NSNotification *)aNotification
 {
   RollUpPopups();
 }
 
@@ -2170,27 +2149,16 @@ bool nsCocoaWindow::ShouldFocusPlugin()
 {
   if (!mHasEverBeenZoomed && [window isZoomed])
     return NO; // See bug 429954.
 
   mHasEverBeenZoomed = YES;
   return YES;
 }
 
-- (void)sendFocusEvent:(PRUint32)eventType
-{
-  if (!mGeckoWindow)
-    return;
-
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsGUIEvent focusGuiEvent(true, eventType, mGeckoWindow);
-  focusGuiEvent.time = PR_IntervalNow();
-  mGeckoWindow->DispatchEvent(&focusGuiEvent, status);
-}
-
 - (void)didEndSheet:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   // Note: 'contextInfo' (if it is set) is the window that is the parent of
   // the sheet.  The value of contextInfo is determined in
   // nsCocoaWindow::Show().  If it's set, 'contextInfo' is always the top-
   // level window, not another sheet itself.  But 'contextInfo' is nil if
@@ -2212,26 +2180,30 @@ bool nsCocoaWindow::ShouldFocusPlugin()
 
 - (bool)toplevelActiveState
 {
   return mToplevelActiveState;
 }
 
 - (void)sendToplevelActivateEvents
 {
-  if (!mToplevelActiveState) {
-    [self sendFocusEvent:NS_ACTIVATE];
+  if (!mToplevelActiveState && mGeckoWindow) {
+    nsIWidgetListener* listener = mGeckoWindow->GetWidgetListener();
+    if (listener)
+      listener->WindowActivated();
     mToplevelActiveState = true;
   }
 }
 
 - (void)sendToplevelDeactivateEvents
 {
-  if (mToplevelActiveState) {
-    [self sendFocusEvent:NS_DEACTIVATE];
+  if (mToplevelActiveState && mGeckoWindow) {
+    nsIWidgetListener* listener = mGeckoWindow->GetWidgetListener();
+    if (listener)
+      listener->WindowDeactivated();
     mToplevelActiveState = false;
   }
 }
 
 @end
 
 static float
 GetDPI(NSWindow* aWindow)
@@ -2672,20 +2644,20 @@ static const NSString* kStateShowsToolba
 
   RollUpPopups();
 
   if ([[self delegate] isKindOfClass:[WindowDelegate class]]) {
     WindowDelegate *windowDelegate = (WindowDelegate *)[self delegate];
     nsCocoaWindow *geckoWindow = [windowDelegate geckoWidget];
     if (!geckoWindow)
       return;
-    nsEventStatus status = nsEventStatus_eIgnore;
-    nsGUIEvent guiEvent(true, NS_OS_TOOLBAR, geckoWindow);
-    guiEvent.time = PR_IntervalNow();
-    geckoWindow->DispatchEvent(&guiEvent, status);
+
+    nsIWidgetListener* listener = geckoWindow->GetWidgetListener();
+    if (listener)
+      listener->OSToolbarButtonPressed();
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 // Retain and release "self" to avoid crashes when our widget (and its native
 // window) is closed as a result of processing a key equivalent (e.g.
 // Command+w or Command+q).  This workaround is only needed for a window
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -29,16 +29,17 @@
 #include "GLContextProvider.h"
 #include "LayerManagerOGL.h"
 #include "nsAutoPtr.h"
 #include "nsAppShell.h"
 #include "nsIdleService.h"
 #include "nsScreenManagerGonk.h"
 #include "nsTArray.h"
 #include "nsWindow.h"
+#include "nsIWidgetListener.h"
 #include "cutils/properties.h"
 #include "BasicLayers.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args)
 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args)
 
 #define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)
@@ -100,26 +101,22 @@ EffectiveScreenRotation()
 
 class ScreenOnOffEvent : public nsRunnable {
 public:
     ScreenOnOffEvent(bool on)
         : mIsOn(on)
     {}
 
     NS_IMETHOD Run() {
-        nsSizeModeEvent event(true, NS_SIZEMODE, NULL);
-        nsEventStatus status;
-
-        event.time = PR_Now() / 1000;
-        event.mSizeMode = mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized;
-
         for (PRUint32 i = 0; i < sTopWindows.Length(); i++) {
             nsWindow *win = sTopWindows[i];
-            event.widget = win;
-            win->DispatchEvent(&event, status);
+
+            if (nsIWidgetListener* listener = win->GetWidgetListener()) {
+                listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized);
+            }
         }
 
         return NS_OK;
     }
 
 private:
     bool mIsOn;
 };
@@ -231,50 +228,53 @@ nsWindow::DoDraw(void)
         return;
     }
 
     if (!gWindowToRedraw) {
         LOG("  no window to draw, bailing");
         return;
     }
 
-    nsPaintEvent event(true, NS_PAINT, gWindowToRedraw);
-    event.region = gWindowToRedraw->mDirtyRegion;
+    nsIntRegion region = gWindowToRedraw->mDirtyRegion;
     gWindowToRedraw->mDirtyRegion.SetEmpty();
 
     LayerManager* lm = gWindowToRedraw->GetLayerManager();
     if (mozilla::layers::LAYERS_OPENGL == lm->GetBackendType()) {
         LayerManagerOGL* oglm = static_cast<LayerManagerOGL*>(lm);
-        oglm->SetClippingRegion(event.region);
+        oglm->SetClippingRegion(region);
         oglm->SetWorldTransform(sRotationMatrix);
-        gWindowToRedraw->mEventCallback(&event);
+
+        if (nsIWidgetListener* listener = gWindowToRedraw->GetWidgetListener())
+          listener->PaintWindow(gWindowToRedraw, region, false, false);
     } else if (mozilla::layers::LAYERS_BASIC == lm->GetBackendType()) {
         MOZ_ASSERT(sFramebufferOpen || sUsingOMTC);
         nsRefPtr<gfxASurface> targetSurface;
 
         if(sUsingOMTC)
             targetSurface = sOMTCSurface;
         else
             targetSurface = Framebuffer::BackBuffer();
 
         {
             nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
-            gfxUtils::PathFromRegion(ctx, event.region);
+            gfxUtils::PathFromRegion(ctx, region);
             ctx->Clip();
 
             // No double-buffering needed.
             AutoLayerManagerSetup setupLayerManager(
                 gWindowToRedraw, ctx, mozilla::layers::BUFFER_NONE,
                 ScreenRotation(EffectiveScreenRotation()));
-            gWindowToRedraw->mEventCallback(&event);
+
+            if (nsIWidgetListener* listener = gWindowToRedraw->GetWidgetListener())
+              listener->PaintWindow(gWindowToRedraw, region, false, false);
         }
 
         if (!sUsingOMTC) {
             targetSurface->Flush();
-            Framebuffer::Present(event.region);
+            Framebuffer::Present(region);
         }
     } else {
         NS_RUNTIMEABORT("Unexpected layer manager type");
     }
 }
 
 nsEventStatus
 nsWindow::DispatchInputEvent(nsGUIEvent &aEvent)
@@ -388,26 +388,19 @@ nsWindow::Resize(PRInt32 aWidth,
 
 NS_IMETHODIMP
 nsWindow::Resize(PRInt32 aX,
                  PRInt32 aY,
                  PRInt32 aWidth,
                  PRInt32 aHeight,
                  bool    aRepaint)
 {
-    nsSizeEvent event(true, NS_SIZE, this);
-    event.time = PR_Now() / 1000;
-
-    nsIntRect rect(aX, aY, aWidth, aHeight);
-    mBounds = rect;
-    event.windowSize = &rect;
-    event.mWinWidth = sVirtualBounds.width;
-    event.mWinHeight = sVirtualBounds.height;
-
-    (*mEventCallback)(&event);
+    mBounds = nsIntRect(aX, aY, aWidth, aHeight);
+    if (mWidgetListener)
+        mWidgetListener->WindowResized(this, aWidth, aHeight);
 
     if (aRepaint && gWindowToRedraw)
         gWindowToRedraw->Invalidate(sVirtualBounds);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -619,25 +612,25 @@ nsWindow::GetThebesSurface()
     // on direct assignment to a gfxASurface
     return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24);
 }
 
 void
 nsWindow::BringToTop()
 {
     if (!sTopWindows.IsEmpty()) {
-        nsGUIEvent event(true, NS_DEACTIVATE, sTopWindows[0]);
-        (*mEventCallback)(&event);
+        if (nsIWidgetListener* listener = sTopWindows[0]->GetWidgetListener())
+            listener->WindowDeactivated();
     }
 
     sTopWindows.RemoveElement(this);
     sTopWindows.InsertElementAt(0, this);
 
-    nsGUIEvent event(true, NS_ACTIVATE, this);
-    (*mEventCallback)(&event);
+    if (mWidgetListener)
+        mWidgetListener->WindowActivated();
     Invalidate(sVirtualBounds);
 }
 
 void
 nsWindow::UserActivity()
 {
     if (!mIdleService) {
         mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
--- a/widget/gtk2/nsWindow.cpp
+++ b/widget/gtk2/nsWindow.cpp
@@ -15,16 +15,17 @@
 #include "prlink.h"
 #include "nsWindow.h"
 #include "nsGTKToolkit.h"
 #include "nsIRollupListener.h"
 #include "nsIDOMNode.h"
 
 #include "nsWidgetsCID.h"
 #include "nsDragService.h"
+#include "nsIWidgetListener.h"
 
 #include "nsGtkKeyUtils.h"
 #include "nsGtkCursors.h"
 
 #include <gtk/gtk.h>
 #if defined(MOZ_WIDGET_GTK3)
 #include <gtk/gtkx.h>
 #endif
@@ -415,50 +416,34 @@ void
 nsWindow::CommonCreate(nsIWidget *aParent, bool aListenForResizes)
 {
     mParent = aParent;
     mListenForResizes = aListenForResizes;
     mCreated = true;
 }
 
 void
-nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
-{
-    nsSizeEvent event(true, NS_SIZE, this);
-
-    event.windowSize = &aRect;
-    event.refPoint.x = aRect.x;
-    event.refPoint.y = aRect.y;
-    event.mWinWidth = aRect.width;
-    event.mWinHeight = aRect.height;
-
-    nsEventStatus status;
-    DispatchEvent(&event, status);
-}
-
-void
 nsWindow::DispatchActivateEvent(void)
 {
     NS_ASSERTION(mContainer || mIsDestroyed,
                  "DispatchActivateEvent only intended for container windows");
 
 #ifdef ACCESSIBILITY
     DispatchActivateEventAccessible();
 #endif //ACCESSIBILITY
-    nsGUIEvent event(true, NS_ACTIVATE, this);
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+
+    if (mWidgetListener)
+      mWidgetListener->WindowActivated();
 }
 
 void
 nsWindow::DispatchDeactivateEvent(void)
 {
-    nsGUIEvent event(true, NS_DEACTIVATE, this);
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+    if (mWidgetListener)
+      mWidgetListener->WindowDeactivated();
 
 #ifdef ACCESSIBILITY
     DispatchDeactivateEventAccessible();
 #endif //ACCESSIBILITY
 }
 
 
 
@@ -1079,21 +1064,20 @@ nsWindow::Resize(PRInt32 aWidth, PRInt32
         }
         else {
             mNeedsResize = true;
         }
     }
 
     NotifyRollupGeometryChange(gRollupListener);
 
-    // synthesize a resize event if this isn't a toplevel
+    // send a resize notification if this is a toplevel
     if (mIsTopLevel || mListenForResizes) {
-        nsIntRect rect(mBounds.x, mBounds.y, aWidth, aHeight);
-        nsEventStatus status;
-        DispatchResizeEvent(rect, status);
+        if (mWidgetListener)
+            mWidgetListener->WindowResized(this, aWidth, aHeight);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
                        bool aRepaint)
@@ -1148,20 +1132,18 @@ nsWindow::Resize(PRInt32 aX, PRInt32 aY,
         else {
             mNeedsResize = true;
         }
     }
 
     NotifyRollupGeometryChange(gRollupListener);
 
     if (mIsTopLevel || mListenForResizes) {
-        // synthesize a resize event
-        nsIntRect rect(aX, aY, aWidth, aHeight);
-        nsEventStatus status;
-        DispatchResizeEvent(rect, status);
+        if (mWidgetListener)
+            mWidgetListener->WindowResized(this, aWidth, aHeight);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Enable(bool aState)
 {
@@ -1448,17 +1430,17 @@ nsWindow::SetFocus(bool aRaise)
     // Ensure owningWidget is the focused GtkWidget within its toplevel window.
     //
     // For eWindowType_popup, this GtkWidget may not actually be the one that
     // receives the key events as it may be the parent window that is active.
     if (!gtk_widget_is_focus(owningWidget)) {
         // This is synchronous.  It takes focus from a plugin or from a widget
         // in an embedder.  The focus manager already knows that this window
         // is active so gBlockActivateEvent avoids another (unnecessary)
-        // NS_ACTIVATE event.
+        // activate notification.
         gBlockActivateEvent = true;
         gtk_widget_grab_focus(owningWidget);
         gBlockActivateEvent = false;
     }
 
     // If this is the widget that already has focus, return.
     if (gFocusWindow == this) {
         LOGFOCUS(("  already have focus [%p]\n", (void *)this));
@@ -2016,57 +1998,44 @@ gdk_window_flash(GdkWindow *    aGdkWind
   gdk_gc_destroy(gc);
 
   gdk_region_offset(aRegion, -x, -y);
 }
 #endif /* MOZ_X11 */
 #endif // DEBUG
 #endif
 
-static void
-DispatchDidPaint(nsIWidget* aWidget)
-{
-    nsEventStatus status;
-    nsPaintEvent didPaintEvent(true, NS_DID_PAINT, aWidget);
-    aWidget->DispatchEvent(&didPaintEvent, status);
-}
-
 #if defined(MOZ_WIDGET_GTK2)
 gboolean
 nsWindow::OnExposeEvent(GdkEventExpose *aEvent)
 #else
 gboolean
 nsWindow::OnExposeEvent(cairo_t *cr)
 #endif
 {
     if (mIsDestroyed) {
         return FALSE;
     }
 
     // Windows that are not visible will be painted after they become visible.
     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
         return FALSE;
 
-    // Dispatch WILL_PAINT to allow scripts etc. to run before we
-    // dispatch PAINT
+    // Dispatch WillPaintWindow notification to allow scripts etc. to run
+    // before we paint
     {
-        nsEventStatus status;
-        nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, this);
-        willPaintEvent.willSendDidPaint = true;
-        DispatchEvent(&willPaintEvent, status);
-
-        // If the window has been destroyed during WILL_PAINT, there is
-        // nothing left to do.
+        if (mWidgetListener)
+          mWidgetListener->WillPaintWindow(this, true);
+
+        // If the window has been destroyed during the will paint notification,
+        // there is nothing left to do.
         if (!mGdkWindow)
             return TRUE;
     }
 
-    nsPaintEvent event(true, NS_PAINT, this);
-    event.willSendDidPaint = true;
-
 #if defined(MOZ_WIDGET_GTK2)
     GdkRectangle *rects;
     gint nrects;
     gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
     if (NS_UNLIKELY(!rects)) // OOM
         return FALSE;
 #else
 #ifdef cairo_copy_clip_rectangle_list
@@ -2088,57 +2057,58 @@ nsWindow::OnExposeEvent(cairo_t *cr)
         rects[0] = aEvent->area;
         nrects = 1;
     }
 #endif
 
     LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
              (void *)this, (void *)mGdkWindow,
              gdk_x11_window_get_xid(mGdkWindow)));
+
+    nsIntRegion region;
   
 #if defined(MOZ_WIDGET_GTK2)
     GdkRectangle *r = rects;
     GdkRectangle *r_end = rects + nrects;
 #else
     cairo_rectangle_t *r = rects->rectangles;
     cairo_rectangle_t *r_end = r + rects->num_rectangles;
 #endif
     for (; r < r_end; ++r) {
-        event.region.Or(event.region, nsIntRect(r->x, r->y, r->width, r->height));
+        region.Or(region, nsIntRect(r->x, r->y, r->width, r->height));
         LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
     }
 
-    // Our bounds may have changed after dispatching WILL_PAINT.  Clip
-    // to the new bounds here.  The event region is relative to this
+    // Our bounds may have changed after calling WillPaintWindow.  Clip
+    // to the new bounds here.  The region is relative to this
     // window.
-    event.region.And(event.region,
-                     nsIntRect(0, 0, mBounds.width, mBounds.height));
+    region.And(region, nsIntRect(0, 0, mBounds.width, mBounds.height));
 
     bool translucent = eTransparencyTransparent == GetTransparencyMode();
     if (!translucent) {
         GList *children =
             gdk_window_peek_children(mGdkWindow);
         while (children) {
             GdkWindow *gdkWin = GDK_WINDOW(children->data);
             nsWindow *kid = get_window_for_gdk_window(gdkWin);
             if (kid && gdk_window_is_visible(gdkWin)) {
                 nsAutoTArray<nsIntRect,1> clipRects;
                 kid->GetWindowClipRegion(&clipRects);
                 nsIntRect bounds;
                 kid->GetBounds(bounds);
                 for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
                     nsIntRect r = clipRects[i] + bounds.TopLeft();
-                    event.region.Sub(event.region, r);
+                    region.Sub(region, r);
                 }
             }
             children = children->next;
         }
     }
 
-    if (event.region.IsEmpty()) {
+    if (region.IsEmpty()) {
 #if defined(MOZ_WIDGET_GTK2)
         g_free(rects);
 #else
         cairo_rectangle_list_destroy(rects);
 #endif
         return TRUE;
     }
     // If this widget uses OMTC...
@@ -2146,34 +2116,38 @@ nsWindow::OnExposeEvent(cairo_t *cr)
         nsEventStatus status;
 #if defined(MOZ_WIDGET_GTK2)
         nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface());
 #else
         nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface(cr));
 #endif
         nsBaseWidget::AutoLayerManagerSetup
           setupLayerManager(this, ctx, mozilla::layers::BUFFER_NONE);
-        DispatchEvent(&event, status);
+
+        if (mWidgetListener)
+            mWidgetListener->PaintWindow(this, region, true, true);
 
         g_free(rects);
 
-        DispatchDidPaint(this);
+        if (mWidgetListener)
+            mWidgetListener->DidPaintWindow();
 
         return TRUE;
 
     } else if (GetLayerManager()->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
         LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(GetLayerManager());
-        manager->SetClippingRegion(event.region);
-
-        nsEventStatus status;
-        DispatchEvent(&event, status);
+        manager->SetClippingRegion(region);
+
+        if (mWidgetListener)
+            mWidgetListener->PaintWindow(this, region, true, true);
 
         g_free(rects);
 
-        DispatchDidPaint(this);
+        if (mWidgetListener)
+            mWidgetListener->DidPaintWindow();
 
         return TRUE;
     }
 
 #if defined(MOZ_WIDGET_GTK2)
     nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface());
 #else
     nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface(cr));
@@ -2183,21 +2157,21 @@ nsWindow::OnExposeEvent(cairo_t *cr)
     nsIntRect boundsRect; // for translucent only
 
     ctx->NewPath();
     if (translucent) {
         // Collapse update area to the bounding box. This is so we only have to
         // call UpdateTranslucentWindowAlpha once. After we have dropped
         // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
         // our private interface so we can rework things to avoid this.
-        boundsRect = event.region.GetBounds();
+        boundsRect = region.GetBounds();
         ctx->Rectangle(gfxRect(boundsRect.x, boundsRect.y,
                                boundsRect.width, boundsRect.height));
     } else {
-        gfxUtils::PathFromRegion(ctx, event.region);
+        gfxUtils::PathFromRegion(ctx, region);
     }
     ctx->Clip();
 
     BufferMode layerBuffering;
     if (translucent) {
         // The double buffering is done here to extract the shape mask.
         // (The shape mask won't be necessary when a visual with an alpha
         // channel is used on compositing window managers.)
@@ -2221,28 +2195,30 @@ nsWindow::OnExposeEvent(cairo_t *cr)
     // XXX aEvent->region may refer to a newly-invalid area.  FIXME
     if (0 && WANT_PAINT_FLASHING && gtk_widget_get_window(aEvent))
         gdk_window_flash(mGdkWindow, 1, 100, aEvent->region);
 #endif
 #endif
 
 #endif // MOZ_X11
 
-    nsEventStatus status;
+    bool painted = false;
     {
       AutoLayerManagerSetup setupLayerManager(this, ctx, layerBuffering);
-      DispatchEvent(&event, status);
+
+      if (mWidgetListener)
+        painted = mWidgetListener->PaintWindow(this, region, true, true);
     }
 
 #ifdef MOZ_X11
-    // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
+    // PaintWindow can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (translucent) {
         if (NS_LIKELY(!mIsDestroyed)) {
-            if (status != nsEventStatus_eIgnore) {
+            if (painted) {
                 nsRefPtr<gfxPattern> pattern = ctx->PopGroup();
 
                 nsRefPtr<gfxImageSurface> img =
                     new gfxImageSurface(gfxIntSize(boundsRect.width, boundsRect.height),
                                         gfxImageSurface::ImageFormatA8);
                 if (img && !img->CairoStatus()) {
                     img->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
 
@@ -2276,17 +2252,18 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 #endif // MOZ_X11
 
 #if defined(MOZ_WIDGET_GTK2)
     g_free(rects);
 #else
     cairo_rectangle_list_destroy(rects);
 #endif
 
-    DispatchDidPaint(this);
+    if (mWidgetListener)
+      mWidgetListener->DidPaintWindow();
 
     // Synchronously flush any new dirty areas
 #if defined(MOZ_WIDGET_GTK2)
     GdkRegion* dirtyArea = gdk_window_get_update_area(mGdkWindow);
 #else
     cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow);
 #endif
 
@@ -2352,33 +2329,29 @@ nsWindow::OnConfigureEvent(GtkWidget *aW
         // Override-redirect window
         //
         // These windows should not be moved by the window manager, and so any
         // change in position is a result of our direction.  mBounds has
         // already been set in Move() or Resize(), and that is more
         // up-to-date than the position in the ConfigureNotify event if the
         // event is from an earlier window move.
         //
-        // Skipping the NS_MOVE dispatch saves context menus from an infinite
+        // Skipping the WindowMoved call saves context menus from an infinite
         // loop when nsXULPopupManager::PopupMoved moves the window to the new
         // position and nsMenuPopupFrame::SetPopupPosition adds
         // offsetForContextMenu on each iteration.
         return FALSE;
     }
 
     mBounds.MoveTo(screenBounds.TopLeft());
 
-    nsGUIEvent event(true, NS_MOVE, this);
-
-    event.refPoint = mBounds.TopLeft();
-
     // XXX mozilla will invalidate the entire window after this move
     // complete.  wtf?
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+    if (mWidgetListener)
+      mWidgetListener->WindowMoved(this, mBounds.x, mBounds.y);
 
     return FALSE;
 }
 
 void
 nsWindow::OnContainerUnrealize(GtkWidget *aWidget)
 {
     // The GdkWindows are about to be destroyed (but not deleted), so remove
@@ -2413,30 +2386,25 @@ nsWindow::OnSizeAllocate(GtkWidget *aWid
 
     if (!mGdkWindow)
         return;
 
     if (mTransparencyBitmap) {
       ApplyTransparencyBitmap();
     }
 
-    nsEventStatus status;
-    DispatchResizeEvent (rect, status);
+    if (mWidgetListener)
+        mWidgetListener->WindowResized(this, rect.width, rect.height);
 }
 
 void
 nsWindow::OnDeleteEvent(GtkWidget *aWidget, GdkEventAny *aEvent)
 {
-    nsGUIEvent event(true, NS_XUL_CLOSE, this);
-
-    event.refPoint.x = 0;
-    event.refPoint.y = 0;
-
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+    if (mWidgetListener)
+        mWidgetListener->RequestWindowClose(this);
 }
 
 void
 nsWindow::OnEnterNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
 {
     // This skips NotifyVirtual and NotifyNonlinearVirtual enter notify events
     // when the pointer enters a child window.  If the destination window is a
     // Gecko window then we'll catch the corresponding event on that window,
@@ -2825,25 +2793,25 @@ nsWindow::OnContainerFocusInEvent(GtkWid
     GtkWidget* top_window = nullptr;
     GetToplevelWidget(&top_window);
     if (top_window && (gtk_widget_get_visible(top_window)))
         SetUrgencyHint(top_window, false);
 
     // Return if being called within SetFocus because the focus manager
     // already knows that the window is active.
     if (gBlockActivateEvent) {
-        LOGFOCUS(("NS_ACTIVATE event is blocked [%p]\n", (void *)this));
+        LOGFOCUS(("activated notification is blocked [%p]\n", (void *)this));
         return;
     }
 
     // This is not usually the correct window for dispatching key events,
     // but the focus manager will call SetFocus to set the correct window if
     // keyboard input will be accepted.  Setting a non-NULL value here
-    // prevents OnButtonPressEvent() from dispatching NS_ACTIVATE if the
-    // widget is already active.
+    // prevents OnButtonPressEvent() from dispatching an activation
+    // notification if the widget is already active.
     gFocusWindow = this;
 
     DispatchActivateEvent();
 
     LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
 }
 
 void
@@ -3209,59 +3177,53 @@ nsWindow::OnWindowStateEvent(GtkWidget *
               (GDK_WINDOW_STATE_ICONIFIED|GDK_WINDOW_STATE_WITHDRAWN));
         if (mHasMappedToplevel != mapped) {
             SetHasMappedToplevel(mapped);
         }
         return;
     }
     // else the widget is a shell widget.
 
-    nsSizeModeEvent event(true, NS_SIZEMODE, this);
-
     // We don't care about anything but changes in the maximized/icon/fullscreen
     // states
     if ((aEvent->changed_mask
          & (GDK_WINDOW_STATE_ICONIFIED |
             GDK_WINDOW_STATE_MAXIMIZED |
             GDK_WINDOW_STATE_FULLSCREEN)) == 0) {
         return;
     }
 
     if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
         LOG(("\tIconified\n"));
-        event.mSizeMode = nsSizeMode_Minimized;
         mSizeState = nsSizeMode_Minimized;
 #ifdef ACCESSIBILITY
         DispatchMinimizeEventAccessible();
 #endif //ACCESSIBILITY
     }
     else if (aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
         LOG(("\tFullscreen\n"));
-        event.mSizeMode = nsSizeMode_Fullscreen;
         mSizeState = nsSizeMode_Fullscreen;
     }
     else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
         LOG(("\tMaximized\n"));
-        event.mSizeMode = nsSizeMode_Maximized;
         mSizeState = nsSizeMode_Maximized;
 #ifdef ACCESSIBILITY
         DispatchMaximizeEventAccessible();
 #endif //ACCESSIBILITY
     }
     else {
         LOG(("\tNormal\n"));
-        event.mSizeMode = nsSizeMode_Normal;
         mSizeState = nsSizeMode_Normal;
 #ifdef ACCESSIBILITY
         DispatchRestoreEventAccessible();
 #endif //ACCESSIBILITY
     }
 
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+    if (mWidgetListener)
+      mWidgetListener->SizeModeChanged(mSizeState);
 }
 
 void
 nsWindow::ThemeChanged()
 {
     NotifyThemeChanged();
 
     if (!mGdkWindow || NS_UNLIKELY(mIsDestroyed))
@@ -5845,18 +5807,16 @@ nsWindow::DispatchEventToRootAccessible(
 
     // Get the root document accessible and fire event to it.
     Accessible *acc = GetAccessible();
     if (acc) {
         accService->FireAccessibleEvent(aEventType, acc);
     }
 }
 
-// XXXndeakin what is all this for? Accessibility should be receiving these
-// notifications of gtk the same as other platforms.
 void
 nsWindow::DispatchActivateEventAccessible(void)
 {
     DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE);
 }
 
 void
 nsWindow::DispatchDeactivateEventAccessible(void)
--- a/widget/gtk2/nsWindow.h
+++ b/widget/gtk2/nsWindow.h
@@ -80,17 +80,16 @@ public:
 
     NS_DECL_ISUPPORTS_INHERITED
     
     void CommonCreate(nsIWidget *aParent, bool aListenForResizes);
     
     // event handling code
     void DispatchActivateEvent(void);
     void DispatchDeactivateEvent(void);
-    void DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus);
 
     virtual nsresult DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus);
     
     // called when we are destroyed
     void OnDestroy(void);
 
     // called to check and see if a widget's dimensions are sane
     bool AreBoundsSane(void);
@@ -358,17 +357,17 @@ private:
     GdkWindow          *mGdkWindow;
 
     GtkWindowGroup     *mWindowGroup;
 
     PRUint32            mHasMappedToplevel : 1,
                         mIsFullyObscured : 1,
                         mRetryPointerGrab : 1;
     GtkWindow          *mTransientParent;
-    PRInt32             mSizeState;
+    nsSizeMode          mSizeState;
     PluginType          mPluginType;
 
     PRInt32             mTransparencyBitmapWidth;
     PRInt32             mTransparencyBitmapHeight;
 
 #ifdef MOZ_HAVE_SHMIMAGE
     // If we're using xshm rendering, mThebesSurface wraps mShmImage
     nsRefPtr<nsShmImage>  mShmImage;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -30,16 +30,17 @@ class   nsRenderingContext;
 class   nsDeviceContext;
 struct  nsFont;
 class   nsIRollupListener;
 class   nsGUIEvent;
 class   imgIContainer;
 class   gfxASurface;
 class   nsIContent;
 class   ViewWrapper;
+class   nsIWidgetListener;
 
 namespace mozilla {
 namespace dom {
 class TabChild;
 }
 namespace layers {
 class LayerManager;
 class PLayersChild;
@@ -82,18 +83,18 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #endif
 #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
 #endif
 
 #define NS_IWIDGET_IID \
-  { 0x91aafae4, 0xd814, 0x4803, \
-    { 0x9a, 0xf5, 0xb0, 0x2f, 0x1b, 0x2c, 0xaf, 0x57 } }
+  { 0xb8f43b25, 0x9036, 0x44e7, \
+    { 0xaa, 0xe2, 0x33, 0x76, 0x6c, 0x35, 0x91, 0xfc } }
 
 /*
  * 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
@@ -488,22 +489,22 @@ class nsIWidget : public nsISupports {
     /**
      * Accessor functions to get and set secondary client data. Used by
      * nsIView in connection with AttachViewToTopLevel above.
      */
     NS_IMETHOD SetAttachedViewPtr(ViewWrapper* aViewWrapper) = 0;
     virtual ViewWrapper* GetAttachedViewPtr() = 0;
 
     /**
-     * Accessor functions to get and set the client data associated with the
-     * widget.
+     * Accessor functions to get and set the listener which handles various
+     * actions for the widget.
      */
     //@{
-    NS_IMETHOD  GetClientData(void*& aClientData) = 0;
-    NS_IMETHOD  SetClientData(void* aClientData) = 0;
+    virtual nsIWidgetListener* GetWidgetListener() = 0;
+    virtual void SetWidgetListener(nsIWidgetListener* alistener) = 0;
     //@}
 
     /**
      * Close and destroy the internal native window. 
      * This method does not delete the widget.
      */
 
     NS_IMETHOD Destroy(void) = 0;
new file mode 100644
--- /dev/null
+++ b/widget/nsIWidgetListener.h
@@ -0,0 +1,129 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozila.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsIWidgetListener_h__
+#define nsIWidgetListener_h__
+
+#include "nscore.h"
+#include "nsGUIEvent.h"
+#include "nsIXULWindow.h"
+
+class nsIView;
+
+class nsIWidgetListener
+{
+public:
+
+  /**
+   * If this listener is for an nsIXULWindow, return it. If this is null, then
+   * this is likely a listener for a view, which can be determined using
+   * GetView. If both methods return null, this will be an nsWebBrowser.
+   */
+  virtual nsIXULWindow* GetXULWindow() { return nullptr; }
+
+  /**
+   * If this listener is for an nsIView, return it.
+   */
+  virtual nsIView* GetView() { return nullptr; }
+
+  /**
+   * Called when a window is moved to location (x, y). Returns true if the
+   * notification was handled. Coordinates are outer window screen coordinates.
+   */
+  virtual bool WindowMoved(nsIWidget* aWidget, PRInt32 aX, PRInt32 aY) { return false; }
+
+  /**
+   * Called when a window is resized to (width, height). Returns true if the
+   * notification was handled. Coordinates are outer window screen coordinates.
+   */
+  virtual bool WindowResized(nsIWidget* aWidget, PRInt32 aWidth, PRInt32 aHeight) { return false; }
+
+  /**
+   * Called when the size mode (minimized, maximized, fullscreen) is changed.
+   */
+  virtual void SizeModeChanged(nsSizeMode sizeMode) { }
+
+  /**
+   * Called when the z-order of the window is changed. Returns true if the
+   * notification was handled. aPlacement indicates the new z order. If
+   * placement is nsWindowZRelative, then aRequestBelow should be the
+   * window to place below. On return, aActualBelow will be set to the
+   * window actually behind. This generally only applies to Windows.
+   */
+  virtual bool ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
+                             nsIWidget* aRequestBelow, nsIWidget** aActualBelow) { return false; }
+
+  /**
+   * Called when the window is activated and focused.
+   */
+  virtual void WindowActivated() { }
+
+  /**
+   * Called when the window is deactivated and no longer focused.
+   */
+  virtual void WindowDeactivated() { }
+
+  /**
+   * Called when the show/hide toolbar button on the Mac titlebar is pressed.
+   */
+  virtual void OSToolbarButtonPressed() { }
+
+  /**
+   * Called when a request is made to close the window. Returns true if the
+   * notification was handled. Returns true if the notification was handled.
+   */
+  virtual bool RequestWindowClose(nsIWidget* aWidget) { return false; }
+
+  /*
+   * Indicate that a paint is about to occur on this window.
+   */
+  virtual void WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint) { }
+
+  /**
+   * Paint the specified region of the window. If aSentWillPaint is true,
+   * then WillPaintWindow has already been called. If aWillSendDidPaint is true,
+   * then a call to DidPaintWindow will be made afterwards. Returns true if the
+   * notification was handled.
+   */
+  virtual bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion,
+                           bool aSentWillPaint, bool aWillSendDidPaint) { return false; }
+
+  /**
+   * On some platforms, indicates that a paint occurred.
+   */
+  virtual void DidPaintWindow() { }
+};
+
+#endif
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -63,16 +63,17 @@ using namespace QtMobility;
 
 #include "nsIdleService.h"
 #include "nsRenderingContext.h"
 #include "nsIRollupListener.h"
 #include "nsWidgetsCID.h"
 #include "nsQtKeyUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
+#include "nsIWidgetListener.h"
 
 #include "nsIStringBundle.h"
 #include "nsGfxCIID.h"
 
 #include "imgIContainer.h"
 #include "nsGfxCIID.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsAutoPtr.h"
@@ -654,16 +655,18 @@ nsWindow::SetFocus(bool aRaise)
         QWidget *widget = GetViewWidget();
         if (widget)
             widget->raise();
         realFocusItem->setFocus(Qt::ActiveWindowFocusReason);
     }
     else
         realFocusItem->setFocus(Qt::OtherFocusReason);
 
+    // XXXndeakin why is this here? It should dispatch only when the OS
+    // notifies us.
     DispatchActivateEvent();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::GetScreenBounds(nsIntRect &aRect)
 {
@@ -987,115 +990,102 @@ GetSurfaceForQWidget(QWidget* aDrawable)
                            DefaultVisualOfScreen(gfxQtPlatform::GetXScreen(aDrawable)),
                            gfxIntSize(aDrawable->size().width(),
                            aDrawable->size().height()));
     NS_IF_ADDREF(result);
     return result;
 }
 #endif
 
-static void
-DispatchDidPaint(nsIWidget* aWidget)
-{
-    nsEventStatus status;
-    nsPaintEvent didPaintEvent(true, NS_DID_PAINT, aWidget);
-    aWidget->DispatchEvent(&didPaintEvent, status);
-}
-
-nsEventStatus
+bool
 nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget)
 {
     if (mIsDestroyed) {
         LOG(("Expose event on destroyed window [%p] window %p\n",
              (void *)this, mWidget));
-        return nsEventStatus_eIgnore;
+        return false;
     }
 
-    // Dispatch WILL_PAINT to allow scripts etc. to run before we
-    // dispatch PAINT
+    // Call WillPaintWindow to allow scripts etc. to run before we paint
     {
-        nsEventStatus status;
-        nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, this);
-        willPaintEvent.willSendDidPaint = true;
-        DispatchEvent(&willPaintEvent, status);
+        if (mWidgetListener)
+            mWidgetListener->WillPaintWindow(this, true);
     }
 
     if (!mWidget)
-        return nsEventStatus_eIgnore;
+        return false;
 
     QRectF r;
     if (aOption)
         r = aOption->exposedRect;
     else
         r = mWidget->boundingRect();
 
     if (r.isEmpty())
         return nsEventStatus_eIgnore;
 
     if (!mDirtyScrollArea.isEmpty())
         mDirtyScrollArea = QRegion();
 
-    nsEventStatus status;
+    bool painted = false;
     nsIntRect rect(r.x(), r.y(), r.width(), r.height());
 
     nsFastStartup* startup = nsFastStartup::GetSingleton();
     if (startup) {
         startup->RemoveFakeLayout();
     }
 
     if (GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
         aPainter->beginNativePainting();
-        nsPaintEvent event(true, NS_PAINT, this);
-        event.willSendDidPaint = true;
-        event.refPoint.x = r.x();
-        event.refPoint.y = r.y();
-        event.region = nsIntRegion(rect);
+        nsIntRegion region(rect);
         static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
-            SetClippingRegion(event.region);
+            SetClippingRegion(region);
 
         gfxMatrix matr;
         matr.Translate(gfxPoint(aPainter->transform().dx(), aPainter->transform().dy()));
 #ifdef MOZ_ENABLE_QTMOBILITY
         // This is needed for rotate transformation on MeeGo
         // This will work very slow if pixman does not handle rotation very well
         matr.Rotate((M_PI/180) * gOrientationFilter.GetWindowRotationAngle());
         static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
             SetWorldTransform(matr);
 #endif //MOZ_ENABLE_QTMOBILITY
 
-        status = DispatchEvent(&event);
+        if (mWidgetListener)
+          painted = mWidgetListener->PaintWindow(this, region, true, true);
         aPainter->endNativePainting();
-        DispatchDidPaint(this);
-        return status;
+        if (mWidgetListener)
+          mWidgetListener->DidPaintWindow();
+        return painted;
     }
 
     gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
     int depth = aPainter->device()->depth();
 
     nsRefPtr<gfxASurface> targetSurface = nullptr;
     if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
         // Prepare offscreen buffers iamge or xlib, depends from paintEngineType
         if (!UpdateOffScreenBuffers(depth, QSize(r.width(), r.height())))
-            return nsEventStatus_eIgnore;
+            return false;
 
         targetSurface = gBufferSurface;
 
 #ifdef CAIRO_HAS_QT_SURFACE
     } else if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
         targetSurface = new gfxQPainterSurface(aPainter);
 #endif
     } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
         if (!UpdateOffScreenBuffers(depth, aWidget->size(), aWidget)) {
-            return nsEventStatus_eIgnore;
+            return false;
         }
         targetSurface = gBufferSurface;
     }
 
     if (NS_UNLIKELY(!targetSurface))
-        return nsEventStatus_eIgnore;
+        return false;
 
     nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
 
     // We will paint to 0, 0 position in offscrenn buffer
     if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
         ctx->Translate(gfxPoint(-r.x(), -r.y()));
     }
     else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
@@ -1108,34 +1098,32 @@ nsWindow::DoPaint(QPainter* aPainter, co
          NS_ASSERTION(PIXMAN_VERSION > PIXMAN_VERSION_ENCODE(0, 21, 2) ||
                       !gOrientationFilter.GetWindowRotationAngle(),
                       "Old pixman and rotate transform, it is going to be slow");
 #endif //MOZ_ENABLE_QTMOBILITY
 
       ctx->SetMatrix(matr);
     }
 
-    nsPaintEvent event(true, NS_PAINT, this);
-    event.willSendDidPaint = true;
-    event.refPoint.x = rect.x;
-    event.refPoint.y = rect.y;
-    event.region = nsIntRegion(rect);
     {
         AutoLayerManagerSetup
             setupLayerManager(this, ctx, mozilla::layers::BUFFER_NONE);
-        status = DispatchEvent(&event);
+        if (mWidgetListener) {
+          nsIntRegion region(rect);
+          painted = mWidgetListener->PaintWindow(this, region, true, true);
+        }
     }
 
     // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (NS_UNLIKELY(mIsDestroyed))
-        return status;
-
-    if (status == nsEventStatus_eIgnore)
-        return status;
+        return painted;
+
+    if (!painted)
+        return false;
 
     LOGDRAW(("[%p] draw done\n", this));
 
     // Handle buffered painting mode
     if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
 #if defined(MOZ_X11) && defined(Q_WS_X11)
         if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
             // Paint offscreen pixmap to QPainter
@@ -1188,46 +1176,41 @@ nsWindow::DoPaint(QPainter* aPainter, co
                           _gfximage_to_qformat(imgs->Format()));
                 aPainter->drawImage(trans, img, trans);
             }
         }
     }
 
     ctx = nullptr;
     targetSurface = nullptr;
-    DispatchDidPaint(this);
+    if (mWidgetListener)
+      mWidgetListener->DidPaintWindow();
 
     // check the return value!
-    return status;
+    return painted;
 }
 
 nsEventStatus
 nsWindow::OnMoveEvent(QGraphicsSceneHoverEvent *aEvent)
 {
     LOG(("configure event [%p] %d %d\n", (void *)this,
         aEvent->pos().x(),  aEvent->pos().y()));
 
     // can we shortcut?
-    if (!mWidget)
+    if (!mWidget || !mWidgetListener)
         return nsEventStatus_eIgnore;
 
     if ((mBounds.x == aEvent->pos().x() &&
          mBounds.y == aEvent->pos().y()))
     {
         return nsEventStatus_eIgnore;
     }
 
-    nsGUIEvent event(true, NS_MOVE, this);
-
-    event.refPoint.x = aEvent->pos().x();
-    event.refPoint.y = aEvent->pos().y();
-
-    // XXX mozilla will invalidate the entire window after this move
-    // complete.  wtf?
-    return DispatchEvent(&event);
+    bool moved = mWidgetListener->WindowMoved(this, aEvent->pos().x(), aEvent->pos().y());
+    return moved ? nsEventStatus_eConsumeNoDefault : nsEventStatus_eIgnore;
 }
 
 nsEventStatus
 nsWindow::OnResizeEvent(QGraphicsSceneResizeEvent *aEvent)
 {
     nsIntRect rect;
 
     // Generate XPFE resize event
@@ -1242,22 +1225,20 @@ nsWindow::OnResizeEvent(QGraphicsSceneRe
     nsEventStatus status;
     DispatchResizeEvent(rect, status);
     return status;
 }
 
 nsEventStatus
 nsWindow::OnCloseEvent(QCloseEvent *aEvent)
 {
-    nsGUIEvent event(true, NS_XUL_CLOSE, this);
-
-    event.refPoint.x = 0;
-    event.refPoint.y = 0;
-
-    return DispatchEvent(&event);
+    if (!mWidgetListener)
+        return nsEventStatus_eIgnore;
+    mWidgetListener->RequestWindowClose(this);
+    return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus
 nsWindow::OnEnterNotifyEvent(QGraphicsSceneHoverEvent *aEvent)
 {
     nsMouseEvent event(true, NS_MOUSE_ENTER, this, nsMouseEvent::eReal);
 
     event.refPoint.x = nscoord(aEvent->pos().x());
@@ -2841,27 +2822,25 @@ nsWindow::GetDPI()
     }
 
     return float(rootWindow->height()/heightInches);
 }
 
 void
 nsWindow::DispatchActivateEvent(void)
 {
-    nsGUIEvent event(true, NS_ACTIVATE, this);
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+    if (mWidgetListener)
+      mWidgetListener->WindowActivated();
 }
 
 void
 nsWindow::DispatchDeactivateEvent(void)
 {
-    nsGUIEvent event(true, NS_DEACTIVATE, this);
-    nsEventStatus status;
-    DispatchEvent(&event, status);
+    if (mWidgetListener)
+      mWidgetListener->WindowDeactivated();
 }
 
 void
 nsWindow::DispatchActivateEventOnTopLevelWindow(void)
 {
     nsWindow * topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
     if (topLevelWindow != nullptr)
          topLevelWindow->DispatchActivateEvent();
@@ -2873,26 +2852,20 @@ nsWindow::DispatchDeactivateEventOnTopLe
     nsWindow * topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
     if (topLevelWindow != nullptr)
          topLevelWindow->DispatchDeactivateEvent();
 }
 
 void
 nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
 {
-    nsSizeEvent event(true, NS_SIZE, this);
-
-    event.windowSize = &aRect;
-    event.refPoint.x = aRect.x;
-    event.refPoint.y = aRect.y;
-    event.mWinWidth = aRect.width;
-    event.mWinHeight = aRect.height;
-
-    nsEventStatus status;
-    DispatchEvent(&event, status); 
+    aStatus = nsEventStatus_eIgnore;
+    if (mWidgetListener &&
+        mWidgetListener->WindowResized(this, aRect.width, aRect.height))
+      aStatus = nsEventStatus_eConsumeNoDefault;
 }
 
 NS_IMETHODIMP
 nsWindow::DispatchEvent(nsGUIEvent *aEvent,
                               nsEventStatus &aStatus)
 {
 #ifdef DEBUG
     debug_DumpEvent(stdout, aEvent->widget, aEvent,
--- a/widget/qt/nsWindow.h
+++ b/widget/qt/nsWindow.h
@@ -77,17 +77,17 @@ class nsIdleService;
 
 class nsWindow : public nsBaseWidget,
                  public nsSupportsWeakReference
 {
 public:
     nsWindow();
     virtual ~nsWindow();
 
-    nsEventStatus DoPaint( QPainter* aPainter, const QStyleOptionGraphicsItem * aOption, QWidget* aWidget);
+    bool DoPaint( QPainter* aPainter, const QStyleOptionGraphicsItem * aOption, QWidget* aWidget);
 
     static void ReleaseGlobals();
 
     NS_DECL_ISUPPORTS_INHERITED
 
     //
     // nsIWidget
     //
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -110,16 +110,17 @@
 #include "gfxWindowsPlatform.h"
 #include "Layers.h"
 #include "nsPrintfCString.h"
 #include "mozilla/Preferences.h"
 #include "nsISound.h"
 #include "WinTaskbar.h"
 #include "WinUtils.h"
 #include "WidgetUtils.h"
+#include "nsIWidgetListener.h"
 
 #ifdef MOZ_ENABLE_D3D9_LAYER
 #include "LayerManagerD3D9.h"
 #endif
 
 #ifdef MOZ_ENABLE_D3D10_LAYER
 #include "LayerManagerD3D10.h"
 #endif
@@ -1582,20 +1583,19 @@ NS_IMETHODIMP nsWindow::SetSizeMode(PRIn
     ::GetWindowPlacement(mWnd, &pl);
     // Don't call ::ShowWindow if we're trying to "restore" a window that is
     // already in a normal state.  Prevents a bug where snapping to one side
     // of the screen and then minimizing would cause Windows to forget our
     // window's correct restored position/size.
     if( !(pl.showCmd == SW_SHOWNORMAL && mode == SW_RESTORE) ) {
       ::ShowWindow(mWnd, mode);
     }
-    // we dispatch an activate event here to ensure that the right child window
-    // is focused
+    // we activate here to ensure that the right child window is focused
     if (mode == SW_MAXIMIZE || mode == SW_SHOW)
-      DispatchFocusToTopLevelWindow(NS_ACTIVATE);
+      DispatchFocusToTopLevelWindow(true);
   }
   return rv;
 }
 
 // Constrain a potential move to fit onscreen
 NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop,
                                       PRInt32 *aX, PRInt32 *aY)
 {
@@ -2695,21 +2695,18 @@ nsWindow::MakeFullScreen(bool aFullScree
     Invalidate();
   }
 
   // Notify the taskbar that we have exited full screen mode.
   if (!aFullScreen && taskbarInfo) {
     taskbarInfo->PrepareFullScreenHWND(mWnd, FALSE);
   }
 
-  // Let the dom know via web shell window
-  nsSizeModeEvent event(true, NS_SIZEMODE, this);
-  event.mSizeMode = mSizeMode;
-  InitEvent(event);
-  DispatchWindowEvent(&event);
+  if (mWidgetListener)
+    mWidgetListener->SizeModeChanged(mSizeMode);
 
   return rv;
 }
 
 /**************************************************************
  *
  * SECTION: Native data storage
  *
@@ -3484,38 +3481,21 @@ NS_IMETHODIMP nsWindow::DispatchEvent(ns
                   event->widget,
                   event,
                   nsCAutoString("something"),
                   (PRInt32) mWnd);
 #endif // WIDGET_DEBUG_OUTPUT
 
   aStatus = nsEventStatus_eIgnore;
 
-  // skip processing of suppressed blur events
-  if (event->message == NS_DEACTIVATE && BlurEventsSuppressed())
-    return NS_OK;
-
   // Top level windows can have a view attached which requires events be sent
   // to the underlying base window and the view. Added when we combined the
   // base chrome window with the main content child for nc client area (title
   // bar) rendering.
   if (mViewCallback) {
-    // A subset of events are sent to the base xul window first
-    switch(event->message) {
-      // sent to the base window, then to the view
-      case NS_SIZE:
-      case NS_DEACTIVATE:
-      case NS_ACTIVATE:
-      case NS_SIZEMODE:
-      case NS_SETZLEVEL:
-      case NS_XUL_CLOSE:
-      case NS_MOVE:
-        (*mEventCallback)(event); // web shell / xul window
-        break;
-    };
     // attached view events
     aStatus = (*mViewCallback)(event);
   }
   else if (mEventCallback) {
     aStatus = (*mEventCallback)(event);
   }
 
   // the window can be destroyed during processing of seemingly innocuous events like, say,
@@ -3942,22 +3922,28 @@ bool nsWindow::DispatchMouseEvent(PRUint
     // the context menu key code in nsEventListenerManager::HandleEvent()
     // released it already.
     return result;
   }
 
   return result;
 }
 
-bool nsWindow::DispatchFocusToTopLevelWindow(PRUint32 aEventType)
-{
-  if (aEventType == NS_ACTIVATE)
+void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate)
+{
+  if (aIsActivate)
     sJustGotActivate = false;
   sJustGotDeactivate = false;
 
+  if (!aIsActivate && BlurEventsSuppressed())
+    return;
+
+  if (!mWidgetListener)
+    return;
+
   // retrive the toplevel window or dialog
   HWND curWnd = mWnd;
   HWND toplevelWnd = NULL;
   while (curWnd) {
     toplevelWnd = curWnd;
 
     nsWindow *win = WinUtils::GetNSWindowPtr(curWnd);
     if (win) {
@@ -3967,57 +3953,23 @@ bool nsWindow::DispatchFocusToTopLevelWi
         break;
     }
 
     curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
   }
 
   if (toplevelWnd) {
     nsWindow *win = WinUtils::GetNSWindowPtr(toplevelWnd);
-    if (win)
-      return win->DispatchFocus(aEventType);
-  }
-
-  return false;
-}
-
-// Deal with focus messages
-bool nsWindow::DispatchFocus(PRUint32 aEventType)
-{
-  // call the event callback
-  if (mEventCallback) {
-    nsGUIEvent event(true, aEventType, this);
-    InitEvent(event);
-
-    //focus and blur event should go to their base widget loc, not current mouse pos
-    event.refPoint.x = 0;
-    event.refPoint.y = 0;
-
-    NPEvent pluginEvent;
-
-    switch (aEventType)
-    {
-      case NS_ACTIVATE:
-        pluginEvent.event = WM_SETFOCUS;
-        break;
-      case NS_DEACTIVATE:
-        pluginEvent.event = WM_KILLFOCUS;
-        break;
-      case NS_PLUGIN_ACTIVATE:
-        pluginEvent.event = WM_KILLFOCUS;
-        break;
-      default:
-        break;
-    }
-
-    event.pluginEvent = (void *)&pluginEvent;
-
-    return DispatchWindowEvent(&event);
-  }
-  return false;
+    if (win) {
+      if (aIsActivate)
+        mWidgetListener->WindowActivated();
+      else
+        mWidgetListener->WindowDeactivated();
+    }
+  }
 }
 
 bool nsWindow::IsTopLevelMouseExit(HWND aWnd)
 {
   DWORD pos = ::GetMessagePos();
   POINT mp;
   mp.x = GET_X_LPARAM(pos);
   mp.y = GET_Y_LPARAM(pos);
@@ -4682,17 +4634,18 @@ bool nsWindow::ProcessMessage(UINT msg, 
     {
       RECT rect;
       ::GetWindowRect(mWnd, &rect);
       result = OnMove(rect.left, rect.top);
     }
     break;
 
     case WM_CLOSE: // close request
-      DispatchStandardEvent(NS_XUL_CLOSE);
+      if (mWidgetListener)
+        mWidgetListener->RequestWindowClose(this);
       result = true; // abort window closure
       break;
 
     case WM_DESTROY:
       // clean up.
       OnDestroy();
       result = true;
       break;
@@ -4971,28 +4924,27 @@ bool nsWindow::ProcessMessage(UINT msg, 
       // default = false - tell the driver that the event was not handled
     }
     break;
 
     // The WM_ACTIVATE event is fired when a window is raised or lowered,
     // and the loword of wParam specifies which. But we don't want to tell
     // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
     // events are fired. Instead, set either the sJustGotActivate or
-    // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
-    // events once the focus events arrive.
+    // gJustGotDeactivate flags and activate/deactivate once the focus
+    // events arrive.
     case WM_ACTIVATE:
       if (mEventCallback) {
         PRInt32 fActive = LOWORD(wParam);
 
         if (WA_INACTIVE == fActive) {
           // when minimizing a window, the deactivation and focus events will
-          // be fired in the reverse order. Instead, just dispatch
-          // NS_DEACTIVATE right away.
+          // be fired in the reverse order. Instead, just deactivate right away.
           if (HIWORD(wParam))
-            result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
+            DispatchFocusToTopLevelWindow(false);
           else
             sJustGotDeactivate = true;
 
           if (mIsTopWidgetWindow)
             mLastKeyboardLayout = gKbdLayout.GetLayout();
 
         } else {
           StopFlashing();
@@ -5049,23 +5001,23 @@ bool nsWindow::ProcessMessage(UINT msg, 
 
     case WM_SETFOCUS:
       // If previous focused window isn't ours, it must have received the
       // redirected message.  So, we should forget it.
       if (!WinUtils::IsOurProcessWindow(HWND(wParam))) {
         ForgetRedirectedKeyDownMessage();
       }
       if (sJustGotActivate) {
-        result = DispatchFocusToTopLevelWindow(NS_ACTIVATE);
+        DispatchFocusToTopLevelWindow(true);
       }
       break;
 
     case WM_KILLFOCUS:
       if (sJustGotDeactivate) {
-        result = DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
+        DispatchFocusToTopLevelWindow(false);
       }
       break;
 
     case WM_WINDOWPOSCHANGED:
     {
       WINDOWPOS *wp = (LPWINDOWPOS)lParam;
       OnWindowPosChanged(wp, result);
     }
@@ -5309,17 +5261,17 @@ bool nsWindow::ProcessMessage(UINT msg, 
           // With OOPP, the plugin window exists in another process and is a child of
           // this window. This window is a placeholder plugin window for the dom. We
           // receive this event when the child window receives focus. (sent from
           // PluginInstanceParent.cpp)
           ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
         } else {
           // WM_KILLFOCUS was received by the child process.
           if (sJustGotDeactivate) {
-            DispatchFocusToTopLevelWindow(NS_DEACTIVATE);
+            DispatchFocusToTopLevelWindow(false);
           }
         }
       }
     }
     break;
   }
 
   //*aRetValue = result;
@@ -5925,46 +5877,42 @@ void nsWindow::OnWindowPosChanged(WINDOW
 
     // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED
     // windows when fullscreen games disable desktop composition. If we're
     // minimized and not being activated, ignore the event and let windows
     // handle it.
     if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE))
       return;
 
-    nsSizeModeEvent event(true, NS_SIZEMODE, this);
-
     WINDOWPLACEMENT pl;
     pl.length = sizeof(pl);
     ::GetWindowPlacement(mWnd, &pl);
 
-    if (pl.showCmd == SW_SHOWMAXIMIZED)
-      event.mSizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
-    else if (pl.showCmd == SW_SHOWMINIMIZED)
-      event.mSizeMode = nsSizeMode_Minimized;
-    else if (mFullscreenMode)
-      event.mSizeMode = nsSizeMode_Fullscreen;
-    else
-      event.mSizeMode = nsSizeMode_Normal;
-
-    // Windows has just changed the size mode of this window. The following
-    // NS_SIZEMODE event will trigger a call into SetSizeMode where we will
+    // Windows has just changed the size mode of this window. The call to
+    // SizeModeChanged will trigger a call into SetSizeMode where we will
     // set the min/max window state again or for nsSizeMode_Normal, call
     // SetWindow with a parameter of SW_RESTORE. There's no need however as
     // this window's mode has already changed. Updating mSizeMode here
     // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related
     // to window docking. (bug 489258)
-    mSizeMode = event.mSizeMode;
+    if (pl.showCmd == SW_SHOWMAXIMIZED)
+      mSizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
+    else if (pl.showCmd == SW_SHOWMINIMIZED)
+      mSizeMode = nsSizeMode_Minimized;
+    else if (mFullscreenMode)
+      mSizeMode = nsSizeMode_Fullscreen;
+    else
+      mSizeMode = nsSizeMode_Normal;
 
     // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See
     // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This
     // prevents the working set from being trimmed but keeps the window active.
     // After the window is minimized, we need to do some touch up work on the
     // active window. (bugs 76831 & 499816)
-    if (!sTrimOnMinimize && nsSizeMode_Minimized == event.mSizeMode)
+    if (!sTrimOnMinimize && nsSizeMode_Minimized == mSizeMode)
       ActivateOtherWindowHelper(mWnd);
 
 #ifdef WINSTATE_DEBUG_OUTPUT
     switch (mSizeMode) {
       case nsSizeMode_Normal:
           PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
                  ("*** mSizeMode: nsSizeMode_Normal\n"));
         break;
@@ -5977,25 +5925,24 @@ void nsWindow::OnWindowPosChanged(WINDOW
                  ("*** mSizeMode: nsSizeMode_Maximized\n");
         break;
       default:
           PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** mSizeMode: ??????\n");
         break;
     };
 #endif
 
-    InitEvent(event);
-
-    result = DispatchWindowEvent(&event);
-
-    // If window was restored, NS_ACTIVATE dispatch was bypassed during the 
+    if (mWidgetListener)
+      mWidgetListener->SizeModeChanged(mSizeMode);
+
+    // If window was restored, window activation was bypassed during the 
     // SetSizeMode call originating from OnWindowPosChanging to avoid saving
-    // pre-restore attributes. Force dispatch now to get correct attributes.
+    // pre-restore attributes. Force activation now to get correct attributes.
     if (mLastSizeMode != nsSizeMode_Normal && mSizeMode == nsSizeMode_Normal)
-      DispatchFocusToTopLevelWindow(NS_ACTIVATE);
+      DispatchFocusToTopLevelWindow(true);
 
     // Skip window size change events below on minimization.
     if (mSizeMode == nsSizeMode_Minimized)
       return;
   }
 
   // Handle window size changes
   if (!(wp->flags & SWP_NOSIZE)) {
@@ -6112,69 +6059,61 @@ void nsWindow::OnWindowPosChanging(LPWIN
   // browser know we are changing size modes, so alternative css can kick in.
   // If we're going into fullscreen mode, ignore this, since it'll reset
   // margins to normal mode. 
   if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) &&
       mSizeMode != nsSizeMode_Fullscreen) {
     WINDOWPLACEMENT pl;
     pl.length = sizeof(pl);
     ::GetWindowPlacement(mWnd, &pl);
-    PRInt32 sizeMode;
+    nsSizeMode sizeMode;
     if (pl.showCmd == SW_SHOWMAXIMIZED)
       sizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized);
     else if (pl.showCmd == SW_SHOWMINIMIZED)
       sizeMode = nsSizeMode_Minimized;
     else if (mFullscreenMode)
       sizeMode = nsSizeMode_Fullscreen;
     else
       sizeMode = nsSizeMode_Normal;
 
-    nsSizeModeEvent event(true, NS_SIZEMODE, this);
-
-    InitEvent(event);
-    event.mSizeMode = static_cast<nsSizeMode>(sizeMode);
-    DispatchWindowEvent(&event);
+    if (mWidgetListener)
+      mWidgetListener->SizeModeChanged(sizeMode);
 
     UpdateNonClientMargins(sizeMode, false);
   }
 
   // enforce local z-order rules
   if (!(info->flags & SWP_NOZORDER)) {
     HWND hwndAfter = info->hwndInsertAfter;
-    
-    nsZLevelEvent event(true, NS_SETZLEVEL, this);
+
     nsWindow *aboveWindow = 0;
-
-    InitEvent(event);
+    nsWindowZ placement;
 
     if (hwndAfter == HWND_BOTTOM)
-      event.mPlacement = nsWindowZBottom;
+      placement = nsWindowZBottom;
     else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST)
-      event.mPlacement = nsWindowZTop;
+      placement = nsWindowZTop;
     else {
-      event.mPlacement = nsWindowZRelative;
+      placement = nsWindowZRelative;
       aboveWindow = WinUtils::GetNSWindowPtr(hwndAfter);
     }
-    event.mReqBelow = aboveWindow;
-    event.mActualBelow = nullptr;
-
-    event.mImmediate = false;
-    event.mAdjusted = false;
-    DispatchWindowEvent(&event);
-
-    if (event.mAdjusted) {
-      if (event.mPlacement == nsWindowZBottom)
-        info->hwndInsertAfter = HWND_BOTTOM;
-      else if (event.mPlacement == nsWindowZTop)
-        info->hwndInsertAfter = HWND_TOP;
-      else {
-        info->hwndInsertAfter = (HWND)event.mActualBelow->GetNativeData(NS_NATIVE_WINDOW);
+
+    if (mWidgetListener) {
+      nsCOMPtr<nsIWidget> actualBelow = nullptr;
+      if (mWidgetListener->ZLevelChanged(false, &placement,
+                                         aboveWindow, getter_AddRefs(actualBelow))) {
+        if (placement == nsWindowZBottom)
+          info->hwndInsertAfter = HWND_BOTTOM;
+        else if (placement == nsWindowZTop)
+          info->hwndInsertAfter = HWND_TOP;
+        else {
+          info->hwndInsertAfter = (HWND)actualBelow->GetNativeData(NS_NATIVE_WINDOW);
+        }
       }
     }
-    NS_IF_RELEASE(event.mActualBelow);
   }
   // prevent rude external programs from making hidden window visible
   if (mWindowType == eWindowType_invisible)
     info->flags &= ~SWP_SHOWWINDOW;
 }
 
 void nsWindow::UserActivity()
 {
@@ -7068,59 +7007,31 @@ void nsWindow::OnDestroy()
 }
 
 // OnMove
 bool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
 {
   mBounds.x = aX;
   mBounds.y = aY;
 
-  nsGUIEvent event(true, NS_MOVE, this);
-  InitEvent(event);
-  event.refPoint.x = aX;
-  event.refPoint.y = aY;
-
-  return DispatchWindowEvent(&event);
+  return mWidgetListener ? mWidgetListener->WindowMoved(this, aX, aY) : false;
 }
 
 // Send a resize message to the listener
 bool nsWindow::OnResize(nsIntRect &aWindowRect)
 {
 #ifdef CAIRO_HAS_D2D_SURFACE
   if (mD2DWindowSurface) {
     mD2DWindowSurface = NULL;
     Invalidate();
   }
 #endif
 
-  // call the event callback
-  if (mEventCallback) {
-    nsSizeEvent event(true, NS_SIZE, this);
-    InitEvent(event);
-    event.windowSize = &aWindowRect;
-    RECT r;
-    if (::GetWindowRect(mWnd, &r)) {
-      event.mWinWidth  = PRInt32(r.right - r.left);
-      event.mWinHeight = PRInt32(r.bottom - r.top);
-    } else {
-      event.mWinWidth  = 0;
-      event.mWinHeight = 0;
-    }
-
-#if 0
-    PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
-           ("[%X] OnResize: client:(%d x %d x %d x %d) window:(%d x %d)\n", this,
-            aWindowRect.x, aWindowRect.y, aWindowRect.width, aWindowRect.height,
-            event.mWinWidth, event.mWinHeight));
-#endif
-
-    return DispatchWindowEvent(&event);
-  }
-
-  return false;
+  return mWidgetListener ?
+         mWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height) : false;
 }
 
 bool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
 {
   return true;
 }
 
 // Can be overriden. Controls auto-erase of background.
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -324,18 +324,17 @@ protected:
     return mTransparencyMode == eTransparencyGlass ||
            mTransparencyMode == eTransparencyBorderlessGlass;
   }
 
   /**
    * Event processing helpers
    */
   bool                    DispatchPluginEvent(const MSG &aMsg);
-  bool                    DispatchFocusToTopLevelWindow(PRUint32 aEventType);
-  bool                    DispatchFocus(PRUint32 aEventType);
+  void                    DispatchFocusToTopLevelWindow(bool aIsActivate);
   bool                    DispatchStandardEvent(PRUint32 aMsg);
   bool                    DispatchCommandEvent(PRUint32 aEventCommand);
   void                    RelayMouseEvent(UINT aMsg, WPARAM wParam, LPARAM lParam);
   static void             RemoveNextCharMessage(HWND aWnd);
   void                    RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
                             UINT aLastMsg,
                             nsFakeCharMessage* aFakeCharMessage = nullptr);
   virtual bool            ProcessMessage(UINT msg, WPARAM &wParam,
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -29,16 +29,17 @@ using mozilla::plugins::PluginInstancePa
 #include "gfxImageSurface.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsPlatform.h"
 #include "nsGfxCIID.h"
 #include "gfxContext.h"
 #include "nsRenderingContext.h"
 #include "prmem.h"
 #include "WinUtils.h"
+#include "nsIWidgetListener.h"
 #include "mozilla/unused.h"
 
 #include "LayerManagerOGL.h"
 #include "BasicLayers.h"
 #ifdef MOZ_ENABLE_D3D9_LAYER
 #include "LayerManagerD3D9.h"
 #endif
 #ifdef MOZ_ENABLE_D3D10_LAYER
@@ -229,23 +230,22 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
       // could fail. Return without asserting since it's not our fault.
       NS_WARNING("Plugin failed to subclass our window");
     }
 
     ValidateRect(mWnd, NULL);
     return true;
   }
 
-  nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, this);
-  willPaintEvent.willSendDidPaint = true;
-  DispatchWindowEvent(&willPaintEvent);
+  if (mWidgetListener) {
+    mWidgetListener->WillPaintWindow(this, true);
+  }
 
   bool result = true;
   PAINTSTRUCT ps;
-  nsEventStatus eventStatus = nsEventStatus_eIgnore;
 
 #ifdef MOZ_XUL
   if (!aDC && (eTransparencyTransparent == mTransparencyMode))
   {
     // For layered translucent windows all drawing should go to memory DC and no
     // WM_PAINT messages are normally generated. To support asynchronous painting
     // we force generation of WM_PAINT messages by invalidating window areas with
     // RedrawWindow, InvalidateRect or InvalidateRgn function calls.
@@ -272,38 +272,31 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
   }
 #endif // WIDGET_DEBUG_OUTPUT
 
   HDC hDC = aDC ? aDC : (::BeginPaint(mWnd, &ps));
   if (!IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) {
     mPaintDC = hDC;
   }
 
-  // generate the event and call the event callback
-  nsPaintEvent event(true, NS_PAINT, this);
-  InitEvent(event);
-
 #ifdef MOZ_XUL
   bool forceRepaint = aDC || (eTransparencyTransparent == mTransparencyMode);
 #else
   bool forceRepaint = NULL != aDC;
 #endif
-  event.region = GetRegionToPaint(forceRepaint, ps, hDC);
-  event.willSendDidPaint = true;
-  event.didSendWillPaint = true;
-
-  if (!event.region.IsEmpty() && mEventCallback)
+  nsIntRegion region = GetRegionToPaint(forceRepaint, ps, hDC);
+  if (!region.IsEmpty() && mWidgetListener)
   {
     // Should probably pass in a real region here, using GetRandomRgn
     // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_4q0e.asp
 
 #ifdef WIDGET_DEBUG_OUTPUT
     debug_DumpPaintEvent(stdout,
                          this,
-                         &event,
+                         region,
                          nsCAutoString("noname"),
                          (PRInt32) mWnd);
 #endif // WIDGET_DEBUG_OUTPUT
 
     switch (GetLayerManager()->GetBackendType()) {
       case LAYERS_BASIC:
         {
           nsRefPtr<gfxASurface> targetSurface;
@@ -380,17 +373,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
           if (!targetSurface) {
             NS_ERROR("Invalid RenderMode!");
             return false;
           }
 
           nsRefPtr<gfxContext> thebesContext = new gfxContext(targetSurface);
           if (IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) {
             const nsIntRect* r;
-            for (nsIntRegionRectIterator iter(event.region);
+            for (nsIntRegionRectIterator iter(region);
                  (r = iter.Next()) != nullptr;) {
               thebesContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height), true);
             }
             thebesContext->Clip();
             thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR);
             thebesContext->Paint();
             thebesContext->SetOperator(gfxContext::OPERATOR_OVER);
           }
@@ -417,17 +410,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
 #else
             doubleBuffering = mozilla::layers::BUFFER_BUFFERED;
 #endif
           }
 
           {
             AutoLayerManagerSetup
                 setupLayerManager(this, thebesContext, doubleBuffering);
-            result = DispatchWindowEvent(&event, eventStatus);
+            result = mWidgetListener->PaintWindow(this, region, true, true);
           }
 
 #ifdef MOZ_XUL
           if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) ||
                IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))&&
               eTransparencyTransparent == mTransparencyMode) {
             // Data from offscreen drawing surface was copied to memory bitmap of transparent
             // bitmap. Now it can be read from memory bitmap to apply alpha channel and after
@@ -531,26 +524,26 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
                             DIB_RGB_COLORS,
                             SRCCOPY);
             }
           }
         }
         break;
       case LAYERS_OPENGL:
         static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager())->
-          SetClippingRegion(event.region);
-        result = DispatchWindowEvent(&event, eventStatus);
+          SetClippingRegion(region);
+        result = mWidgetListener->PaintWindow(this, region, true, true);
         break;
 #ifdef MOZ_ENABLE_D3D9_LAYER
       case LAYERS_D3D9:
         {
           LayerManagerD3D9 *layerManagerD3D9 =
             static_cast<mozilla::layers::LayerManagerD3D9*>(GetLayerManager());
-          layerManagerD3D9->SetClippingRegion(event.region);
-          result = DispatchWindowEvent(&event, eventStatus);
+          layerManagerD3D9->SetClippingRegion(region);
+          result = mWidgetListener->PaintWindow(this, region, true, true);
           if (layerManagerD3D9->DeviceWasRemoved()) {
             mLayerManager->Destroy();
             mLayerManager = nullptr;
             // When our device was removed, we should have gfxWindowsPlatform
             // check if its render mode is up to date!
             gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
             Invalidate();
           }
@@ -560,17 +553,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
 #ifdef MOZ_ENABLE_D3D10_LAYER
       case LAYERS_D3D10:
         {
           gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
           LayerManagerD3D10 *layerManagerD3D10 = static_cast<mozilla::layers::LayerManagerD3D10*>(GetLayerManager());
           if (layerManagerD3D10->device() != gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) {
             Invalidate();
           } else {
-            result = DispatchWindowEvent(&event, eventStatus);
+            result = mWidgetListener->PaintWindow(this, region, true, true);
           }
         }
         break;
 #endif
       default:
         NS_ERROR("Unknown layers backend used!");
         break;
     }
@@ -584,31 +577,31 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
   mLastPaintEndTime = TimeStamp::Now();
 
 #if defined(WIDGET_DEBUG_OUTPUT)
   if (debug_WantPaintFlashing())
   {
     // Only flash paint events which have not ignored the paint message.
     // Those that ignore the paint message aren't painting anything so there
     // is only the overhead of the dispatching the paint event.
-    if (nsEventStatus_eIgnore != eventStatus) {
+    if (result) {
       ::InvertRgn(debugPaintFlashDC, debugPaintFlashRegion);
       PR_Sleep(PR_MillisecondsToInterval(30));
       ::InvertRgn(debugPaintFlashDC, debugPaintFlashRegion);
       PR_Sleep(PR_MillisecondsToInterval(30));
     }
     ::ReleaseDC(mWnd, debugPaintFlashDC);
     ::DeleteObject(debugPaintFlashRegion);
   }
 #endif // WIDGET_DEBUG_OUTPUT
 
   mPainting = false;
 
-  nsPaintEvent didPaintEvent(true, NS_DID_PAINT, this);
-  DispatchWindowEvent(&didPaintEvent);
+  if (mWidgetListener)
+    mWidgetListener->DidPaintWindow();
 
   if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, NULL, false)) {
     OnPaint(aDC, 1);
   }
 
   return result;
 }
 
--- a/widget/xpwidgets/PuppetWidget.cpp
+++ b/widget/xpwidgets/PuppetWidget.cpp
@@ -12,16 +12,17 @@
 #if defined(MOZ_ENABLE_D3D10_LAYER)
 # include "LayerManagerD3D10.h"
 #endif
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Hal.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/PLayersChild.h"
 #include "PuppetWidget.h"
+#include "nsIWidgetListener.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
 static void
 InvalidateRegion(nsIWidget* aWidget, const nsIntRegion& aRegion)
@@ -179,18 +180,21 @@ PuppetWidget::Resize(PRInt32 aWidth,
   // XXX: roc says that |aRepaint| dictates whether or not to
   // invalidate the expanded area
   if (oldBounds.Size() < mBounds.Size() && aRepaint) {
     nsIntRegion dirty(mBounds);
     dirty.Sub(dirty,  oldBounds);
     InvalidateRegion(this, dirty);
   }
 
-  if (!oldBounds.IsEqualEdges(mBounds)) {
-    DispatchResizeEvent();
+  // XXXndeakin this isn't the right widget listener to use. It should use
+  // the view wrapper pointer but that won't compile. This will be fixed up
+  // in a later patch.
+  if (!oldBounds.IsEqualEdges(mBounds) && mWidgetListener) {
+    mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PuppetWidget::SetFocus(bool aRaise)
 {
@@ -471,88 +475,68 @@ PuppetWidget::SetCursor(nsCursor aCursor
   if (!mTabChild ||
       !mTabChild->SendSetCursor(aCursor)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult
-PuppetWidget::DispatchPaintEvent()
+PuppetWidget::Paint()
 {
   NS_ABORT_IF_FALSE(!mDirtyRegion.IsEmpty(), "paint event logic messed up");
 
-  nsIntRect dirtyRect = mDirtyRegion.GetBounds();
-  nsPaintEvent event(true, NS_PAINT, this);
-  event.refPoint.x = dirtyRect.x;
-  event.refPoint.y = dirtyRect.y;
-  event.region = mDirtyRegion;
-  event.willSendDidPaint = true;
+  if (!mWidgetListener)
+    return NS_OK;
+
+  nsIntRegion region = mDirtyRegion;
 
   // reset repaint tracking
   mDirtyRegion.SetEmpty();
   mPaintTask.Revoke();
 
-  nsEventStatus status;
   {
 #ifdef DEBUG
-    debug_DumpPaintEvent(stderr, this, &event,
+    debug_DumpPaintEvent(stderr, this, region,
                          nsCAutoString("PuppetWidget"), 0);
 #endif
 
     if (mozilla::layers::LAYERS_D3D10 == mLayerManager->GetBackendType()) {
-      DispatchEvent(&event, status);
+      mWidgetListener->PaintWindow(this, region, false, true);
     } else {
       nsRefPtr<gfxContext> ctx = new gfxContext(mSurface);
       ctx->Rectangle(gfxRect(0,0,0,0));
       ctx->Clip();
       AutoLayerManagerSetup setupLayerManager(this, ctx,
                                               BUFFER_NONE);
-      DispatchEvent(&event, status);
+      mWidgetListener->PaintWindow(this, region, false, true);
       mTabChild->NotifyPainted();
     }
   }
 
-  nsPaintEvent didPaintEvent(true, NS_DID_PAINT, this);
-  DispatchEvent(&didPaintEvent, status);
+  mWidgetListener->DidPaintWindow();
 
   return NS_OK;
 }
 
-nsresult
-PuppetWidget::DispatchResizeEvent()
-{
-  nsSizeEvent event(true, NS_SIZE, this);
-
-  nsIntRect rect = mBounds;     // copy in case something messes with it
-  event.windowSize = &rect;
-  event.refPoint.x = rect.x;
-  event.refPoint.y = rect.y;
-  event.mWinWidth = rect.width;
-  event.mWinHeight = rect.height;
-
-  nsEventStatus status;
-  return DispatchEvent(&event, status);
-}
-
 void
 PuppetWidget::SetChild(PuppetWidget* aChild)
 {
   NS_ABORT_IF_FALSE(this != aChild, "can't parent a widget to itself");
   NS_ABORT_IF_FALSE(!aChild->mChild,
                     "fake widget 'hierarchy' only expected to have one level");
 
   mChild = aChild;
 }
 
 NS_IMETHODIMP
 PuppetWidget::PaintTask::Run()
 {
   if (mWidget) {
-    mWidget->DispatchPaintEvent();
+    mWidget->Paint();
   }
   return NS_OK;
 }
 
 float
 PuppetWidget::GetDPI()
 {
   if (mDPI < 0) {
--- a/widget/xpwidgets/PuppetWidget.h
+++ b/widget/xpwidgets/PuppetWidget.h
@@ -161,18 +161,17 @@ public:
 
   // Gets the DPI of the screen corresponding to this widget.
   // Contacts the parent process which gets the DPI from the
   // proper widget there. TODO: Handle DPI changes that happen
   // later on.
   virtual float GetDPI();
 
 private:
-  nsresult DispatchPaintEvent();
-  nsresult DispatchResizeEvent();
+  nsresult Paint();
 
   void SetChild(PuppetWidget* aChild);
 
   nsresult IMEEndComposition(bool aCancel);
 
   class PaintTask : public nsRunnable {
   public:
     NS_DECL_NSIRUNNABLE
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -23,16 +23,17 @@
 #include "LayerManagerOGL.h"
 #include "nsIXULRuntime.h"
 #include "nsIXULWindow.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
 #include "nsView.h"
 #include "nsIViewManager.h"
 #include "nsEventStateManager.h"
+#include "nsIWidgetListener.h"
 #include "nsIGfxInfo.h"
 #include "npapi.h"
 #include "base/thread.h"
 #include "prenv.h"
 #include "mozilla/Attributes.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
@@ -81,17 +82,17 @@ nsAutoRollup::~nsAutoRollup()
 
 //-------------------------------------------------------------------------
 //
 // nsBaseWidget constructor
 //
 //-------------------------------------------------------------------------
 
 nsBaseWidget::nsBaseWidget()
-: mClientData(nullptr)
+: mWidgetListener(nullptr)
 , mViewWrapperPtr(nullptr)
 , mEventCallback(nullptr)
 , mViewCallback(nullptr)
 , mContext(nullptr)
 , mCursor(eCursor_standard)
 , mWindowType(eWindowType_child)
 , mBorderStyle(eBorderStyle_none)
 , mOnDestroyCalled(false)
@@ -227,26 +228,24 @@ NS_IMETHODIMP nsBaseWidget::CaptureMouse
 }
 
 //-------------------------------------------------------------------------
 //
 // Accessor functions to get/set the client data
 //
 //-------------------------------------------------------------------------
 
-NS_IMETHODIMP nsBaseWidget::GetClientData(void*& aClientData)
+nsIWidgetListener* nsBaseWidget::GetWidgetListener()
 {
-  aClientData = mClientData;
-  return NS_OK;
+  return mWidgetListener;
 }
 
-NS_IMETHODIMP nsBaseWidget::SetClientData(void* aClientData)
+void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
 {
-  mClientData = aClientData;
-  return NS_OK;
+  mWidgetListener = aWidgetListener;
 }
 
 already_AddRefed<nsIWidget>
 nsBaseWidget::CreateChild(const nsIntRect  &aRect,
                           EVENT_CALLBACK   aHandleEventFunction,
                           nsDeviceContext *aContext,
                           nsWidgetInitData *aInitData,
                           bool             aForceUseIWidgetParent)
@@ -1341,21 +1340,22 @@ void nsBaseWidget::SetSizeConstraints(co
   // probably in the middle of a reflow.
 }
 
 const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
 {
   return mSizeConstraints;
 }
 
-// If clientData is non-null, then get the presShell from either the window
+// If widgetListener is non-null, then get the presShell from either the window
 // or the view. Otherwise, assume that this is a widget attached to a view.
 static nsIPresShell* GetPresShell(nsIWidget* aWidget, void* clientData)
 {
-  nsCOMPtr<nsIXULWindow> window(do_QueryInterface(static_cast<nsISupports *>(clientData)));
+  nsCOMPtr<nsIXULWindow> window =
+    aWidgetListener ? aWidgetListener->GetXULWindow() : nullptr;
   if (window) {
     nsCOMPtr<nsIDocShell> docShell;
     window->GetDocShell(getter_AddRefs(docShell));
     if (docShell) {
       nsCOMPtr<nsIPresShell> presShell;
       docShell->GetPresShell(getter_AddRefs(presShell));
       return presShell.get();
     }
@@ -1368,19 +1368,23 @@ static nsIPresShell* GetPresShell(nsIWid
   }
  
   return nullptr;
 }
 
 void
 nsBaseWidget::NotifyWindowDestroyed()
 {
-  nsCOMPtr<nsIBaseWindow> window(do_QueryInterface(static_cast<nsISupports *>(mClientData)));
-  if (window) {
-    window->Destroy();
+  if (!mWidgetListener)
+    return;
+
+  nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
+  nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
+  if (xulWindow) {
+    xulWindow->Destroy();
   }
 }
 
 void
 nsBaseWidget::NotifySizeMoveDone()
 {
   nsIPresShell* presShell = GetPresShell(this, nullptr);
   if (presShell) {
@@ -1405,33 +1409,32 @@ nsBaseWidget::NotifyThemeChanged()
     presShell->ThemeChanged();
   }
 }
 
 void
 nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
                                    UIStateChangeType aShowFocusRings)
 {
-  nsCOMPtr<nsIPresShell> presShell = GetPresShell(this, mClientData);
-
+  nsIPresShell* presShell = GetPresShell(this, mWidgetListener);
   nsIDocument* doc = presShell->GetDocument();
   if (doc) {
     nsPIDOMWindow* win = doc->GetWindow();
     if (win) {
       win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
     }
   }
 }
 
 #ifdef ACCESSIBILITY
 
 Accessible*
 nsBaseWidget::GetAccessible()
 {
-  nsIPresShell* presShell = GetPresShell(this, mClientData);
+  nsIPresShell* presShell = GetPresShell(this, mWidgetListener);
   NS_ENSURE_TRUE(presShell, nullptr);
 
   // If container is null then the presshell is not active. This often happens
   // when a preshell is being held onto for fastback.
   nsPresContext* presContext = presShell->GetPresContext();
   nsCOMPtr<nsISupports> container = presContext->GetContainer();
   NS_ENSURE_TRUE(container, nullptr);
 
@@ -1679,28 +1682,27 @@ nsBaseWidget::debug_DumpEvent(FILE *    
           (void *) (aWindowID ? aWindowID : 0x0),
           aGuiEvent->refPoint.x,
           aGuiEvent->refPoint.y);
 }
 //////////////////////////////////////////////////////////////
 /* static */ void
 nsBaseWidget::debug_DumpPaintEvent(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
-                                   nsPaintEvent *        aPaintEvent,
+                                   const nsIntRegion &   aRegion,
                                    const nsCAutoString & aWidgetName,
                                    PRInt32               aWindowID)
 {
   NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
   NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
-  NS_ASSERTION(nullptr != aPaintEvent,"cmon, the paint event is null");
 
   if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
     return;
   
-  nsIntRect rect = aPaintEvent->region.GetBounds();
+  nsIntRect rect = aRegion.GetBounds();
   fprintf(aFileOut,
           "%4d PAINT      widget=%p name=%-12s id=%-8p bounds-rect=%3d,%-3d %3d,%-3d", 
           _GetPrintCount(),
           (void *) aWidget,
           aWidgetName.get(),
           (void *) aWindowID,
           rect.x, rect.y, rect.width, rect.height
     );
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -59,18 +59,18 @@ protected:
 public:
   nsBaseWidget();
   virtual ~nsBaseWidget();
 
   NS_DECL_ISUPPORTS
 
   // nsIWidget interface
   NS_IMETHOD              CaptureMouse(bool aCapture);
-  NS_IMETHOD              GetClientData(void*& aClientData);
-  NS_IMETHOD              SetClientData(void* aClientData);
+  virtual nsIWidgetListener*  GetWidgetListener();
+  virtual void            SetWidgetListener(nsIWidgetListener* alistener);
   NS_IMETHOD              Destroy();
   NS_IMETHOD              SetParent(nsIWidget* aNewParent);
   virtual nsIWidget*      GetParent(void);
   virtual nsIWidget*      GetTopLevelWidget();
   virtual nsIWidget*      GetSheetWindowParent(void);
   virtual float           GetDPI();
   virtual double          GetDefaultScale();
   virtual void            AddChild(nsIWidget* aChild);
@@ -326,17 +326,17 @@ protected:
    * When this function returns, the compositor should not be 
    * able to access the opengl context anymore.
    * It is safe to call it several times if platform implementations
    * require the compositor to be destroyed before ~nsBaseWidget is
    * reached (This is the case with gtk2 for instance).
    */
   void DestroyCompositor();
 
-  void*             mClientData;
+  nsIWidgetListener* mWidgetListener;
   ViewWrapper*      mViewWrapperPtr;
   EVENT_CALLBACK    mEventCallback;
   EVENT_CALLBACK    mViewCallback;
   nsDeviceContext* mContext;
   nsRefPtr<LayerManager> mLayerManager;
   nsRefPtr<LayerManager> mBasicLayerManager;
   nsRefPtr<CompositorChild> mCompositorChild;
   nsRefPtr<CompositorParent> mCompositorParent;
@@ -378,17 +378,17 @@ protected:
   static void debug_DumpEvent(FILE *                aFileOut,
                               nsIWidget *           aWidget,
                               nsGUIEvent *          aGuiEvent,
                               const nsCAutoString & aWidgetName,
                               PRInt32               aWindowID);
 
   static void debug_DumpPaintEvent(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
-                                   nsPaintEvent *        aPaintEvent,
+                                   const nsIntRegion &   aPaintEvent,
                                    const nsCAutoString & aWidgetName,
                                    PRInt32               aWindowID);
 
   static bool debug_GetCachedBoolPref(const char* aPrefName);
 #endif
 };
 
 // A situation can occur when a mouse event occurs over a menu label while the
--- a/xpfe/appshell/src/nsWebShellWindow.cpp
+++ b/xpfe/appshell/src/nsWebShellWindow.cpp
@@ -25,16 +25,17 @@
 #include "nsIWebNavigation.h"
 #include "nsIWindowWatcher.h"
 
 #include "nsIDOMXULElement.h"
 
 #include "nsGUIEvent.h"
 #include "nsWidgetsCID.h"
 #include "nsIWidget.h"
+#include "nsIWidgetListener.h"
 
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMNodeList.h"
 
 #include "nsITimer.h"
 #include "nsXULPopupManager.h"
 
 #include "prmem.h"
@@ -154,22 +155,22 @@ nsresult nsWebShellWindow::Initialize(ns
      top-level child windows in OSes that do not. Later.
   */
   nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent));
   if (parentAsWin) {
     parentAsWin->GetMainWidget(getter_AddRefs(parentWidget));
     mParentWindow = do_GetWeakReference(aParent);
   }
 
-  mWindow->SetClientData(this);
+  mWindow->SetWidgetListener(this);
   mWindow->Create((nsIWidget *)parentWidget,          // Parent nsIWidget
-                  nullptr,                             // Native parent widget
+                  nullptr,                            // Native parent widget
                   r,                                  // Widget dimensions
-                  nsWebShellWindow::HandleEvent,      // Event handler function
-                  nullptr,                             // Device context
+                  nullptr,                            // Event handler function
+                  nullptr,                            // Device context
                   &widgetInitData);                   // Widget initialization data
   mWindow->GetClientBounds(r);
   // Match the default background color of content. Important on windows
   // since we no longer use content child widgets.
   mWindow->SetBackgroundColor(NS_RGB(255,255,255));
 
   // Create web shell
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
@@ -211,218 +212,178 @@ nsresult nsWebShellWindow::Initialize(ns
                          nullptr,
                          nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
   }
                      
   return rv;
 }
 
-
-/*
- * Toolbar
- */
-nsresult
-nsWebShellWindow::Toolbar()
+bool
+nsWebShellWindow::WindowMoved(nsIWidget* aWidget, PRInt32 x, PRInt32 y)
 {
-    nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
-    nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(kungFuDeathGrip));
-    if (!wbc)
-      return NS_ERROR_UNEXPECTED;
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm) {
+    nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
+    pm->AdjustPopupsOnWindowChange(window);
+  }
 
-    // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
-    //      due to components with multiple sidebar components
-    //      (such as Mail/News, Addressbook, etc)... and frankly,
-    //      Mac IE, OmniWeb, and other Mac OS X apps all work this way
-
-    PRUint32    chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
-                              nsIWebBrowserChrome::CHROME_LOCATIONBAR |
-                              nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
-
-    PRUint32    chromeFlags, newChromeFlags = 0;
-    wbc->GetChromeFlags(&chromeFlags);
-    newChromeFlags = chromeFlags & chromeMask;
-    if (!newChromeFlags)    chromeFlags |= chromeMask;
-    else                    chromeFlags &= (~newChromeFlags);
-    wbc->SetChromeFlags(chromeFlags);
-    return NS_OK;
+  // Persist position, but not immediately, in case this OS is firing
+  // repeated move events as the user drags the window
+  SetPersistenceTimer(PAD_POSITION);
+  return false;
 }
 
-
-/*
- * Event handler function...
- *
- * This function is called to process events for the nsIWidget of the 
- * nsWebShellWindow...
- */
-nsEventStatus
-nsWebShellWindow::HandleEvent(nsGUIEvent *aEvent)
+bool
+nsWebShellWindow::WindowResized(nsIWidget* aWidget, PRInt32 aWidth, PRInt32 aHeight)
 {
-  nsEventStatus result = nsEventStatus_eIgnore;
-  nsIDocShell* docShell = nullptr;
-  nsWebShellWindow *eventWindow = nullptr;
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm) {
+    nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
+    pm->AdjustPopupsOnWindowChange(window);
+  }
+
+  nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
+  shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false);
+  // Persist size, but not immediately, in case this OS is firing
+  // repeated size events as the user drags the sizing handle
+  if (!IsLocked())
+    SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
+  return true;
+}
 
-  // Get the WebShell instance...
-  if (nullptr != aEvent->widget) {
-    void* data;
+bool
+nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget)
+{
+  // Maintain a reference to this as it is about to get destroyed.
+  nsCOMPtr<nsIXULWindow> xulWindow(this);
+
+  nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
+  nsCOMPtr<nsIDOMEventTarget> eventTarget = do_QueryInterface(window);
 
-    aEvent->widget->GetClientData(data);
-    if (data != nullptr) {
-      eventWindow = reinterpret_cast<nsWebShellWindow *>(data);
-      docShell = eventWindow->mDocShell;
-    }
+  nsCOMPtr<nsIPresShell> presShell;
+  mDocShell->GetPresShell(getter_AddRefs(presShell));
+
+  if (eventTarget) {
+    nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
+
+    nsEventStatus status = nsEventStatus_eIgnore;
+    nsMouseEvent event(true, NS_XUL_CLOSE, nullptr, nsMouseEvent::eReal);
+    if (NS_SUCCEEDED(eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status)) &&
+        status == nsEventStatus_eConsumeNoDefault)
+      return false;
   }
 
-  if (docShell) {
-    switch(aEvent->message) {
-      /*
-       * For size events, the DocShell must be resized to fill the entire
-       * client area of the window...
-       */
-      case NS_MOVE: {
-        // Adjust any child popups so that their widget offsets and coordinates
-        // are correct with respect to the new position of the window
-        nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-        if (pm) {
-          nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(docShell);
-          pm->AdjustPopupsOnWindowChange(window);
-        }
+  Destroy();
+  return false;
+}
+
+void
+nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode)
+{
+  // An alwaysRaised (or higher) window will hide any newly opened normal
+  // browser windows, so here we just drop a raised window to the normal
+  // zlevel if it's maximized. We make no provision for automatically
+  // re-raising it when restored.
+  if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
+    PRUint32 zLevel;
+    GetZLevel(&zLevel);
+    if (zLevel > nsIXULWindow::normalZ)
+      SetZLevel(nsIXULWindow::normalZ);
+  }
+  mWindow->SetSizeMode(sizeMode);
 
-        // persist position, but not immediately, in case this OS is firing
-        // repeated move events as the user drags the window
-        eventWindow->SetPersistenceTimer(PAD_POSITION);
-        break;
-      }
-      case NS_SIZE: {
-        nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-        if (pm) {
-          nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(docShell);
-          pm->AdjustPopupsOnWindowChange(window);
-        }
- 
-        nsSizeEvent* sizeEvent = (nsSizeEvent*)aEvent;
-        nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(docShell));
-        shellAsWin->SetPositionAndSize(0, 0, sizeEvent->windowSize->width, 
-          sizeEvent->windowSize->height, false);  
-        // persist size, but not immediately, in case this OS is firing
-        // repeated size events as the user drags the sizing handle
-        if (!eventWindow->IsLocked())
-          eventWindow->SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
-        result = nsEventStatus_eConsumeNoDefault;
-        break;
-      }
-      case NS_SIZEMODE: {
-        nsSizeModeEvent* modeEvent = (nsSizeModeEvent*)aEvent;
+  // Persist mode, but not immediately, because in many (all?)
+  // cases this will merge with the similar call in NS_SIZE and
+  // write the attribute values only once.
+  SetPersistenceTimer(PAD_MISC);
+  nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(mDocShell);
+  if (ourWindow) {
+    // Let the application know if it's in fullscreen mode so it
+    // can update its UI.
+    if (sizeMode == nsSizeMode_Fullscreen) {
+      ourWindow->SetFullScreen(true);
+    }
+    else if (sizeMode != nsSizeMode_Minimized) {
+      ourWindow->SetFullScreen(false);
+    }
 
-        // an alwaysRaised (or higher) window will hide any newly opened
-        // normal browser windows. here we just drop a raised window
-        // to the normal zlevel if it's maximized. we make no provision
-        // for automatically re-raising it when restored.
-        if (modeEvent->mSizeMode == nsSizeMode_Maximized ||
-            modeEvent->mSizeMode == nsSizeMode_Fullscreen) {
-          PRUint32 zLevel;
-          eventWindow->GetZLevel(&zLevel);
-          if (zLevel > nsIXULWindow::normalZ)
-            eventWindow->SetZLevel(nsIXULWindow::normalZ);
-        }
-
-        aEvent->widget->SetSizeMode(modeEvent->mSizeMode);
+    // And always fire a user-defined sizemodechange event on the window
+    ourWindow->DispatchCustomEvent("sizemodechange");
+  }
 
-        // persist mode, but not immediately, because in many (all?)
-        // cases this will merge with the similar call in NS_SIZE and
-        // write the attribute values only once.
-        eventWindow->SetPersistenceTimer(PAD_MISC);
-        result = nsEventStatus_eConsumeDoDefault;
+  // Note the current implementation of SetSizeMode just stores
+  // the new state; it doesn't actually resize. So here we store
+  // the state and pass the event on to the OS. The day is coming
+  // when we'll handle the event here, and the return result will
+  // then need to be different.
+}
 
-        nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(docShell);
-        if (ourWindow) {
-          // Let the application know if it's in fullscreen mode so it
-          // can update its UI.
-          if (modeEvent->mSizeMode == nsSizeMode_Fullscreen) {
-            ourWindow->SetFullScreen(true);
-          }
-          else if (modeEvent->mSizeMode != nsSizeMode_Minimized) {
-            ourWindow->SetFullScreen(false);
-          }
+void
+nsWebShellWindow::OSToolbarButtonPressed()
+{
+  // Keep a reference as setting the chrome flags can fire events.
+  nsCOMPtr<nsIXULWindow> xulWindow(this);
 
-          // And always fire a user-defined sizemodechange event on the window
-          ourWindow->DispatchCustomEvent("sizemodechange");
-        }
+  // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
+  //      due to components with multiple sidebar components
+  //      (such as Mail/News, Addressbook, etc)... and frankly,
+  //      Mac IE, OmniWeb, and other Mac OS X apps all work this way
+  PRUint32    chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
+                            nsIWebBrowserChrome::CHROME_LOCATIONBAR |
+                            nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
+
+  nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow));
+  if (!wbc)
+    return;
 
-        // Note the current implementation of SetSizeMode just stores
-        // the new state; it doesn't actually resize. So here we store
-        // the state and pass the event on to the OS. The day is coming
-        // when we'll handle the event here, and the return result will
-        // then need to be different.
-        break;
-      }
-      case NS_OS_TOOLBAR: {
-        nsCOMPtr<nsIXULWindow> kungFuDeathGrip(eventWindow);
-        eventWindow->Toolbar();
-        break;
-      }
-      case NS_XUL_CLOSE: {
-        // Calling ExecuteCloseHandler may actually close the window
-        // (it probably shouldn't, but you never know what the users JS 
-        // code will do).  Therefore we add a death-grip to the window
-        // for the duration of the close handler.
-        nsCOMPtr<nsIXULWindow> kungFuDeathGrip(eventWindow);
-        if (!eventWindow->ExecuteCloseHandler())
-          eventWindow->Destroy();
-        break;
-      }
+  PRUint32    chromeFlags, newChromeFlags = 0;
+  wbc->GetChromeFlags(&chromeFlags);
+  newChromeFlags = chromeFlags & chromeMask;
+  if (!newChromeFlags)    chromeFlags |= chromeMask;
+  else                    chromeFlags &= (~newChromeFlags);
+  wbc->SetChromeFlags(chromeFlags);
+}
 
-      case NS_SETZLEVEL: {
-        nsZLevelEvent *zEvent = (nsZLevelEvent *) aEvent;
-
-        zEvent->mAdjusted = eventWindow->ConstrainToZLevel(zEvent->mImmediate,
-                              &zEvent->mPlacement,
-                              zEvent->mReqBelow, &zEvent->mActualBelow);
-        break;
-      }
+bool
+nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
+                                nsIWidget* aRequestBelow, nsIWidget** aActualBelow)
+{
+  if (aActualBelow)
+    *aActualBelow = nullptr;
 
-      case NS_ACTIVATE: {
-#if defined(DEBUG_saari) || defined(DEBUG_smaug)
-        printf("nsWebShellWindow::NS_ACTIVATE\n");
-#endif
-        // focusing the window could cause it to close, so keep a reference to it
-        nsCOMPtr<nsIXULWindow> kungFuDeathGrip(eventWindow);
+  return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
+}
 
-        nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docShell);
-        nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
-        if (fm && window)
-          fm->WindowRaised(window);
+void
+nsWebShellWindow::WindowActivated()
+{
+  nsCOMPtr<nsIXULWindow> xulWindow(this);
 
-        if (eventWindow->mChromeLoaded) {
-          eventWindow->PersistentAttributesDirty(
-                             PAD_POSITION | PAD_SIZE | PAD_MISC);
-          eventWindow->SavePersistentAttributes();
-        }
+  // focusing the window could cause it to close, so keep a reference to it
+  nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell);
+  nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
+  if (fm && window)
+    fm->WindowRaised(window);
 
-        break;
-      }
-
-      case NS_DEACTIVATE: {
-#if defined(DEBUG_saari) || defined(DEBUG_smaug)
-        printf("nsWebShellWindow::NS_DEACTIVATE\n");
-#endif
+  if (mChromeLoaded) {
+    PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC);
+    SavePersistentAttributes();
+   }
+}
 
-        nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docShell);
-        nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
-        if (fm && window)
-          fm->WindowLowered(window);
-        break;
-      }
-      
-      default:
-        break;
+void
+nsWebShellWindow::WindowDeactivated()
+{
+  nsCOMPtr<nsIXULWindow> xulWindow(this);
 
-    }
-  }
-  return result;
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
+  nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
+  if (fm && window)
+    fm->WindowLowered(window);
 }
 
 #ifdef USE_NATIVE_MENUS
 static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
 {
   // Find the menubar tag (if there is more than one, we ignore all but
   // the first).
   nsCOMPtr<nsIDOMNodeList> menubarElements;
--- a/xpfe/appshell/src/nsWebShellWindow.h
+++ b/xpfe/appshell/src/nsWebShellWindow.h
@@ -7,26 +7,28 @@
 #define nsWebShellWindow_h__
 
 #include "mozilla/Mutex.h"
 #include "nsEvent.h"
 #include "nsIWebProgressListener.h"
 #include "nsITimer.h"
 #include "nsCOMPtr.h"
 #include "nsXULWindow.h"
+#include "nsIWidgetListener.h"
 
 /* Forward declarations.... */
 class nsIURI;
 
 namespace mozilla {
 class WebShellWindowTimerCallback;
 } // namespace mozilla
 
 class nsWebShellWindow : public nsXULWindow,
-                         public nsIWebProgressListener
+                         public nsIWebProgressListener,
+                         public nsIWidgetListener
 {
 public:
   nsWebShellWindow(PRUint32 aChromeFlags);
 
   // nsISupports interface...
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsWebShellWindow methods...
@@ -39,16 +41,29 @@ public:
   nsresult Toolbar();
 
   // nsIWebProgressListener
   NS_DECL_NSIWEBPROGRESSLISTENER
 
   // nsIBaseWindow
   NS_IMETHOD Destroy();
 
+  // nsIWidgetListener
+  virtual nsIXULWindow* GetXULWindow() { return this; }
+
+  virtual bool WindowMoved(nsIWidget* aWidget, PRInt32 x, PRInt32 y);
+  virtual bool WindowResized(nsIWidget* aWidget, PRInt32 aWidth, PRInt32 aHeight);
+  virtual bool RequestWindowClose(nsIWidget* aWidget);
+  virtual void SizeModeChanged(nsSizeMode sizeMode);
+  virtual void OSToolbarButtonPressed();
+  virtual bool ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
+                             nsIWidget* aRequestBelow, nsIWidget** aActualBelow);
+  virtual void WindowActivated();
+  virtual void WindowDeactivated();
+
 protected:
   friend class mozilla::WebShellWindowTimerCallback;
   
   virtual ~nsWebShellWindow();
 
   void                     LoadContentAreas();
   bool                     ExecuteCloseHandler();
   void                     ConstrainToOpenerScreen(PRInt32* aX, PRInt32* aY);
--- a/xpfe/appshell/src/nsXULWindow.cpp
+++ b/xpfe/appshell/src/nsXULWindow.cpp
@@ -503,17 +503,17 @@ NS_IMETHODIMP nsXULWindow::Destroy()
     mPrimaryContentTreeOwner->XULWindow(nullptr);
     NS_RELEASE(mPrimaryContentTreeOwner);
   }
   if (mChromeTreeOwner) {
     mChromeTreeOwner->XULWindow(nullptr);
     NS_RELEASE(mChromeTreeOwner);
   }
   if (mWindow) {
-    mWindow->SetClientData(0); // nsWebShellWindow hackery
+    mWindow->SetWidgetListener(nullptr); // nsWebShellWindow hackery
     mWindow->Destroy();
     mWindow = nullptr;
   }
 
   if (!mIsHiddenWindow) {
     /* Inform appstartup we've destroyed this window and it could
        quit now if it wanted. This must happen at least after mDocShell
        is destroyed, because onunload handlers fire then, and those being
@@ -1874,21 +1874,17 @@ bool nsXULWindow::ConstrainToZLevel(bool
     }
 
     /* CalculateZPosition can tell us to be below nothing, because it tries
        not to change something it doesn't recognize. A request to verify
        being below an unrecognized window, then, is treated as a request
        to come to the top (below null) */
     nsCOMPtr<nsIXULWindow> windowAbove;
     if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) {
-      void *data;
-      (*aActualBelow)->GetClientData(data);
-      if (data) {
-        windowAbove = reinterpret_cast<nsWebShellWindow*>(data);
-      }
+      windowAbove = (*aActualBelow)->GetWidgetListener()->GetXULWindow();
     }
 
     mediator->SetZPosition(us, newPosition, windowAbove);
   }
 
   return altered;
 }