From f958ca676d4702bf9928abdcf4676aae1c874a61 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Fri, 29 Oct 2004 20:47:25 +0000 Subject: [PATCH] Push view update batching up to the root view manager. Make all associated members only be accessed by the root view manager. Document the invalidation setup a bit. Bug 244290, r+sr=roc --- view/public/nsIViewManager.h | 12 +++ view/src/nsView.cpp | 1 + view/src/nsViewManager.cpp | 193 ++++++++++++++++++++++------------- view/src/nsViewManager.h | 101 ++++++++++++++++-- widget/src/gtk/nsWindow.cpp | 7 -- widget/src/xlib/nsWindow.cpp | 7 -- 6 files changed, 229 insertions(+), 92 deletions(-) diff --git a/view/public/nsIViewManager.h b/view/public/nsIViewManager.h index 1666ea1c299..25ffd221150 100644 --- a/view/public/nsIViewManager.h +++ b/view/public/nsIViewManager.h @@ -112,6 +112,11 @@ public: /** * Called to force a redrawing of any dirty areas. */ + // XXXbz why is this exposed? Shouldn't update view batches handle this? + // It's not like Composite() does what's expected inside a view update batch + // anyway, since dirty areas may not have been invalidated on the widget yet + // and widget changes may not have been propagated yet. Maybe this should + // call FlushPendingInvalidates()? NS_IMETHOD Composite(void) = 0; /** @@ -348,6 +353,9 @@ public: * prevent the view manager from refreshing. * @return error status */ + // XXXbz callers of this function don't seem to realize that it disables + // refresh for the entire view manager hierarchy.... Maybe it shouldn't do + // that? NS_IMETHOD DisableRefresh(void) = 0; /** @@ -409,6 +417,7 @@ public: /** * Display the specified view. Used when printing. */ + //XXXbz how is this different from UpdateView(NS_VMREFRESH_IMMEDIATE)? NS_IMETHOD Display(nsIView *aView, nscoord aX, nscoord aY, const nsRect& aClipRect) = 0; /** @@ -437,6 +446,9 @@ public: * Callers should use UpdateView(view, NS_VMREFRESH_IMMEDIATE) in most cases instead * @result error status */ + // XXXbz Callers seem to be confused about this one... and it doesn't play + // right with view update batching at all (will miss updates). Maybe this + // should call FlushPendingInvalidates()? NS_IMETHOD ForceUpdate() = 0; /** diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index 9d27a423cc7..b95b49ee46d 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -181,6 +181,7 @@ nsView::nsView() mOpacity = 1.0f; mViewManager = nsnull; mChildRemoved = PR_FALSE; + mDirtyRegion = nsnull; } void nsView::DropMouseGrabbing() { diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 1e51e4d092b..991082034a2 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -433,6 +433,8 @@ static PRBool IsViewVisible(nsView *aView) void nsViewManager::PostInvalidateEvent() { + NS_ASSERTION(IsRootVM(), "Caller screwed up"); + nsCOMPtr eventQueue; mEventQueueService->GetSpecialEventQueue( nsIEventQueueService::UI_THREAD_EVENT_QUEUE, getter_AddRefs(eventQueue)); @@ -491,11 +493,14 @@ nsViewManager::~nsViewManager() mRootView = nsnull; } - nsCOMPtr eventQueue; - mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE, - getter_AddRefs(eventQueue)); - NS_ASSERTION(nsnull != eventQueue, "Event queue is null"); - eventQueue->RevokeEvents(this); + if (IsRootVM()) { + nsCOMPtr eventQueue; + mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE, + getter_AddRefs(eventQueue)); + NS_ASSERTION(nsnull != eventQueue, "Event queue is null"); + eventQueue->RevokeEvents(this); + } + mInvalidateEventQueue = nsnull; mSynthMouseMoveEventQueue = nsnull; @@ -615,9 +620,15 @@ NS_IMETHODIMP nsViewManager::SetRootView(nsIView *aView) nsView* parent = mRootView->GetParent(); if (parent) { parent->InsertChild(mRootView, nsnull); + mRootViewManager = parent->GetViewManager()->RootViewManager(); + } else { + mRootViewManager = this; } mRootView->SetZIndex(PR_FALSE, 0, PR_FALSE); + } else { + // XXXbz not really needed, probably + mRootViewManager = this; } return NS_OK; @@ -727,7 +738,7 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, { NS_ASSERTION(aRegion != nsnull, "Null aRegion"); - if (PR_FALSE == mRefreshEnabled) + if (! IsRefreshEnabled()) return; nsRect viewRect; @@ -760,12 +771,12 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, MOZ_TIMER_START(mWatch); #endif - NS_ASSERTION(!mPainting, "recursive painting not permitted"); - if (mPainting) { - mRecursiveRefreshPending = PR_TRUE; + NS_ASSERTION(!IsPainting(), "recursive painting not permitted"); + if (IsPainting()) { + RootViewManager()->mRecursiveRefreshPending = PR_TRUE; return; } - mPainting = PR_TRUE; + SetPainting(PR_TRUE); // force double buffering in general aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; @@ -795,7 +806,7 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, //couldn't get rendering context. this is ok at init time atleast if (nsnull == localcx) { - mPainting = PR_FALSE; + SetPainting(PR_FALSE); return; } } else { @@ -914,7 +925,7 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, localcx->Translate(viewRect.x, viewRect.y); } - mPainting = PR_FALSE; + SetPainting(PR_FALSE); // notify the listeners. if (nsnull != mCompositeListeners) { @@ -929,9 +940,9 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, } } - if (mRecursiveRefreshPending) { + if (RootViewManager()->mRecursiveRefreshPending) { UpdateAllViews(aUpdateFlags); - mRecursiveRefreshPending = PR_FALSE; + RootViewManager()->mRecursiveRefreshPending = PR_FALSE; } localcx->ReleaseBackbuffer(); @@ -1544,6 +1555,8 @@ nsViewManager::CreateBlendingBuffers(nsIRenderingContext *aRC, void nsViewManager::ProcessPendingUpdates(nsView* aView) { + NS_ASSERTION(IsRootVM(), "Updates will be missed"); + // Protect against a null-view. if (!aView) { return; @@ -1563,18 +1576,20 @@ void nsViewManager::ProcessPendingUpdates(nsView* aView) // process pending updates in child view. for (nsView* childView = aView->GetFirstChild(); childView; childView = childView->GetNextSibling()) { - if (childView->GetViewManager() == this) { - ProcessPendingUpdates(childView); - } + ProcessPendingUpdates(childView); } } NS_IMETHODIMP nsViewManager::Composite() { - if (mUpdateCnt > 0) + if (!IsRootVM()) { + return RootViewManager()->Composite(); + } + + if (UpdateCount() > 0) { ForceUpdate(); - mUpdateCnt = 0; + ClearUpdateCount(); } return NS_OK; @@ -1611,12 +1626,7 @@ nsViewManager::UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY) return; } - nsView* realRoot = mRootView; - while (realRoot->GetParent()) { - realRoot = realRoot->GetParent(); - } - - UpdateWidgetArea(realRoot, damageRect, view); + UpdateWidgetArea(RootViewManager()->GetRootView(), damageRect, view); Composite(); } @@ -1688,12 +1698,13 @@ PRBool nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRect &aDamag if (!childCovers) { nsViewManager* vm = aWidgetView->GetViewManager(); - ++vm->mUpdateCnt; + nsViewManager* rootVM = RootViewManager(); + rootVM->IncrementUpdateCount(); - if (!vm->mRefreshEnabled) { + if (!IsRefreshEnabled()) { // accumulate this rectangle in the view's dirty region, so we can process it later. vm->AddRectToDirtyRegion(aWidgetView, bounds); - vm->mHasPendingInvalidates = PR_TRUE; + rootVM->mHasPendingInvalidates = PR_TRUE; } else { ViewToWidget(aWidgetView, aWidgetView, bounds); widget->Invalidate(bounds, PR_FALSE); @@ -1743,19 +1754,18 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU UpdateWidgetArea(widgetParent, damagedRect, nsnull); } else { + // Propagate the update to the root widget of the root view manager, since + // iframes, for example, can overlap each other and be translucent. So we + // have to possibly invalidate our rect in each of the widgets we have + // lying about. damagedRect.MoveBy(ComputeViewOffset(view)); - nsView* realRoot = mRootView; - while (realRoot->GetParent()) { - realRoot = realRoot->GetParent(); - } - - UpdateWidgetArea(realRoot, damagedRect, nsnull); + UpdateWidgetArea(RootViewManager()->GetRootView(), damagedRect, nsnull); } - ++mUpdateCnt; + RootViewManager()->IncrementUpdateCount(); - if (!mRefreshEnabled) { + if (!IsRefreshEnabled()) { return NS_OK; } @@ -1769,6 +1779,10 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags) { + if (RootViewManager() != this) { + return RootViewManager()->UpdateAllViews(aUpdateFlags); + } + UpdateViews(mRootView, aUpdateFlags); return NS_OK; } @@ -1781,9 +1795,7 @@ void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags) // update all children as well. nsView* childView = aView->GetFirstChild(); while (nsnull != childView) { - if (childView->GetViewManager() == this) { - UpdateViews(childView, aUpdateFlags); - } + UpdateViews(childView, aUpdateFlags); childView = childView->GetNextSibling(); } } @@ -1854,7 +1866,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS break; // Refresh the view - if (mRefreshEnabled) { + if (IsRefreshEnabled()) { // If an ancestor widget was hidden and then shown, we could // have a delayed resize to handle. if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) && @@ -2239,8 +2251,9 @@ void nsViewManager::BuildDisplayList(nsView* aView, const nsRect& aRect, PRBool void nsViewManager::BuildEventTargetList(nsVoidArray &aTargets, nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured, PLArenaPool &aPool) { - NS_ASSERTION(!mPainting, "View manager cannot handle events during a paint"); - if (mPainting) { + NS_ASSERTION(!IsPainting(), + "View manager cannot handle events during a paint"); + if (IsPainting()) { return; } @@ -2363,9 +2376,8 @@ nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBo NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult) { - nsView* rootParent = mRootView ? mRootView->GetParent() : nsnull; - if (rootParent) { - return rootParent->GetViewManager()->GrabMouseEvents(aView, aResult); + if (!IsRootVM()) { + return RootViewManager()->GrabMouseEvents(aView, aResult); } // Along with nsView::SetVisibility, we enforce that the mouse grabber @@ -2395,20 +2407,6 @@ NS_IMETHODIMP nsViewManager::GrabKeyEvents(nsIView *aView, PRBool &aResult) return NS_OK; } -nsView* nsViewManager::GetMouseEventGrabber() const { - nsView* root = mRootView; - while (root && root->GetParent()) { - nsViewManager* viewManager = root->GetParent()->GetViewManager(); - if (!viewManager) - return nsnull; - root = viewManager->mRootView; - } - if (!root) - return nsnull; - nsViewManager* viewManager = root->GetViewManager(); - return viewManager ? viewManager->mMouseGrabber : nsnull; -} - NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView) { aView = GetMouseEventGrabber(); @@ -2827,8 +2825,9 @@ static PRBool IsAncestorOf(const nsView* aAncestor, const nsView* aView) */ PRBool nsViewManager::CanScrollWithBitBlt(nsView* aView) { - NS_ASSERTION(!mPainting, "View manager shouldn't be scrolling during a paint"); - if (mPainting) { + NS_ASSERTION(!IsPainting(), + "View manager shouldn't be scrolling during a paint"); + if (IsPainting()) { return PR_FALSE; // do the safe thing } @@ -2999,6 +2998,21 @@ NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility return NS_OK; } +void nsViewManager::UpdateWidgetsForView(nsView* aView) +{ + NS_PRECONDITION(aView, "Must have view!"); + + if (aView->HasWidget()) { + aView->GetWidget()->Update(); + } + + for (nsView* childView = aView->GetFirstChild(); + childView; + childView = childView->GetNextSibling()) { + UpdateWidgetsForView(childView); + } +} + PRBool nsViewManager::IsViewInserted(nsView *aView) { if (mRootView == aView) { @@ -3213,6 +3227,10 @@ void nsViewManager::AddRectToDirtyRegion(nsView* aView, const nsRect &aRect) con NS_IMETHODIMP nsViewManager::DisableRefresh(void) { + if (!IsRootVM()) { + return RootViewManager()->DisableRefresh(); + } + if (mUpdateBatchCnt > 0) return NS_OK; @@ -3222,6 +3240,10 @@ NS_IMETHODIMP nsViewManager::DisableRefresh(void) NS_IMETHODIMP nsViewManager::EnableRefresh(PRUint32 aUpdateFlags) { + if (!IsRootVM()) { + return RootViewManager()->EnableRefresh(aUpdateFlags); + } + if (mUpdateBatchCnt > 0) return NS_OK; @@ -3245,6 +3267,10 @@ NS_IMETHODIMP nsViewManager::EnableRefresh(PRUint32 aUpdateFlags) NS_IMETHODIMP nsViewManager::BeginUpdateViewBatch(void) { + if (!IsRootVM()) { + return RootViewManager()->BeginUpdateViewBatch(); + } + nsresult result = NS_OK; if (mUpdateBatchCnt == 0) { @@ -3260,6 +3286,10 @@ NS_IMETHODIMP nsViewManager::BeginUpdateViewBatch(void) NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags) { + if (!IsRootVM()) { + return RootViewManager()->EndUpdateViewBatch(aUpdateFlags); + } + nsresult result = NS_OK; --mUpdateBatchCnt; @@ -3305,19 +3335,19 @@ NS_IMETHODIMP nsViewManager::Display(nsIView* aView, nscoord aX, nscoord aY, con nsView *view = NS_STATIC_CAST(nsView*, aView); nsIRenderingContext *localcx = nsnull; - if (PR_FALSE == mRefreshEnabled) + if (! IsRefreshEnabled()) return NS_OK; - NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); + NS_ASSERTION(!IsPainting(), "recursive painting not permitted"); - mPainting = PR_TRUE; + SetPainting(PR_TRUE); mContext->CreateRenderingContext(localcx); //couldn't get rendering context. this is ok if at startup if (nsnull == localcx) { - mPainting = PR_FALSE; + SetPainting(PR_FALSE); return NS_ERROR_FAILURE; } @@ -3340,7 +3370,7 @@ NS_IMETHODIMP nsViewManager::Display(nsIView* aView, nscoord aX, nscoord aY, con NS_RELEASE(localcx); - mPainting = PR_FALSE; + SetPainting(PR_FALSE); return NS_OK; @@ -3373,9 +3403,12 @@ NS_IMETHODIMP nsViewManager::GetWidget(nsIWidget **aWidget) NS_IMETHODIMP nsViewManager::ForceUpdate() { - nsIWidget* widget = GetWidget(); - if (widget) - widget->Update(); + if (!IsRootVM()) { + return RootViewManager()->ForceUpdate(); + } + + // Walk the view tree looking for widgets, and call Update() on each one + UpdateWidgetsForView(mRootView); return NS_OK; } @@ -3881,11 +3914,24 @@ void nsViewManager::ShowDisplayList(const nsVoidArray* aDisplayList) nsPoint nsViewManager::ComputeViewOffset(const nsView *aView) { + NS_PRECONDITION(aView, "Null view in ComputeViewOffset?"); + nsPoint origin(0, 0); +#ifdef DEBUG + const nsView* rootView; + const nsView* origView = aView; +#endif + while (aView) { +#ifdef DEBUG + rootView = aView; +#endif origin += aView->GetPosition(); aView = aView->GetParent(); } + NS_ASSERTION(rootView == + origView->GetViewManager()->RootViewManager()->GetRootView(), + "Unexpected root view"); return origin; } @@ -3896,6 +3942,7 @@ PRBool nsViewManager::DoesViewHaveNativeWidget(nsView* aView) return PR_FALSE; } +/* static */ nsView* nsViewManager::GetWidgetView(nsView *aView) { while (aView) { @@ -4053,13 +4100,17 @@ nsViewManager::AllowDoubleBuffering(PRBool aDoubleBuffer) NS_IMETHODIMP nsViewManager::IsPainting(PRBool& aIsPainting) { - aIsPainting = mPainting; + aIsPainting = IsPainting(); return NS_OK; } NS_IMETHODIMP nsViewManager::FlushPendingInvalidates() { + if (!IsRootVM()) { + return RootViewManager()->FlushPendingInvalidates(); + } + if (mHasPendingInvalidates) { ProcessPendingUpdates(mRootView); mHasPendingInvalidates = PR_FALSE; @@ -4070,6 +4121,8 @@ nsViewManager::FlushPendingInvalidates() void nsViewManager::ProcessInvalidateEvent() { + NS_ASSERTION(IsRootVM(), + "Incorrectly targeted invalidate event"); FlushPendingInvalidates(); mInvalidateEventQueue = nsnull; } diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index bc6bbba285e..9166125f21f 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -92,6 +92,37 @@ class nsHashtable; fixed-position frames. */ +/** + Invalidation model: + + 1) Callers call into the view manager and ask it to update a view. + + 2) The view manager finds the "right" widget for the view, henceforth called + the root widget. + + 3) The view manager traverses descendants of the root widget and for each + one that needs invalidation either + + a) Calls Invalidate() on the widget (no batching) + or + b) Stores the rect to invalidate on the widget's view (batching) + + // XXXbz we want to change this a bit. See bug 243726 + + 4) When batching, the call to end the batch either processes the pending + Invalidate() calls on the widgets or posts an event to do so. + + It's important to note that widgets associated to views outside this view + manager can end up being invalidated during step 3. Therefore, the end of a + view update batch really needs to traverse the entire view tree, to ensure + 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 nsZPlaceholderView : public nsView { public: @@ -308,6 +339,12 @@ private: PRBool IsViewInserted(nsView *aView); + /** + * Function to recursively call Update() on all widgets belonging to + * a view or its kids. + */ + void UpdateWidgetsForView(nsView* aView); + /** * Returns the nearest parent view with an attached widget. Can be the * same view as passed-in. @@ -364,10 +401,47 @@ private: } } + // Safety helpers + void IncrementUpdateCount() { + NS_ASSERTION(IsRootVM(), + "IncrementUpdateCount called on non-root viewmanager"); + ++mUpdateCnt; + } + + void DecrementUpdateCount() { + NS_ASSERTION(IsRootVM(), + "DecrementUpdateCount called on non-root viewmanager"); + --mUpdateCnt; + } + + PRInt32 UpdateCount() const { + NS_ASSERTION(IsRootVM(), + "DecrementUpdateCount called on non-root viewmanager"); + return mUpdateCnt; + } + + void ClearUpdateCount() { + NS_ASSERTION(IsRootVM(), + "DecrementUpdateCount called on non-root viewmanager"); + mUpdateCnt = 0; + } + + PRBool IsPainting() const { + return RootViewManager()->mPainting; + } + + void SetPainting(PRBool aPainting) { + RootViewManager()->mPainting = aPainting; + } + public: // NOT in nsIViewManager, so private to the view module nsView* GetRootView() const { return mRootView; } - nsView* GetMouseEventGrabber() const; + nsView* GetMouseEventGrabber() const { + return RootViewManager()->mMouseGrabber; + } nsView* GetKeyEventGrabber() const { return mKeyGrabber; } + nsViewManager* RootViewManager() const { return mRootViewManager; } + PRBool IsRootVM() const { return this == RootViewManager(); } nsEventStatus HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured); @@ -389,18 +463,14 @@ public: // NOT in nsIViewManager, so private to the view module // not be in this view manager). static nsPoint ComputeViewOffset(const nsView *aView); - PRBool IsRefreshEnabled() { return mRefreshEnabled; } + PRBool IsRefreshEnabled() { return RootViewManager()->mRefreshEnabled; } private: nsIDeviceContext *mContext; float mTwipsToPixels; float mPixelsToTwips; nsIViewObserver *mObserver; - nsView *mMouseGrabber; nsView *mKeyGrabber; - PRInt32 mUpdateCnt; - PRInt32 mUpdateBatchCnt; - PRUint32 mUpdateBatchFlags; nsIScrollableView *mRootScrollable; nscolor mDefaultBackgroundColor; nsPoint mMouseLocation; // device units, relative to mRootView @@ -413,13 +483,28 @@ private: nsISupportsArray *mCompositeListeners; nsCOMPtr mRegionFactory; nsView *mRootView; + nsViewManager *mRootViewManager; nsCOMPtr mEventQueueService; - nsCOMPtr mInvalidateEventQueue; nsCOMPtr mSynthMouseMoveEventQueue; + PRPackedBool mAllowDoubleBuffering; + + // The following members should not be accessed directly except by + // the root view manager. Some have accessor functions to enforce + // this, as noted. + + // Use GrabMouseEvents() and GetMouseEventGrabber() to access mMouseGrabber. + nsView *mMouseGrabber; + // Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(), + // ClearUpdateCount() on the root viewmanager to access mUpdateCnt. + PRInt32 mUpdateCnt; + PRInt32 mUpdateBatchCnt; + PRUint32 mUpdateBatchFlags; + nsCOMPtr mInvalidateEventQueue; + // Use IsRefreshEnabled() to check the value of mRefreshEnabled. PRPackedBool mRefreshEnabled; + // Use IsPainting() and SetPainting() to access mPainting. PRPackedBool mPainting; PRPackedBool mRecursiveRefreshPending; - PRPackedBool mAllowDoubleBuffering; PRPackedBool mHasPendingInvalidates; //from here to public should be static and locked... MMP diff --git a/widget/src/gtk/nsWindow.cpp b/widget/src/gtk/nsWindow.cpp index b2578137601..cb28b8fd9cf 100644 --- a/widget/src/gtk/nsWindow.cpp +++ b/widget/src/gtk/nsWindow.cpp @@ -912,13 +912,6 @@ NS_IMETHODIMP nsWindow::Update(void) // g_print("nsWidget::Update(this=%p): avoided update of empty area\n", this); } - // The view manager also expects us to force our - // children to update too! - - for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { - kid->Update(); - } - // While I'd think you should NS_RELEASE(aPaintEvent.widget) here, // if you do, it is a NULL pointer. Not sure where it is getting // released. diff --git a/widget/src/xlib/nsWindow.cpp b/widget/src/xlib/nsWindow.cpp index f8576633d39..486055bee2a 100644 --- a/widget/src/xlib/nsWindow.cpp +++ b/widget/src/xlib/nsWindow.cpp @@ -602,13 +602,6 @@ NS_IMETHODIMP nsWindow::Update(void) } } - // The view manager also expects us to force our - // children to update too! - - for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { - kid->Update(); - } - // While I'd think you should NS_RELEASE(aPaintEvent.widget) here, // if you do, it is a NULL pointer. Not sure where it is getting // released.