Bug 655267. Move the synth mouse move handling from the view manager to the pres shell. r=roc
authorTimothy Nikkel <tnikkel@gmail.com>
Wed, 11 May 2011 10:49:16 -0500
changeset 69344 916987d881346e5bc8ba17cc843fc42ce5566ea4
parent 69343 d5728312d7564f298556ea73d63bf3f4043f2b40
child 69345 24e3014896d69af7d59b739ffa6b41ff833c9a82
push id19929
push usertnikkel@gmail.com
push dateWed, 11 May 2011 15:49:41 +0000
treeherdermozilla-central@916987d88134 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs655267
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 655267. Move the synth mouse move handling from the view manager to the pres shell. r=roc I also snuck in some minor cleanup.
layout/base/nsPresShell.cpp
view/public/nsIView.h
view/public/nsIViewManager.h
view/src/nsView.cpp
view/src/nsView.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -838,18 +838,16 @@ public:
   virtual LayerManager* GetLayerManager();
 
   virtual void SetIgnoreViewportScrolling(PRBool aIgnore);
 
   virtual void SetDisplayPort(const nsRect& aDisplayPort);
 
   virtual nsresult SetResolution(float aXResolution, float aYResolution);
 
- virtual void SynthesizeMouseMove(PRBool aFromScroll);
-
   //nsIViewObserver interface
 
   NS_IMETHOD Paint(nsIView* aViewToPaint,
                    nsIWidget* aWidget,
                    const nsRegion& aDirtyRegion,
                    const nsIntRegion& aIntDirtyRegion,
                    PRBool aPaintDefaultBackground,
                    PRBool aWillSendDidPaint);
@@ -1377,16 +1375,51 @@ private:
   void FireResizeEvent();
   void FireBeforeResizeEvent();
   static void AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell);
   nsRevocableEventPtr<nsRunnableMethod<PresShell> > mResizeEvent;
   nsCOMPtr<nsITimer> mAsyncResizeEventTimer;
   PRPackedBool mAsyncResizeTimerIsActive;
   PRPackedBool mInResize;
 
+  virtual void SynthesizeMouseMove(PRBool aFromScroll);
+
+  // Check if aEvent is a mouse event and record the mouse location for later
+  // synth mouse moves.
+  void RecordMouseLocation(nsGUIEvent* aEvent);
+  // This is used for synthetic mouse events that are sent when what is under
+  // the mouse pointer may have changed without the mouse moving (eg scrolling,
+  // change to the document contents).
+  // It is set only on a presshell for a root document, this value represents
+  // the last observed location of the mouse relative to that root document. It
+  // is set to (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if the mouse isn't
+  // over our window or there is no last observed mouse location for some
+  // reason.
+  nsPoint mMouseLocation;
+  class nsSynthMouseMoveEvent : public nsRunnable {
+  public:
+    nsSynthMouseMoveEvent(PresShell* aPresShell, PRBool aFromScroll)
+      : mPresShell(aPresShell), mFromScroll(aFromScroll) {
+      NS_ASSERTION(mPresShell, "null parameter");
+    }
+    void Revoke() { mPresShell = nsnull; }
+    NS_IMETHOD Run() {
+      if (mPresShell)
+        mPresShell->ProcessSynthMouseMoveEvent(mFromScroll);
+      return NS_OK;
+    }
+  private:
+    PresShell* mPresShell;
+    PRBool mFromScroll;
+  };
+  nsRevocableEventPtr<nsSynthMouseMoveEvent> mSynthMouseMoveEvent;
+  void ProcessSynthMouseMoveEvent(PRBool aFromScroll);
+
+  PresShell* GetRootPresShell();
+
 private:
 #ifdef DEBUG
   // Ensure that every allocation from the PresArena is eventually freed.
   PRUint32 mPresArenaAllocCount;
 #endif
 
 public:
 
@@ -1654,16 +1687,17 @@ NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresS
 
 NS_MEMORY_REPORTER_IMPLEMENT(LayoutBidi,
                              "heap-used/layout/bidi",
                              "Memory used by layout Bidi processor.",
                              PresShell::SizeOfBidiMemoryReporter,
                              nsnull)
 
 PresShell::PresShell()
+  : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
 {
   mSelection = nsnull;
 #ifdef MOZ_REFLOW_PERF
   mReflowCountMgr = new ReflowCountMgr();
   mReflowCountMgr->SetPresContext(mPresContext);
   mReflowCountMgr->SetPresShell(this);
 #endif
 #ifdef PR_LOGGING
@@ -1950,16 +1984,18 @@ PresShell::Destroy()
   }
 
   // Same for our reflow continuation timer
   if (mReflowContinueTimer) {
     mReflowContinueTimer->Cancel();
     mReflowContinueTimer = nsnull;
   }
 
+  mSynthMouseMoveEvent.Revoke();
+
   if (mCaret) {
     mCaret->Terminate();
     mCaret = nsnull;
   }
 
   if (mSelection) {
     mSelection->DisconnectFromPresShell();
   }
@@ -5950,18 +5986,189 @@ void PresShell::SetRenderingState(const 
 
   mRenderFlags = aState.mRenderFlags;
   mXResolution = aState.mXResolution;
   mYResolution = aState.mYResolution;
 }
 
 void PresShell::SynthesizeMouseMove(PRBool aFromScroll)
 {
-  if (mViewManager && !mPaintingSuppressed && mIsActive) {
-    mViewManager->SynthesizeMouseMove(aFromScroll);
+  if (mPaintingSuppressed || !mIsActive || !mPresContext) {
+    return;
+  }
+
+  if (!mPresContext->IsRoot()) {
+    nsIPresShell* rootPresShell = GetRootPresShell();
+    if (rootPresShell) {
+      rootPresShell->SynthesizeMouseMove(aFromScroll);
+    }
+    return;
+  }
+
+  if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
+    return;
+
+  if (!mSynthMouseMoveEvent.IsPending()) {
+    nsRefPtr<nsSynthMouseMoveEvent> ev =
+        new nsSynthMouseMoveEvent(this, aFromScroll);
+
+    if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
+      NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
+      return;
+    }
+
+    mSynthMouseMoveEvent = ev;
+  }
+}
+
+/**
+ * Find the first floating view with a widget in a postorder traversal of the
+ * view tree that contains the point. Thus more deeply nested floating views
+ * are preferred over their ancestors, and floating views earlier in the
+ * view hierarchy (i.e., added later) are preferred over their siblings.
+ * This is adequate for finding the "topmost" floating view under a point,
+ * given that floating views don't supporting having a specific z-index.
+ * 
+ * We cannot exit early when aPt is outside the view bounds, because floating
+ * views aren't necessarily included in their parent's bounds, so this could
+ * traverse the entire view hierarchy --- use carefully.
+ */
+static nsIView* FindFloatingViewContaining(nsIView* aView, nsPoint aPt)
+{
+  if (aView->GetVisibility() == nsViewVisibility_kHide)
+    // No need to look into descendants.
+    return nsnull;
+
+  nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
+  if (frame && !frame->PresContext()->PresShell()->IsActive()) {
+    return nsnull;
+  }
+
+  for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
+    nsIView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
+    if (r)
+      return r;
+  }
+
+  if (aView->GetFloating() && aView->HasWidget() &&
+      aView->GetDimensions().Contains(aPt))
+    return aView;
+    
+  return nsnull;
+}
+
+/*
+ * This finds the first view containing the given point in a postorder
+ * traversal of the view tree that contains the point, assuming that the
+ * point is not in a floating view.  It assumes that only floating views
+ * extend outside the bounds of their parents.
+ *
+ * This methods should only be called if FindFloatingViewContaining
+ * returns null.
+ */
+static nsIView* FindViewContaining(nsIView* aView, nsPoint aPt)
+{
+  if (!aView->GetDimensions().Contains(aPt) ||
+      aView->GetVisibility() == nsViewVisibility_kHide) {
+    return nsnull;
+  }
+
+  nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
+  if (frame && !frame->PresContext()->PresShell()->IsActive()) {
+    return nsnull;
+  }
+
+  for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
+    nsIView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
+    if (r)
+      return r;
+  }
+
+  return aView;
+}
+
+void
+PresShell::ProcessSynthMouseMoveEvent(PRBool aFromScroll)
+{
+  // allow new event to be posted while handling this one only if the
+  // source of the event is a scroll (to prevent infinite reflow loops)
+  if (aFromScroll) {
+    mSynthMouseMoveEvent.Forget();
+  }
+
+  nsIView* rootView = mViewManager ? mViewManager->GetRootView() : nsnull;
+  if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) ||
+      !rootView || !rootView->HasWidget() || !mPresContext) {
+    mSynthMouseMoveEvent.Forget();
+    return;
+  }
+
+  NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here");
+
+  // Hold a ref to ourselves so DispatchEvent won't destroy us (since
+  // we need to access members after we call DispatchEvent).
+  nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
+  
+#ifdef DEBUG_MOUSE_LOCATION
+  printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
+         this, mMouseLocation.x, mMouseLocation.y);
+#endif
+
+  PRInt32 APD = mPresContext->AppUnitsPerDevPixel();
+
+  // We need a widget to put in the event we are going to dispatch so we look
+  // for a view that has a widget and the mouse location is over. We first look
+  // for floating views, if there isn't one we use the root view. |view| holds
+  // that view.
+  nsIView* view = nsnull;
+
+  // The appunits per devpixel ratio of |view|.
+  PRInt32 viewAPD;
+
+  // refPoint will be mMouseLocation relative to the widget of |view|, the
+  // widget we will put in the event we dispatch, in viewAPD appunits
+  nsPoint refpoint(0, 0);
+
+  // We always dispatch the event to the pres shell that contains the view that
+  // the mouse is over. pointVM is the VM of that pres shell.
+  nsIViewManager *pointVM = nsnull;
+
+  // This could be a bit slow (traverses entire view hierarchy)
+  // but it's OK to do it once per synthetic mouse event
+  view = FindFloatingViewContaining(rootView, mMouseLocation);
+  if (!view) {
+    view = rootView;
+    nsIView *pointView = FindViewContaining(rootView, mMouseLocation);
+    // pointView can be null in situations related to mouse capture
+    pointVM = (pointView ? pointView : view)->GetViewManager();
+    refpoint = mMouseLocation + rootView->ViewToWidgetOffset();
+    viewAPD = APD;
+  } else {
+    pointVM = view->GetViewManager();
+    nsIFrame* frame = static_cast<nsIFrame*>(view->GetClientData());
+    NS_ASSERTION(frame, "floating views can't be anonymous");
+    viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
+    refpoint = mMouseLocation.ConvertAppUnits(APD, viewAPD);
+    refpoint -= view->GetOffsetTo(rootView);
+    refpoint += view->ViewToWidgetOffset();
+  }
+  NS_ASSERTION(view->GetWidget(), "view should have a widget here");
+  nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, view->GetWidget(),
+                     nsMouseEvent::eSynthesized);
+  event.refPoint = refpoint.ToNearestPixels(viewAPD);
+  event.time = PR_IntervalNow();
+  // XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
+
+  nsCOMPtr<nsIViewObserver> observer = pointVM->GetViewObserver();
+  if (observer) {
+    observer->DispatchSynthMouseMove(&event, !aFromScroll);
+  }
+
+  if (!aFromScroll) {
+    mSynthMouseMoveEvent.Forget();
   }
 }
 
 static void DrawThebesLayer(ThebesLayer* aLayer,
                             gfxContext* aContext,
                             const nsIntRegion& aRegionToDraw,
                             const nsIntRegion& aRegionToInvalidate,
                             void* aCallbackData)
@@ -6244,30 +6451,85 @@ PresShell::GetFocusedDOMWindowInOurWindo
 {
   nsCOMPtr<nsPIDOMWindow> rootWindow = GetRootWindow();
   NS_ENSURE_TRUE(rootWindow, nsnull);
   nsPIDOMWindow* focusedWindow;
   nsFocusManager::GetFocusedDescendant(rootWindow, PR_TRUE, &focusedWindow);
   return focusedWindow;
 }
 
+void
+PresShell::RecordMouseLocation(nsGUIEvent* aEvent)
+{
+  if (!mPresContext)
+    return;
+
+  if (!mPresContext->IsRoot()) {
+    PresShell* rootPresShell = GetRootPresShell();
+    if (rootPresShell) {
+      rootPresShell->RecordMouseLocation(aEvent);
+    }
+    return;
+  }
+
+  if ((aEvent->message == NS_MOUSE_MOVE &&
+       static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal) ||
+      aEvent->message == NS_MOUSE_ENTER ||
+      aEvent->message == NS_MOUSE_BUTTON_DOWN ||
+      aEvent->message == NS_MOUSE_BUTTON_UP) {
+    nsIFrame* rootFrame = GetRootFrame();
+    if (!rootFrame) {
+      nsIView* rootView = mViewManager->GetRootView();
+      mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
+        aEvent->widget, aEvent->refPoint, rootView);
+    } else {
+      mMouseLocation =
+        nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
+    }
+#ifdef DEBUG_MOUSE_LOCATION
+    if (aEvent->message == NS_MOUSE_ENTER)
+      printf("[ps=%p]got mouse enter for %p\n",
+             this, aEvent->widget);
+    printf("[ps=%p]setting mouse location to (%d,%d)\n",
+           this, mMouseLocation.x, mMouseLocation.y);
+#endif
+    if (aEvent->message == NS_MOUSE_ENTER)
+      SynthesizeMouseMove(PR_FALSE);
+  } else if (aEvent->message == NS_MOUSE_EXIT) {
+    // Although we only care about the mouse moving into an area for which this
+    // pres shell doesn't receive mouse move events, we don't check which widget
+    // the mouse exit was for since this seems to vary by platform.  Hopefully
+    // this won't matter at all since we'll get the mouse move or enter after
+    // the mouse exit when the mouse moves from one of our widgets into another.
+    mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
+#ifdef DEBUG_MOUSE_LOCATION
+    printf("[ps=%p]got mouse exit for %p\n",
+           this, aEvent->widget);
+    printf("[ps=%p]clearing mouse location\n",
+           this);
+#endif
+  }
+}
+
 NS_IMETHODIMP
 PresShell::HandleEvent(nsIView         *aView,
                        nsGUIEvent*     aEvent,
                        PRBool          aDontRetargetEvents,
                        nsEventStatus*  aEventStatus)
 {
   NS_ASSERTION(aView, "null view");
 
   if (mIsDestroying ||
       (sDisableNonTestMouseEvents && NS_IS_MOUSE_EVENT(aEvent) &&
        !(aEvent->flags & NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT))) {
     return NS_OK;
   }
 
+  RecordMouseLocation(aEvent);
+
 #ifdef ACCESSIBILITY
   if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT) {
     NS_TIME_FUNCTION_MIN(1.0);
 
     // Accessibility events come through OS requests and not from scripts,
     // so it is safe to handle here
     return HandleEventInternal(aEvent, aView, aEventStatus);
   }
@@ -9260,8 +9522,20 @@ PresShell::SetIsActive(PRBool aIsActive)
  * dependent factors changes.
  */
 nsresult
 PresShell::UpdateImageLockingState()
 {
   // We're locked if we're both thawed and active.
   return mDocument->SetImageLockingState(!mFrozen && mIsActive);
 }
+
+PresShell*
+PresShell::GetRootPresShell()
+{
+  if (mPresContext) {
+    nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
+    if (rootPresContext) {
+      return static_cast<PresShell*>(rootPresContext->PresShell());
+    }
+  }
+  return nsnull;
+}
--- a/view/public/nsIView.h
+++ b/view/public/nsIView.h
@@ -57,18 +57,18 @@ class nsIWidget;
 // show - the layer is shown irrespective of the visibility of 
 //        the layer's parent.
 enum nsViewVisibility {
   nsViewVisibility_kHide = 0,
   nsViewVisibility_kShow = 1
 };
 
 #define NS_IVIEW_IID    \
-  { 0x63052d96, 0x2a4b, 0x434f, \
-    { 0xb4, 0xd3, 0x61, 0x41, 0x83, 0x24, 0x00, 0x76 } }
+  { 0xe0a3b0ee, 0x8d0f, 0x4dcb, \
+    { 0x89, 0x04, 0x81, 0x2d, 0xfd, 0x90, 0x00, 0x73 } }
 
 // Public view flags are defined in this file
 #define NS_VIEW_FLAGS_PUBLIC              0x00FF
 // Private view flags are private to the view module,
 // and are defined in nsView.h
 #define NS_VIEW_FLAGS_PRIVATE             0xFF00
 
 // Public view flags
@@ -169,16 +169,24 @@ public:
    * are in appunits of this.
    * The view's bounds (x,y) might not be the same as the view's position,
    * if the view has content above or to the left of its origin.
    * @param aBounds out parameter for bounds
    */
   nsRect GetBounds() const { return mDimBounds; }
 
   /**
+   * The bounds of this view relative to this view. So this is the same as
+   * GetBounds except this is relative to this view instead of the parent view.
+   */
+  nsRect GetDimensions() const {
+    nsRect r = mDimBounds; r.MoveBy(-mPosX, -mPosY); return r;
+  }
+
+  /**
    * Set the dimensions at which invalidations are clipped, which can
    * be different than |GetDimensions()|.  |aRect| is relative to
    * |this|.  It can be null, in which case invalidations return to
    * being clipped to the view dimensions.
    *
    * The caller is responsible for invalidating the area that may lie
    * outside the view dimensions but inside |aRect| after this call.
    */
@@ -209,16 +217,23 @@ public:
    * Adding the return value to a point in the coordinate system of |this|
    * will transform the point to the coordinate system of aWidget.
    *
    * The offset is expressed in appunits of |this|.
    */
   nsPoint GetOffsetToWidget(nsIWidget* aWidget) const;
 
   /**
+   * Takes a point aPt that is in the coordinate system of |this|'s parent view
+   * and converts it to be in the coordinate system of |this| taking into
+   * account the offset and any app unit per dev pixel ratio differences.
+   */
+  nsPoint ConvertFromParentCoords(nsPoint aPt) const;
+
+  /**
    * Called to query the visibility state of a view.
    * @result current visibility state
    */
   nsViewVisibility GetVisibility() const { return mVis; }
 
   /**
    * Called to query the z-index of a view.
    * The z-index is relative to all siblings of the view.
--- a/view/public/nsIViewManager.h
+++ b/view/public/nsIViewManager.h
@@ -44,18 +44,18 @@
 
 class nsIWidget;
 struct nsRect;
 class nsRegion;
 class nsDeviceContext;
 class nsIViewObserver;
 
 #define NS_IVIEWMANAGER_IID \
-{ 0xa47cdaf9, 0x50fd, 0x40d8, \
-  { 0x92, 0xe5, 0x93, 0x4f, 0xfb, 0x01, 0xdd, 0x98 } }
+{ 0x144ef328, 0xbece, 0x43d6, \
+  { 0xac, 0xac, 0x1a, 0x90, 0x4b, 0x5c, 0xc1, 0x11 } }
 
 class nsIViewManager : public nsISupports
 {
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWMANAGER_IID)
   /**
    * Initialize the ViewManager
@@ -255,26 +255,23 @@ public:
    * this view. This is a hack, but it fixes some problems with
    * views that need to be drawn in front of all other views.
    */
   NS_IMETHOD  SetViewFloating(nsIView *aView, PRBool aFloatingView) = 0;
 
   /**
    * Set the view observer associated with this manager
    * @param aObserver - new observer
-   * @result error status
    */
-  NS_IMETHOD SetViewObserver(nsIViewObserver *aObserver) = 0;
+  virtual void SetViewObserver(nsIViewObserver *aObserver) = 0;
 
   /**
    * Get the view observer associated with this manager
-   * @param aObserver - out parameter for observer
-   * @result error status
    */
-  NS_IMETHOD GetViewObserver(nsIViewObserver *&aObserver) = 0;
+  virtual nsIViewObserver* GetViewObserver() = 0;
 
   /**
    * Get the device context associated with this manager
    * @result device context
    */
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext) = 0;
 
   class UpdateViewBatch {
@@ -376,23 +373,16 @@ public:
   /**
    * Retrieve the time of the last user event. User events
    * include mouse and keyboard events. The viewmanager
    * saves the time of the last user event.
    *
    * @param aTime Last user event time in microseconds
    */
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime)=0;
-
-  /**
-   * Dispatch a mouse move event based on the most recent mouse
-   * position.  This is used when the contents of the page moved
-   * (aFromScroll is false) or scrolled (aFromScroll is true).
-   */
-  NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll)=0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID)
 
 // Paint timing mode flags
 
 // intermediate: do no special timing processing; repaint when the
 // toolkit issues an expose event (which will happen *before* PLEvent
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -1179,18 +1179,19 @@ nsView::GetBoundsInParentUnits() const
     return mDimBounds;
   }
   PRInt32 ourAPD = VM->AppUnitsPerDevPixel();
   PRInt32 parentAPD = parent->GetViewManager()->AppUnitsPerDevPixel();
   return mDimBounds.ConvertAppUnitsRoundOut(ourAPD, parentAPD);
 }
 
 nsPoint
-nsView::ConvertFromParentCoords(nsPoint aPt) const
+nsIView::ConvertFromParentCoords(nsPoint aPt) const
 {
-  nsView* parent = GetParent();
+  const nsView* view = static_cast<const nsView*>(this);
+  const nsView* parent = view->GetParent();
   if (parent) {
     aPt = aPt.ConvertAppUnits(parent->GetViewManager()->AppUnitsPerDevPixel(),
-                              GetViewManager()->AppUnitsPerDevPixel());
+                              view->GetViewManager()->AppUnitsPerDevPixel());
   }
   aPt -= GetPosition();
   return aPt;
 }
--- a/view/src/nsView.h
+++ b/view/src/nsView.h
@@ -72,18 +72,16 @@ public:
    * Called to indicate that the dimensions of the view have been changed.
    * The x and y coordinates may be < 0, indicating that the view extends above
    * or to the left of its origin position. The term 'dimensions' indicates it
    * is relative to this view.
    */
   virtual void SetDimensions(const nsRect &aRect, PRBool aPaint = PR_TRUE,
                              PRBool aResizeWidget = PR_TRUE);
   void SetInvalidationDimensions(const nsRect* aRect);
-  void GetDimensions(nsRect &aRect) const { aRect = mDimBounds; aRect.x -= mPosX; aRect.y -= mPosY; }
-  void GetDimensions(nsSize &aSize) const { aSize.width = mDimBounds.width; aSize.height = mDimBounds.height; }
 
   /**
    * Called to indicate that the visibility of a view has been
    * changed.
    * @param visibility new visibility state
    */
   NS_IMETHOD  SetVisibility(nsViewVisibility visibility);
 
@@ -143,18 +141,16 @@ public:
   // instead of nsIView and nsIViewManager.
   nsView* GetFirstChild() const { return mFirstChild; }
   nsView* GetNextSibling() const { return mNextSibling; }
   nsView* GetParent() const { return mParent; }
   nsViewManager* GetViewManager() const { return mViewManager; }
   // These are superseded by a better interface in nsIView
   PRInt32 GetZIndex() const { return mZIndex; }
   PRBool GetZIndexIsAuto() const { return (mVFlags & NS_VIEW_FLAG_AUTO_ZINDEX) != 0; }
-  // This is a better interface than GetDimensions(nsRect&) above
-  nsRect GetDimensions() const { nsRect r = mDimBounds; r.MoveBy(-mPosX, -mPosY); return r; }
   // Same as GetBounds but converts to parent appunits if they are different.
   nsRect GetBoundsInParentUnits() const;
 
   nsRect GetInvalidationDimensions() const {
     return mHaveInvalidationDimensions ? mInvalidationDimensions : GetDimensions();
   }
 
   // These are defined exactly the same in nsIView, but for now they have to be redeclared
@@ -180,17 +176,16 @@ public:
   void SetNextSibling(nsView *aSibling) { mNextSibling = aSibling; }
 
   PRUint32 GetViewFlags() const { return mVFlags; }
   void SetViewFlags(PRUint32 aFlags) { mVFlags = aFlags; }
 
   void SetTopMost(PRBool aTopMost) { aTopMost ? mVFlags |= NS_VIEW_FLAG_TOPMOST : mVFlags &= ~NS_VIEW_FLAG_TOPMOST; }
   PRBool IsTopMost() { return((mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); }
 
-  nsPoint ConvertFromParentCoords(nsPoint aPt) const;
   void ResetWidgetBounds(PRBool aRecurse, PRBool aMoveOnly, PRBool aInvalidateChangedSize);
   void SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY);
   void AssertNoWindow();
 
   void NotifyEffectiveVisibilityChanged(PRBool aEffectivelyVisible);
 
   // Update the cached RootViewManager for all view manager descendents,
   // If the hierarchy is being removed, aViewManagerParent points to the view
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -71,48 +71,31 @@ PRTime gFirstPaintTimestamp = 0; // Time
 
    DeCOMify newly private methods
    Optimize view storage
 */
 
 /**
    A note about platform assumptions:
 
-   We assume all native widgets are opaque.
-   
    We assume that a widget is z-ordered on top of its parent.
    
    We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
    we ask for a specific z-order, we don't assume that widget z-ordering actually works.
 */
 
 #define NSCOORD_NONE      PR_INT32_MIN
 
-//-------------- Begin Invalidate Event Definition ------------------------
-
-class nsInvalidateEvent : public nsViewManagerEvent {
-public:
-  nsInvalidateEvent(nsViewManager *vm) : nsViewManagerEvent(vm) {}
-
-  NS_IMETHOD Run() {
-    if (mViewManager)
-      mViewManager->ProcessInvalidateEvent();
-    return NS_OK;
-  }
-};
-
-//-------------- End Invalidate Event Definition ---------------------------
-
 void
 nsViewManager::PostInvalidateEvent()
 {
   NS_ASSERTION(IsRootVM(), "Caller screwed up");
 
   if (!mInvalidateEvent.IsPending()) {
-    nsRefPtr<nsViewManagerEvent> ev = new nsInvalidateEvent(this);
+    nsRefPtr<nsInvalidateEvent> ev = new nsInvalidateEvent(this);
     if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
       NS_WARNING("failed to dispatch nsInvalidateEvent");
     } else {
       mInvalidateEvent = ev;
     }
   }
 }
 
@@ -120,18 +103,17 @@ nsViewManager::PostInvalidateEvent()
 
 PRInt32 nsViewManager::mVMCount = 0;
 
 // Weakly held references to all of the view managers
 nsVoidArray* nsViewManager::gViewManagers = nsnull;
 PRUint32 nsViewManager::gLastUserEventTime = 0;
 
 nsViewManager::nsViewManager()
-  : mMouseLocation(NSCOORD_NONE, NSCOORD_NONE)
-  , mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
+  : mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
   , mRootViewManager(this)
 {
   if (gViewManagers == nsnull) {
     NS_ASSERTION(mVMCount == 0, "View Manager count is incorrect");
     // Create an array to hold a list of view managers
     gViewManagers = new nsVoidArray;
   }
  
@@ -152,17 +134,16 @@ nsViewManager::~nsViewManager()
     // Destroy any remaining views
     mRootView->Destroy();
     mRootView = nsnull;
   }
 
   // Make sure to revoke pending events for all viewmanagers, since some events
   // are posted by a non-root viewmanager.
   mInvalidateEvent.Revoke();
-  mSynthMouseMoveEvent.Revoke();
   
   if (!IsRootVM()) {
     // We have a strong ref to mRootViewManager
     NS_RELEASE(mRootViewManager);
   }
 
   NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
   --mVMCount;
@@ -274,18 +255,17 @@ NS_IMETHODIMP nsViewManager::SetRootView
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeight)
 {
   if (nsnull != mRootView) {
     if (mDelayedResize == nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
-      nsRect dim;
-      mRootView->GetDimensions(dim);
+      nsRect dim = mRootView->GetDimensions();
       *aWidth = dim.width;
       *aHeight = dim.height;
     } else {
       *aWidth = mDelayedResize.width;
       *aHeight = mDelayedResize.height;
     }
   }
   else
@@ -293,19 +273,18 @@ NS_IMETHODIMP nsViewManager::GetWindowDi
       *aWidth = 0;
       *aHeight = 0;
     }
   return NS_OK;
 }
 
 void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
 {
-  nsRect oldDim;
+  nsRect oldDim = mRootView->GetDimensions();
   nsRect newDim(0, 0, aWidth, aHeight);
-  mRootView->GetDimensions(oldDim);
   // We care about resizes even when one dimension is already zero.
   if (!oldDim.IsEqualEdges(newDim)) {
     // Don't resize the widget. It is already being set elsewhere.
     mRootView->SetDimensions(newDim, PR_TRUE, PR_FALSE);
     if (mObserver)
       mObserver->ResizeReflow(mRootView, aWidth, aHeight);
   }
 }
@@ -396,18 +375,17 @@ void nsViewManager::Refresh(nsView *aVie
 
   // damageRegion is the damaged area, in twips, relative to the view origin
   nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
   // move region from widget coordinates into view coordinates
   damageRegion.MoveBy(-aView->ViewToWidgetOffset());
 
   if (damageRegion.IsEmpty()) {
 #ifdef DEBUG_roc
-    nsRect viewRect;
-    aView->GetDimensions(viewRect);
+    nsRect viewRect = aView->GetDimensions();
     nsRect damageRect = damageRegion.GetBounds();
     printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
            damageRect.x, damageRect.y, damageRect.width, damageRect.height,
            viewRect.x, viewRect.y, viewRect.width, viewRect.height);
 #endif
     return;
   }
 
@@ -507,20 +485,17 @@ NS_IMETHODIMP nsViewManager::Composite()
     }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
 {
   // Mark the entire view as damaged
-  nsView* view = static_cast<nsView*>(aView);
-
-  nsRect dims = view->GetDimensions();
-  return UpdateView(view, dims, aUpdateFlags);
+  return UpdateView(aView, aView->GetDimensions(), aUpdateFlags);
 }
 
 /**
  * @param aWidget the widget for aWidgetView; in some cases the widget
  * is being managed directly by the frame system, so aWidgetView->GetWidget()
  * will return null but nsView::GetViewFor(aWidget) returns aWidgetview
  * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
  * every widget child of aWidgetView, plus aWidgetView's own widget
@@ -1035,60 +1010,16 @@ NS_IMETHODIMP nsViewManager::DispatchEve
 
         if (NS_IsEventUsingCoordinates(aEvent)) {
           // will dispatch using coordinates. Pretty bogus but it's consistent
           // with what presshell does.
           view = GetDisplayRootFor(baseView);
         }
 
         if (nsnull != view) {
-          PRInt32 APD = AppUnitsPerDevPixel();
-
-          if ((aEvent->message == NS_MOUSE_MOVE &&
-               static_cast<nsMouseEvent*>(aEvent)->reason ==
-                 nsMouseEvent::eReal) ||
-              aEvent->message == NS_MOUSE_ENTER ||
-              aEvent->message == NS_MOUSE_BUTTON_DOWN ||
-              aEvent->message == NS_MOUSE_BUTTON_UP) {
-            // aEvent->point is relative to the widget, so we convert it to be
-            // relative to the view origin
-            nsPoint pt = -baseView->ViewToWidgetOffset();
-            pt += baseView->GetOffsetTo(RootViewManager()->mRootView);
-            pt.x += NSIntPixelsToAppUnits(aEvent->refPoint.x, APD);
-            pt.y += NSIntPixelsToAppUnits(aEvent->refPoint.y, APD);
-            PRInt32 rootAPD = RootViewManager()->AppUnitsPerDevPixel();
-            pt = pt.ConvertAppUnits(APD, rootAPD);
-            RootViewManager()->mMouseLocation = pt;
-#ifdef DEBUG_MOUSE_LOCATION
-            if (aEvent->message == NS_MOUSE_ENTER)
-              printf("[vm=%p]got mouse enter for %p\n",
-                     this, aEvent->widget);
-            printf("[vm=%p]setting mouse location to (%d,%d)\n",
-                   this, mMouseLocation.x, mMouseLocation.y);
-#endif
-            if (aEvent->message == NS_MOUSE_ENTER)
-              SynthesizeMouseMove(PR_FALSE);
-          } else if (aEvent->message == NS_MOUSE_EXIT) {
-            // Although we only care about the mouse moving into an area
-            // for which this view manager doesn't receive mouse move
-            // events, we don't check which view the mouse exit was for
-            // since this seems to vary by platform.  Hopefully this
-            // won't matter at all since we'll get the mouse move or
-            // enter after the mouse exit when the mouse moves from one
-            // of our widgets into another.
-            RootViewManager()->mMouseLocation =
-              nsPoint(NSCOORD_NONE, NSCOORD_NONE);
-#ifdef DEBUG_MOUSE_LOCATION
-            printf("[vm=%p]got mouse exit for %p\n",
-                   this, aEvent->widget);
-            printf("[vm=%p]clearing mouse location\n",
-                   this);
-#endif
-          }
-
           *aStatus = HandleEvent(view, aEvent);
         }
     
         break;
       }
     }
 
   return NS_OK;
@@ -1343,19 +1274,18 @@ void nsViewManager::InvalidateRectDiffer
     InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.YMost(), aRect.YMost(), PR_FALSE);
   }
 }
 
 NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRBool aRepaintExposedAreaOnly)
 {
   nsView* view = static_cast<nsView*>(aView);
   NS_ASSERTION(view->GetViewManager() == this, "wrong view manager");
-  nsRect oldDimensions;
 
-  view->GetDimensions(oldDimensions);
+  nsRect oldDimensions = view->GetDimensions();
   if (!oldDimensions.IsEqualEdges(aRect)) {
     // resize the view.
     // Prevent Invalidation of hidden views 
     if (view->GetVisibility() == nsViewVisibility_kHide) {  
       view->SetDimensions(aRect, PR_FALSE);
     } else {
       nsView* parentView = view->GetParent();
       if (!parentView) {
@@ -1499,32 +1429,16 @@ NS_IMETHODIMP nsViewManager::SetViewZInd
   if (oldidx != aZIndex || oldTopMost != aTopMost ||
       oldIsAuto != aAutoZIndex) {
     UpdateView(view, NS_VMREFRESH_NO_SYNC);
   }
 
   return rv;
 }
 
-NS_IMETHODIMP nsViewManager::SetViewObserver(nsIViewObserver *aObserver)
-{
-  mObserver = aObserver;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsViewManager::GetViewObserver(nsIViewObserver *&aObserver)
-{
-  if (nsnull != mObserver) {
-    aObserver = mObserver;
-    NS_ADDREF(mObserver);
-    return NS_OK;
-  } else
-    return NS_ERROR_NO_INTERFACE;
-}
-
 NS_IMETHODIMP nsViewManager::GetDeviceContext(nsDeviceContext *&aContext)
 {
   NS_IF_ADDREF(mContext);
   aContext = mContext;
   return NS_OK;
 }
 
 void nsViewManager::TriggerRefresh(PRUint32 aUpdateFlags)
@@ -1723,181 +1637,16 @@ nsViewManager::ProcessInvalidateEvent()
 
 NS_IMETHODIMP
 nsViewManager::GetLastUserEventTime(PRUint32& aTime)
 {
   aTime = gLastUserEventTime;
   return NS_OK;
 }
 
-class nsSynthMouseMoveEvent : public nsViewManagerEvent {
-public:
-  nsSynthMouseMoveEvent(nsViewManager *aViewManager,
-                        PRBool aFromScroll)
-    : nsViewManagerEvent(aViewManager),
-      mFromScroll(aFromScroll) {
-  }
-
-  NS_IMETHOD Run() {
-    if (mViewManager)
-      mViewManager->ProcessSynthMouseMoveEvent(mFromScroll);
-    return NS_OK;
-  }
-
-private:
-  PRBool mFromScroll;
-};
-
-NS_IMETHODIMP
-nsViewManager::SynthesizeMouseMove(PRBool aFromScroll)
-{
-  if (!IsRootVM())
-    return RootViewManager()->SynthesizeMouseMove(aFromScroll);
-
-  if (mMouseLocation == nsPoint(NSCOORD_NONE, NSCOORD_NONE))
-    return NS_OK;
-
-  if (!mSynthMouseMoveEvent.IsPending()) {
-    nsRefPtr<nsViewManagerEvent> ev =
-        new nsSynthMouseMoveEvent(this, aFromScroll);
-
-    if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
-      NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    mSynthMouseMoveEvent = ev;
-  }
-
-  return NS_OK;
-}
-
-/**
- * Find the first floating view with a widget in a postorder traversal of the
- * view tree that contains the point. Thus more deeply nested floating views
- * are preferred over their ancestors, and floating views earlier in the
- * view hierarchy (i.e., added later) are preferred over their siblings.
- * This is adequate for finding the "topmost" floating view under a point,
- * given that floating views don't supporting having a specific z-index.
- * 
- * We cannot exit early when aPt is outside the view bounds, because floating
- * views aren't necessarily included in their parent's bounds, so this could
- * traverse the entire view hierarchy --- use carefully.
- */
-static nsView* FindFloatingViewContaining(nsView* aView, nsPoint aPt)
-{
-  if (aView->GetVisibility() == nsViewVisibility_kHide)
-    // No need to look into descendants.
-    return nsnull;
-
-  for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
-    nsView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
-    if (r)
-      return r;
-  }
-
-  if (aView->GetFloating() && aView->HasWidget() &&
-      aView->GetDimensions().Contains(aPt))
-    return aView;
-    
-  return nsnull;
-}
-
-/*
- * This finds the first view containing the given point in a postorder
- * traversal of the view tree that contains the point, assuming that the
- * point is not in a floating view.  It assumes that only floating views
- * extend outside the bounds of their parents.
- *
- * This methods should only be called if FindFloatingViewContaining
- * returns null.
- */
-static nsView* FindViewContaining(nsView* aView, nsPoint aPt)
-{
-  if (!aView->GetDimensions().Contains(aPt) ||
-      aView->GetVisibility() == nsViewVisibility_kHide) {
-    return nsnull;
-  }
-
-  for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
-    nsView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
-    if (r)
-      return r;
-  }
-
-  return aView;
-}
-
-void
-nsViewManager::ProcessSynthMouseMoveEvent(PRBool aFromScroll)
-{
-  // allow new event to be posted while handling this one only if the
-  // source of the event is a scroll (to prevent infinite reflow loops)
-  if (aFromScroll)
-    mSynthMouseMoveEvent.Forget();
-
-  NS_ASSERTION(IsRootVM(), "Only the root view manager should be here");
-
-  if (mMouseLocation == nsPoint(NSCOORD_NONE, NSCOORD_NONE) || !mRootView ||
-      !mRootView->HasWidget()) {
-    mSynthMouseMoveEvent.Forget();
-    return;
-  }
-
-  // Hold a ref to ourselves so DispatchEvent won't destroy us (since
-  // we need to access members after we call DispatchEvent).
-  nsCOMPtr<nsIViewManager> kungFuDeathGrip(this);
-  
-#ifdef DEBUG_MOUSE_LOCATION
-  printf("[vm=%p]synthesizing mouse move to (%d,%d)\n",
-         this, mMouseLocation.x, mMouseLocation.y);
-#endif
-
-  PRInt32 APD = AppUnitsPerDevPixel();
-
-  // this will be mMouseLocation relative to the widget of |view|, the widget
-  // we will put in the event we dispatch, in viewAPD appunits
-  nsPoint refpoint(0, 0);
-  PRInt32 viewAPD;
-  // the VM of the view the point is in
-  nsViewManager *pointVM;
-
-  // This could be a bit slow (traverses entire view hierarchy)
-  // but it's OK to do it once per synthetic mouse event
-  nsView* view = FindFloatingViewContaining(mRootView, mMouseLocation);
-  if (!view) {
-    view = mRootView;
-    nsView *pointView = FindViewContaining(mRootView, mMouseLocation);
-    // pointView can be null in situations related to mouse capture
-    pointVM = (pointView ? pointView : view)->GetViewManager();
-    refpoint = mMouseLocation + mRootView->ViewToWidgetOffset();
-    viewAPD = APD;
-  } else {
-    pointVM = view->GetViewManager();
-    viewAPD = pointVM->AppUnitsPerDevPixel();
-    refpoint = mMouseLocation.ConvertAppUnits(APD, viewAPD);
-    refpoint -= view->GetOffsetTo(mRootView);
-    refpoint += view->ViewToWidgetOffset();
-  }
-  NS_ASSERTION(view->GetWidget(), "view should have a widget here");
-  nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, view->GetWidget(),
-                     nsMouseEvent::eSynthesized);
-  event.refPoint = refpoint.ToNearestPixels(viewAPD);
-  event.time = PR_IntervalNow();
-  // XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
-
-  nsCOMPtr<nsIViewObserver> observer = pointVM->GetViewObserver();
-  if (observer) {
-    observer->DispatchSynthMouseMove(&event, !aFromScroll);
-  }
-
-  if (!aFromScroll)
-    mSynthMouseMoveEvent.Forget();
-}
-
 void
 nsViewManager::InvalidateHierarchy()
 {
   if (mRootView) {
     if (!IsRootVM()) {
       NS_RELEASE(mRootViewManager);
     }
     nsView *parent = mRootView->GetParent();
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -77,25 +77,17 @@
    that those invalidates happen.
 
    To cope with this, invalidate event processing and view update batch
    handling should only happen on the root viewmanager.  This means the root
    view manager is the only thing keeping track of mUpdateCnt.  As a result,
    Composite() calls should also be forwarded to the root view manager.
 */
 
-class nsViewManagerEvent : public nsRunnable {
-public:
-  nsViewManagerEvent(class nsViewManager *vm) : mViewManager(vm) {
-    NS_ASSERTION(mViewManager, "null parameter");
-  }
-  void Revoke() { mViewManager = nsnull; }
-protected:
-  class nsViewManager *mViewManager;
-};
+class nsInvalidateEvent;
 
 class nsViewManager : public nsIViewManager {
 public:
   nsViewManager();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   NS_DECL_ISUPPORTS
@@ -136,35 +128,32 @@ public:
   NS_IMETHOD  ResizeView(nsIView *aView, const nsRect &aRect, PRBool aRepaintExposedAreaOnly = PR_FALSE);
 
   NS_IMETHOD  SetViewFloating(nsIView *aView, PRBool aFloating);
 
   NS_IMETHOD  SetViewVisibility(nsIView *aView, nsViewVisibility aVisible);
 
   NS_IMETHOD  SetViewZIndex(nsIView *aView, PRBool aAuto, PRInt32 aZIndex, PRBool aTopMost=PR_FALSE);
 
-  NS_IMETHOD  SetViewObserver(nsIViewObserver *aObserver);
-  NS_IMETHOD  GetViewObserver(nsIViewObserver *&aObserver);
+  virtual void SetViewObserver(nsIViewObserver *aObserver) { mObserver = aObserver; }
+  virtual nsIViewObserver* GetViewObserver() { return mObserver; }
 
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext);
 
   virtual nsIViewManager* BeginUpdateViewBatch(void);
   NS_IMETHOD  EndUpdateViewBatch(PRUint32 aUpdateFlags);
 
   NS_IMETHOD GetRootWidget(nsIWidget **aWidget);
   NS_IMETHOD ForceUpdate();
  
   NS_IMETHOD IsPainting(PRBool& aIsPainting);
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime);
   void ProcessInvalidateEvent();
   static PRUint32 gLastUserEventTime;
 
-  NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll);
-  void ProcessSynthMouseMoveEvent(PRBool aFromScroll);
-
   /* Update the cached RootViewManager pointer on this view manager. */
   void InvalidateHierarchy();
 
 protected:
   virtual ~nsViewManager();
 
 private:
 
@@ -258,45 +247,40 @@ public: // NOT in nsIViewManager, so pri
   PRBool IsRootVM() const { return this == RootViewManager(); }
 
   nsEventStatus HandleEvent(nsView* aView, nsGUIEvent* aEvent);
 
   nsresult CreateRegion(nsIRegion* *result);
 
   PRBool IsRefreshEnabled() { return RootViewManager()->mUpdateBatchCnt == 0; }
 
-  nsIViewObserver* GetViewObserver() { return mObserver; }
-
   // Call this when you need to let the viewmanager know that it now has
   // pending updates.
   void PostPendingUpdate() { RootViewManager()->mHasPendingUpdates = PR_TRUE; }
 
   PRInt32 AppUnitsPerDevPixel() const
   {
     return mContext->AppUnitsPerDevPixel();
   }
 
 private:
   nsRefPtr<nsDeviceContext> mContext;
   nsIViewObserver   *mObserver;
-  // relative to mRootView and set only on the root view manager
-  nsPoint           mMouseLocation;
 
   // The size for a resize that we delayed until the root view becomes
   // visible again.
   nsSize            mDelayedResize;
 
   nsCOMPtr<nsIFactory> mRegionFactory;
   nsView            *mRootView;
   // mRootViewManager is a strong ref unless it equals |this|.  It's
   // never null (if we have no ancestors, it will be |this|).
   nsViewManager     *mRootViewManager;
 
-  nsRevocableEventPtr<nsViewManagerEvent> mSynthMouseMoveEvent;
-  nsRevocableEventPtr<nsViewManagerEvent> mInvalidateEvent;
+  nsRevocableEventPtr<nsInvalidateEvent> mInvalidateEvent;
 
   // The following members should not be accessed directly except by
   // the root view manager.  Some have accessor functions to enforce
   // this, as noted.
   
   // Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(),
   // ClearUpdateCount() on the root viewmanager to access mUpdateCnt.
   PRInt32           mUpdateCnt;
@@ -315,9 +299,25 @@ private:
   static nsVoidArray       *gViewManagers;
 
   void PostInvalidateEvent();
 };
 
 //when the refresh happens, should it be double buffered?
 #define NS_VMREFRESH_DOUBLE_BUFFER      0x0001
 
+class nsInvalidateEvent : public nsRunnable {
+public:
+  nsInvalidateEvent(class nsViewManager *vm) : mViewManager(vm) {
+    NS_ASSERTION(mViewManager, "null parameter");
+  }
+  void Revoke() { mViewManager = nsnull; }
+
+  NS_IMETHOD Run() {
+    if (mViewManager)
+      mViewManager->ProcessInvalidateEvent();
+    return NS_OK;
+  }
+protected:
+  class nsViewManager *mViewManager;
+};
+
 #endif /* nsViewManager_h___ */