diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index b526ce31d31..2e2d650da64 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -1163,46 +1163,34 @@ void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceCo return; } - nsCOMPtr children(dont_AddRef(widget->GetChildren())); - if (!children) { - return; - } - - children->First(); - do { - nsCOMPtr child; - if (!NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) { - return; - } - - nsCOMPtr childWidget = do_QueryInterface(child); - if (childWidget) { - PRBool widgetVisible; - childWidget->IsVisible(widgetVisible); - if (widgetVisible) { - nsView* view = nsView::GetViewFor(childWidget); - if (view && view->GetVisibility() == nsViewVisibility_kShow - && !view->GetFloating()) { - nsRect bounds = view->GetBounds(); - if (bounds.width > 0 && bounds.height > 0) { - nsView* viewParent = view->GetParent(); + for (nsIWidget* childWidget = widget->GetFirstChild(); + childWidget; + childWidget = childWidget->GetNextSibling()) { + PRBool widgetVisible; + childWidget->IsVisible(widgetVisible); + if (widgetVisible) { + nsView* view = nsView::GetViewFor(childWidget); + if (view && view->GetVisibility() == nsViewVisibility_kShow + && !view->GetFloating()) { + nsRect bounds = view->GetBounds(); + if (bounds.width > 0 && bounds.height > 0) { + nsView* viewParent = view->GetParent(); - while (viewParent && viewParent != aRootView) { - viewParent->ConvertToParentCoords(&bounds.x, &bounds.y); - viewParent = viewParent->GetParent(); - } + while (viewParent && viewParent != aRootView) { + viewParent->ConvertToParentCoords(&bounds.x, &bounds.y); + viewParent = viewParent->GetParent(); + } - // maybe we couldn't get the view into the coordinate - // system of aRootView (maybe it's not a descendant - // view of aRootView?); if so, don't use it - if (viewParent) { - aRgn.Or(aRgn, bounds); - } + // maybe we couldn't get the view into the coordinate + // system of aRootView (maybe it's not a descendant + // view of aRootView?); if so, don't use it + if (viewParent) { + aRgn.Or(aRgn, bounds); } } } } - } while (NS_SUCCEEDED(children->Next())); + } } PRBool nsViewManager::BuildRenderingDisplayList(nsIView* aRootView, @@ -1628,32 +1616,24 @@ PRBool nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRect &aDamag } PRBool childCovers = PR_FALSE; - nsCOMPtr children(dont_AddRef(widget->GetChildren())); - if (children) { - children->First(); - do { - nsCOMPtr child; - if (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) { - nsCOMPtr childWidget = do_QueryInterface(child); - if (childWidget) { - nsView* view = nsView::GetViewFor(childWidget); - if (nsnull != view) { - nsRect damage = bounds; - nsView* vp = view; - while (vp != aWidgetView && nsnull != vp) { - vp->ConvertFromParentCoords(&damage.x, &damage.y); - vp = vp->GetParent(); - } + for (nsIWidget* childWidget = widget->GetFirstChild(); + childWidget; + childWidget = childWidget->GetNextSibling()) { + nsView* view = nsView::GetViewFor(childWidget); + if (nsnull != view) { + nsRect damage = bounds; + nsView* vp = view; + while (vp != aWidgetView && nsnull != vp) { + vp->ConvertFromParentCoords(&damage.x, &damage.y); + vp = vp->GetParent(); + } - if (nsnull != vp) { // vp == nsnull means it's in a different hierarchy so we ignore it - if (UpdateWidgetArea(view, damage, aIgnoreWidgetView)) { - childCovers = PR_TRUE; - } - } - } + if (nsnull != vp) { // vp == nsnull means it's in a different hierarchy so we ignore it + if (UpdateWidgetArea(view, damage, aIgnoreWidgetView)) { + childCovers = PR_TRUE; } } - } while (NS_SUCCEEDED(children->Next())); + } } if (!childCovers) { diff --git a/widget/public/nsIWidget.h b/widget/public/nsIWidget.h index 16f683b89ec..322ae28a7d3 100644 --- a/widget/public/nsIWidget.h +++ b/widget/public/nsIWidget.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -46,6 +46,7 @@ #include "prthread.h" #include "nsEvent.h" +#include "nsCOMPtr.h" // forward declarations class nsIAppShell; @@ -256,6 +257,12 @@ class nsIWidget : public nsISupports { NS_DEFINE_STATIC_IID_ACCESSOR(NS_IWIDGET_IID) + nsIWidget() + : mLastChild(nsnull) + , mPrevSibling(nsnull) + {} + + /** * Create and initialize a widget. * @@ -357,13 +364,48 @@ class nsIWidget : public nsISupports { virtual nsIWidget* GetParent(void) = 0; /** - * Return an nsEnumerator over the children of this widget. - * - * @return an enumerator over the list of children or nsnull if it does not - * have any children - * + * Return the first child of this widget. Will return null if + * there are no children. */ - virtual nsIEnumerator* GetChildren(void) = 0; + nsIWidget* GetFirstChild() const { + return mFirstChild; + } + + /** + * Return the last child of this widget. Will return null if + * there are no children. + */ + nsIWidget* GetLastChild() const { + return mLastChild; + } + + /** + * Return the next sibling of this widget + */ + nsIWidget* GetNextSibling() const { + return mNextSibling; + } + + /** + * Set the next sibling of this widget + */ + void SetNextSibling(nsIWidget* aSibling) { + mNextSibling = aSibling; + } + + /** + * Return the previous sibling of this widget + */ + nsIWidget* GetPrevSibling() const { + return mPrevSibling; + } + + /** + * Set the previous sibling of this widget + */ + void SetPrevSibling(nsIWidget* aSibling) { + mPrevSibling = aSibling; + } /** * Show or hide this widget @@ -975,6 +1017,18 @@ class nsIWidget : public nsISupports { */ NS_IMETHOD GetLastInputEventTime(PRUint32& aTime) = 0; + +protected: + // keep the list of children. We also keep track of our siblings. + // The ownership model is as follows: parent holds a strong ref to + // the first element of the list, and each element holds a strong + // ref to the next element in the list. The prevsibling and + // lastchild pointers are weak, which is fine as long as they are + // maintained properly. + nsCOMPtr mFirstChild; + nsIWidget* mLastChild; + nsCOMPtr mNextSibling; + nsIWidget* mPrevSibling; }; #endif // nsIWidget_h__ diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 0281ea299e4..6238173ad57 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -1543,24 +1543,15 @@ NS_IMETHODIMP nsChildView::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) } // Scroll the children (even if the widget is not visible) - nsCOMPtr children(getter_AddRefs(GetChildren())); - if ( children ) { - children->First(); - do { - nsCOMPtr child; - if (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) { - nsCOMPtr widget = do_QueryInterface(child); - - // We use resize rather than move since it gives us control - // over repainting. In the case of blitting, Quickdraw views - // draw their child widgets on the blit, so we can scroll - // like a bat out of hell by not wasting time invalidating - // the widgets, since it's completely unnecessary to do so. - nsRect bounds; - widget->GetBounds(bounds); - widget->Resize(bounds.x + aDx, bounds.y + aDy, bounds.width, bounds.height, PR_FALSE); - } - } while (NS_SUCCEEDED(children->Next())); + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + // We use resize rather than move since it gives us control + // over repainting. In the case of blitting, Quickdraw views + // draw their child widgets on the blit, so we can scroll + // like a bat out of hell by not wasting time invalidating + // the widgets, since it's completely unnecessary to do so. + nsRect bounds; + kid->GetBounds(bounds); + kid->Resize(bounds.x + aDx, bounds.y + aDy, bounds.width, bounds.height, PR_FALSE); } if (mVisible) diff --git a/widget/src/gtk/nsWidget.cpp b/widget/src/gtk/nsWidget.cpp index 91f3abbd9ad..69b23486f23 100644 --- a/widget/src/gtk/nsWidget.cpp +++ b/widget/src/gtk/nsWidget.cpp @@ -607,10 +607,8 @@ NS_IMETHODIMP nsWidget::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint) gtk_widget_set_usize(mWidget, aWidth, aHeight); ResetInternalVisibility(); - PRInt32 childCount = mChildren.Count(); - PRInt32 index; - for (index = 0; index < childCount; index++) { - NS_STATIC_CAST(nsWidget*, mChildren[index])->ResetInternalVisibility(); + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + NS_STATIC_CAST(nsWidget*, kid)->ResetInternalVisibility(); } return NS_OK; @@ -2243,19 +2241,8 @@ void nsWidget::ThemeChanged() { // Dispatch a NS_THEMECHANGED event for each of our children, recursively - nsCOMPtr children = dont_AddRef(GetChildren()); - if (children) { - nsCOMPtr isupp; - - while (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(isupp))) && isupp) { - - nsWidget* child = NS_REINTERPRET_CAST(nsWidget*, isupp.get()); - child->ThemeChanged(); - - if (NS_FAILED(children->Next())) { - break; - } - } + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + NS_STATIC_CAST(nsWidget*, kid)->ThemeChanged(); } DispatchStandardEvent(NS_THEMECHANGED); diff --git a/widget/src/gtk/nsWindow.cpp b/widget/src/gtk/nsWindow.cpp index 879a920d220..e469d9de524 100644 --- a/widget/src/gtk/nsWindow.cpp +++ b/widget/src/gtk/nsWindow.cpp @@ -894,26 +894,8 @@ NS_IMETHODIMP nsWindow::Update(void) // The view manager also expects us to force our // children to update too! - nsCOMPtr children; - - children = dont_AddRef(GetChildren()); - - if (children) { - nsCOMPtr isupp; - - nsCOMPtr child; - while (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(isupp))) && isupp) { - - child = do_QueryInterface(isupp); - - if (child) { - child->Update(); - } - - if (NS_FAILED(children->Next())) { - break; - } - } + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + kid->Update(); } // While I'd think you should NS_RELEASE(aPaintEvent.widget) here, @@ -2225,26 +2207,14 @@ NS_IMETHODIMP nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) } // Update bounds on our child windows - nsCOMPtr children = dont_AddRef(GetChildren()); - if (children) { - nsCOMPtr isupp; - nsCOMPtr child; - while (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(isupp)) && isupp)) { - child = do_QueryInterface(isupp); - - if (child) { - nsRect bounds; - child->GetBounds(bounds); - bounds.x += aDx; - bounds.y += aDy; - nsWidget* childWidget = NS_STATIC_CAST(nsWidget*, NS_STATIC_CAST(nsIWidget*, child.get())); - childWidget->SetBounds(bounds); - childWidget->ResetInternalVisibility(); - } - - if (NS_FAILED(children->Next())) - break; - } + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + nsRect bounds; + kid->GetBounds(bounds); + bounds.x += aDx; + bounds.y += aDy; + nsWidget* childWidget = NS_STATIC_CAST(nsWidget*, kid); + childWidget->SetBounds(bounds); + childWidget->ResetInternalVisibility(); } return NS_OK; @@ -2724,10 +2694,8 @@ NS_IMETHODIMP nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint) mBounds.height = aHeight; ResetInternalVisibility(); - PRInt32 childCount = mChildren.Count(); - PRInt32 index; - for (index = 0; index < childCount; index++) { - NS_STATIC_CAST(nsWidget*, mChildren[index])->ResetInternalVisibility(); + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + NS_STATIC_CAST(nsWidget*, kid)->ResetInternalVisibility(); } // code to keep the window from showing before it has been moved or resized diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp index 46785cc0657..14a1caa69e3 100644 --- a/widget/src/gtk2/nsWindow.cpp +++ b/widget/src/gtk2/nsWindow.cpp @@ -346,21 +346,13 @@ nsWindow::Destroy(void) NativeShow(PR_FALSE); - // walk the list of children and call destroy on them. - nsCOMPtr children = dont_AddRef(GetChildren()); - if (children) { - nsCOMPtr isupp; - nsCOMPtr child; - while (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(isupp)) - && isupp)) { - child = do_QueryInterface(isupp); - if (child) { - child->Destroy(); - } - - if (NS_FAILED(children->Next())) - break; - } + // walk the list of children and call destroy on them. Have to be + // careful, though -- calling destroy on a kid may actually remove + // it from our child list, losing its sibling links. + for (nsIWidget* kid = mFirstChild; kid; ) { + nsIWidget* next = kid->GetNextSibling(); + kid->Destroy(); + kid = next; } #ifdef USE_XIM @@ -835,25 +827,12 @@ nsWindow::Scroll(PRInt32 aDx, moz_drawingarea_scroll(mDrawingarea, aDx, aDy); // Update bounds on our child windows - nsCOMPtr children = dont_AddRef(GetChildren()); - if (children) { - nsCOMPtr isupp; - nsCOMPtr child; - while (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(isupp)) - && isupp)) { - child = do_QueryInterface(isupp); - if (child) { - nsRect bounds; - child->GetBounds(bounds); - bounds.x += aDx; - bounds.y += aDy; - NS_STATIC_CAST(nsBaseWidget*, - (nsIWidget*)child)->SetBounds(bounds); - } - - if (NS_FAILED(children->Next())) - break; - } + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + nsRect bounds; + kid->GetBounds(bounds); + bounds.x += aDx; + bounds.y += aDy; + NS_STATIC_CAST(nsBaseWidget*, kid)->SetBounds(bounds); } // Process all updates so that everything is drawn. diff --git a/widget/src/mac/nsChildWindow.cpp b/widget/src/mac/nsChildWindow.cpp index e4f1857774e..3a1c9e1ab7c 100644 --- a/widget/src/mac/nsChildWindow.cpp +++ b/widget/src/mac/nsChildWindow.cpp @@ -97,36 +97,33 @@ void nsChildWindow::CalcWindowRegions() // clip the siblings out of the window region and visRegion if (mClipSiblings && mParent && !mIsTopWidgetWindow) { // need to walk the siblings backwards, to get clipping right. - nsCOMPtr siblings = getter_AddRefs((nsIBidirectionalEnumerator*)mParent->GetChildren()); - if (siblings && NS_SUCCEEDED(siblings->Last())) { - StRegionFromPool siblingRgn; - if (siblingRgn == nsnull) - return; - do { - // when we reach ourself, stop clipping. - nsCOMPtr item; - if (NS_FAILED(siblings->CurrentItem(getter_AddRefs(item))) || - item == NS_STATIC_CAST(nsIWidget*, this)) - break; - - nsCOMPtr sibling(do_QueryInterface(item)); - PRBool visible; - sibling->IsVisible(visible); - if (visible) { // don't clip if not visible. - // get sibling's bounds in parent's coordinate system. - nsRect siblingRect; - sibling->GetBounds(siblingRect); - - // transform from parent's coordinate system to widget coordinates. - siblingRect.MoveBy(-mBounds.x, -mBounds.y); + nsIWidget* sibling = mParent->GetLastChild(); + NS_ASSERTION(sibling, "We're in the list, so it better have a last child!"); + StRegionFromPool siblingRgn; + if (siblingRgn == nsnull) + return; - Rect macRect; - ::SetRect(&macRect, siblingRect.x, siblingRect.y, siblingRect.XMost(), siblingRect.YMost()); - ::RectRgn(siblingRgn, &macRect); - ::DiffRgn(mWindowRegion, siblingRgn, mWindowRegion); - ::DiffRgn(mVisRegion, siblingRgn, mVisRegion); - } - } while (NS_SUCCEEDED(siblings->Prev())); - } + do { + if (sibling == NS_STATIC_CAST(nsIWidget*, this)) + break; + + PRBool visible; + sibling->IsVisible(visible); + if (visible) { // don't clip if not visible. + // get sibling's bounds in parent's coordinate system. + nsRect siblingRect; + sibling->GetBounds(siblingRect); + + // transform from parent's coordinate system to widget coordinates. + siblingRect.MoveBy(-mBounds.x, -mBounds.y); + + Rect macRect; + ::SetRect(&macRect, siblingRect.x, siblingRect.y, siblingRect.XMost(), siblingRect.YMost()); + ::RectRgn(siblingRgn, &macRect); + ::DiffRgn(mWindowRegion, siblingRgn, mWindowRegion); + ::DiffRgn(mVisRegion, siblingRgn, mVisRegion); + } + sibling = sibling->GetPrevSibling(); + } while (sibling); } } diff --git a/widget/src/mac/nsWindow.cpp b/widget/src/mac/nsWindow.cpp index f5df818e91b..6e944da772a 100644 --- a/widget/src/mac/nsWindow.cpp +++ b/widget/src/mac/nsWindow.cpp @@ -298,21 +298,9 @@ nsWindow::nsWindow() : nsBaseWidget() , nsDeleteObserved(this), nsIKBStateContro nsWindow::~nsWindow() { // notify the children that we're gone - nsCOMPtr children ( getter_AddRefs(GetChildren()) ); - if (children) - { - children->First(); - do - { - nsISupports* child; - if (NS_SUCCEEDED(children->CurrentItem(&child))) - { - nsWindow* childWindow = static_cast(static_cast(child)); - NS_RELEASE(child); - - childWindow->mParent = nsnull; - } - } while (NS_SUCCEEDED(children->Next())); + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid); + childWindow->mParent = nsnull; } mDestructorCalled = PR_TRUE; @@ -1737,36 +1725,27 @@ void nsWindow::UpdateWidget(nsRect& aRect, nsIRenderingContext* aContext) // and it does for the most part. However; certain cases, such as overlapping // areas that are handled by different view managers, don't properly clip siblings. #ifdef FRONT_TO_BACK -# define FIRST_CHILD(children) (children->Last()) -# define NEXT_CHILD(children) (children->Prev()) +# define FIRST_CHILD() (mFirstChild) +# define NEXT_CHILD(child) (child->GetNextSibling()) #else -# define FIRST_CHILD(children) (children->First()) -# define NEXT_CHILD(children) (children->Next()) +# define FIRST_CHILD() (mLastChild) +# define NEXT_CHILD(child) (child->GetPrevSibling()) #endif // recursively draw the children - nsCOMPtr children(getter_AddRefs((nsIBidirectionalEnumerator*)GetChildren())); - if (children) { - FIRST_CHILD(children); - do { - nsISupports* child; - if (NS_SUCCEEDED(children->CurrentItem(&child))) { - nsWindow* childWindow = static_cast(static_cast(child)); + for (nsIWidget* kid = FIRST_CHILD(); kid; kid = NEXT_CHILD(kid)) { + nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid); - nsRect childBounds; - childWindow->GetBounds(childBounds); + nsRect childBounds; + childWindow->GetBounds(childBounds); - // redraw only the intersection of the child rect and the update rect - nsRect intersection; - if (intersection.IntersectRect(aRect, childBounds)) - { - intersection.MoveBy(-childBounds.x, -childBounds.y); - childWindow->UpdateWidget(intersection, aContext); - } - - NS_RELEASE(child); - } - } while (NS_SUCCEEDED(NEXT_CHILD(children))); + // redraw only the intersection of the child rect and the update rect + nsRect intersection; + if (intersection.IntersectRect(aRect, childBounds)) + { + intersection.MoveBy(-childBounds.x, -childBounds.y); + childWindow->UpdateWidget(intersection, aContext); + } } #undef FIRST_CHILD @@ -1956,25 +1935,14 @@ NS_IMETHODIMP nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) scrollChildren: //-------- // Scroll the children - nsCOMPtr children ( getter_AddRefs(GetChildren()) ); - if (children) - { - children->First(); - do - { - nsISupports* child; - if (NS_SUCCEEDED(children->CurrentItem(&child))) - { - nsWindow* childWindow = static_cast(static_cast(child)); - NS_RELEASE(child); + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid); - nsRect bounds; - childWindow->GetBounds(bounds); - bounds.x += aDx; - bounds.y += aDy; - childWindow->SetBounds(bounds); - } - } while (NS_SUCCEEDED(children->Next())); + nsRect bounds; + childWindow->GetBounds(bounds); + bounds.x += aDx; + bounds.y += aDy; + childWindow->SetBounds(bounds); } // recalculate the window regions @@ -2214,33 +2182,29 @@ void nsWindow::CalcWindowRegions() ::CopyRgn(mWindowRegion, mVisRegion); // clip the children out of the visRegion - nsCOMPtr children ( getter_AddRefs(GetChildren()) ); - if (children) + if (mFirstChild) { StRegionFromPool childRgn; if (childRgn != nsnull) { - children->First(); + nsIWidget* child = mFirstChild; do { - nsISupports* child; - if (NS_SUCCEEDED(children->CurrentItem(&child))) - { - nsWindow* childWindow = static_cast(static_cast(child)); - NS_RELEASE(child); + nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, child); - PRBool visible; - childWindow->IsVisible(visible); - if (visible) { - nsRect childRect; - childWindow->GetBounds(childRect); + PRBool visible; + childWindow->IsVisible(visible); + if (visible) { + nsRect childRect; + childWindow->GetBounds(childRect); - Rect macRect; - ::SetRect(&macRect, childRect.x, childRect.y, childRect.XMost(), childRect.YMost()); - ::RectRgn(childRgn, &macRect); - ::DiffRgn(mVisRegion, childRgn, mVisRegion); - } + Rect macRect; + ::SetRect(&macRect, childRect.x, childRect.y, childRect.XMost(), childRect.YMost()); + ::RectRgn(childRgn, &macRect); + ::DiffRgn(mVisRegion, childRgn, mVisRegion); } - } while (NS_SUCCEEDED(children->Next())); + + child = child->GetNextSibling(); + } while (child); } } } @@ -2342,29 +2306,16 @@ nsWindow* nsWindow::FindWidgetHit(Point aThePoint) nsWindow* widgetHit = this; - nsCOMPtr normalEnum ( getter_AddRefs(GetChildren()) ); - nsCOMPtr children ( do_QueryInterface(normalEnum) ); - if (children) - { - // traverse through all the nsWindows to find out who got hit, lowest level of course - children->Last(); - do + // traverse through all the nsWindows to find out who got hit, lowest level of course + for (nsIWidget* kid = mLastChild; kid; kid = kid->GetPrevSibling()) { + nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid); + + nsWindow* deeperHit = childWindow->FindWidgetHit(aThePoint); + if (deeperHit) { - nsISupports* child; - if (NS_SUCCEEDED(children->CurrentItem(&child))) - { - nsWindow* childWindow = static_cast(static_cast(child)); - NS_RELEASE(child); - - nsWindow* deeperHit = childWindow->FindWidgetHit(aThePoint); - if (deeperHit) - { - widgetHit = deeperHit; - break; - } - } + widgetHit = deeperHit; + break; } - while (NS_SUCCEEDED(children->Prev())); } return widgetHit; diff --git a/widget/src/xlib/nsWindow.cpp b/widget/src/xlib/nsWindow.cpp index 3f6da006e82..325fa89a3e7 100644 --- a/widget/src/xlib/nsWindow.cpp +++ b/widget/src/xlib/nsWindow.cpp @@ -605,26 +605,8 @@ NS_IMETHODIMP nsWindow::Update(void) // The view manager also expects us to force our // children to update too! - nsCOMPtr children; - - children = dont_AddRef(GetChildren()); - - if (children) { - nsCOMPtr isupp; - - nsCOMPtr child; - while (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(isupp))) && isupp) { - - child = do_QueryInterface(isupp); - - if (child) { - child->Update(); - } - - if (NS_FAILED(children->Next())) { - break; - } - } + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + kid->Update(); } // While I'd think you should NS_RELEASE(aPaintEvent.widget) here, @@ -695,25 +677,13 @@ NS_IMETHODIMP nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) //-------- // Scroll the children - nsCOMPtr children ( getter_AddRefs(GetChildren()) ); - if (children) - { - children->First(); - do - { - nsISupports* child; - if (NS_SUCCEEDED(children->CurrentItem(&child))) - { - nsWindow *childWindow = NS_STATIC_CAST(nsWindow*, NS_STATIC_CAST(nsIWidget*, child)); - NS_RELEASE(child); - - nsRect bounds; - childWindow->GetRequestedBounds(bounds); - childWindow->Move(bounds.x + aDx, bounds.y + aDy); - Invalidate(bounds, PR_TRUE); - } - } while (NS_SUCCEEDED(children->Next())); - } + for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { + childWindow = NS_STATIC_CAST(nsWindow*, kid); + nsRect bounds; + childWindow->GetRequestedBounds(bounds); + childWindow->Move(bounds.x + aDx, bounds.y + aDy); + Invalidate(bounds, PR_TRUE); + } // If we are obscurred by another window we have to update those areas // which were not copied with the XCopyArea function. diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index ec6ac171a55..5ea0cd5f0f2 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -62,9 +62,6 @@ static PRInt32 gNumWidgets; // nsBaseWidget NS_IMPL_ISUPPORTS1(nsBaseWidget, nsIWidget) -// nsBaseWidget::Enumerator -NS_IMPL_ISUPPORTS2(nsBaseWidget::Enumerator, nsIBidirectionalEnumerator, nsIEnumerator) - //------------------------------------------------------------------------- // @@ -241,6 +238,9 @@ NS_IMETHODIMP nsBaseWidget::SetClientData(void* aClientData) //------------------------------------------------------------------------- NS_METHOD nsBaseWidget::Destroy() { + // Just in case our parent is the only ref to us + nsCOMPtr kungFuDeathGrip(this); + // disconnect from the parent nsIWidget *parent = GetParent(); if (parent) { @@ -277,23 +277,6 @@ nsIWidget* nsBaseWidget::GetParent(void) return nsnull; } -//------------------------------------------------------------------------- -// -// Get this nsBaseWidget's list of children -// -//------------------------------------------------------------------------- -nsIEnumerator* nsBaseWidget::GetChildren() -{ - nsIEnumerator* children = nsnull; - - if (mChildren.Count()) { - children = new Enumerator(*this); - NS_IF_ADDREF(children); - } - return children; -} - - //------------------------------------------------------------------------- // // Add a child to the list of children @@ -301,7 +284,19 @@ nsIEnumerator* nsBaseWidget::GetChildren() //------------------------------------------------------------------------- void nsBaseWidget::AddChild(nsIWidget* aChild) { - mChildren.AppendObject(aChild); + NS_PRECONDITION(!aChild->GetNextSibling() && !aChild->GetPrevSibling(), + "aChild not properly removed from its old child list"); + + if (!mFirstChild) { + mFirstChild = mLastChild = aChild; + } else { + // append to the list + NS_ASSERTION(mLastChild, "Bogus state"); + NS_ASSERTION(!mLastChild->GetNextSibling(), "Bogus state"); + mLastChild->SetNextSibling(aChild); + aChild->SetPrevSibling(mLastChild); + mLastChild = aChild; + } } @@ -312,7 +307,29 @@ void nsBaseWidget::AddChild(nsIWidget* aChild) //------------------------------------------------------------------------- void nsBaseWidget::RemoveChild(nsIWidget* aChild) { - mChildren.RemoveObject(aChild); + NS_ASSERTION(aChild->GetParent() == NS_STATIC_CAST(nsIWidget*, this), + "Not one of our kids!"); + + if (mLastChild == aChild) { + mLastChild = mLastChild->GetPrevSibling(); + } + if (mFirstChild == aChild) { + mFirstChild = mFirstChild->GetNextSibling(); + } + + // Now remove from the list. Make sure that we pass ownership of the tail + // of the list correctly before we have aChild let go of it. + nsIWidget* prev = aChild->GetPrevSibling(); + nsIWidget* next = aChild->GetNextSibling(); + if (prev) { + prev->SetNextSibling(next); + } + if (next) { + next->SetPrevSibling(prev); + } + + aChild->SetNextSibling(nsnull); + aChild->SetPrevSibling(nsnull); } @@ -328,26 +345,36 @@ NS_IMETHODIMP nsBaseWidget::SetZIndex(PRInt32 aZIndex) // reorder this child in its parent's list. nsBaseWidget* parent = NS_STATIC_CAST(nsBaseWidget*, GetParent()); if (parent) { - parent->mChildren.RemoveObject(this); - PRInt32 childCount = parent->mChildren.Count(); - PRInt32 index; - // XXXbz would a binary search for the right insertion point be - // better? How long does this list get? - for (index = 0; index < childCount; index++) { - nsIWidget* childWidget = parent->mChildren[index]; + parent->RemoveChild(this); + // Scope sib outside the for loop so we can check it afterward + nsIWidget* sib = parent->GetFirstChild(); + for ( ; sib; sib = sib->GetNextSibling()) { PRInt32 childZIndex; - if (NS_SUCCEEDED(childWidget->GetZIndex(&childZIndex))) { + if (NS_SUCCEEDED(sib->GetZIndex(&childZIndex))) { if (aZIndex < childZIndex) { - parent->mChildren.InsertObjectAt(this, index); - PlaceBehind(eZPlacementBelow, childWidget, PR_FALSE); + // Insert ourselves before sib + nsIWidget* prev = sib->GetPrevSibling(); + mNextSibling = sib; + mPrevSibling = prev; + sib->SetPrevSibling(this); + if (prev) { + prev->SetNextSibling(this); + } else { + NS_ASSERTION(sib == parent->mFirstChild, "Broken child list"); + // We've taken ownership of sib, so it's safe to have parent let + // go of it + parent->mFirstChild = this; + } + PlaceBehind(eZPlacementBelow, sib, PR_FALSE); break; } } } // were we added to the list? - if (index == childCount) { - parent->mChildren.AppendObject(this); + if (!sib) { + parent->AddChild(this); } + NS_RELEASE(parent); } return NS_OK; @@ -1275,131 +1302,3 @@ nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut, #endif // DEBUG - - - - - - - - - - - - - - - - - - - - - -//------------------------------------------------------------------------- -// -// Constructor -// -//------------------------------------------------------------------------- - -nsBaseWidget::Enumerator::Enumerator(nsBaseWidget & inParent) - : mCurrentPosition(0), mParent(inParent) -{ -} - - -//------------------------------------------------------------------------- -// -// Destructor -// -//------------------------------------------------------------------------- -nsBaseWidget::Enumerator::~Enumerator() -{ -} - - -//enumerator interfaces -NS_IMETHODIMP -nsBaseWidget::Enumerator::Next() -{ - if (mCurrentPosition < mParent.mChildren.Count() - 1 ) - mCurrentPosition ++; - else - return NS_ERROR_FAILURE; - return NS_OK; -} - - - -NS_IMETHODIMP -nsBaseWidget::Enumerator::Prev() -{ - if (mCurrentPosition > 0 ) - mCurrentPosition --; - else - return NS_ERROR_FAILURE; - return NS_OK; -} - - - -NS_IMETHODIMP -nsBaseWidget::Enumerator::CurrentItem(nsISupports **aItem) -{ - if (!aItem) - return NS_ERROR_NULL_POINTER; - - if ( mCurrentPosition < mParent.mChildren.Count() ) - NS_IF_ADDREF(*aItem = mParent.mChildren[mCurrentPosition]); - else - return NS_ERROR_FAILURE; - - return NS_OK; -} - - - -NS_IMETHODIMP -nsBaseWidget::Enumerator::First() -{ - if ( mParent.mChildren.Count() ) { - mCurrentPosition = 0; - return NS_OK; - } - else - return NS_ERROR_FAILURE; - - return NS_OK; -} - - - -NS_IMETHODIMP -nsBaseWidget::Enumerator::Last() -{ - PRInt32 itemCount = mParent.mChildren.Count(); - if ( itemCount ) { - mCurrentPosition = itemCount - 1; - return NS_OK; - } - else - return NS_ERROR_FAILURE; - - return NS_OK; -} - - - -NS_IMETHODIMP -nsBaseWidget::Enumerator::IsDone() -{ - PRInt32 itemCount = mParent.mChildren.Count(); - - if ((mCurrentPosition == itemCount-1) || (itemCount == 0) ){ //empty lists always return done - return NS_OK; - } - else { - return NS_ENUMERATOR_FALSE; - } - return NS_OK; -} diff --git a/widget/src/xpwidgets/nsBaseWidget.h b/widget/src/xpwidgets/nsBaseWidget.h index d604b3b549a..e244bb1dc5b 100644 --- a/widget/src/xpwidgets/nsBaseWidget.h +++ b/widget/src/xpwidgets/nsBaseWidget.h @@ -39,7 +39,6 @@ #include "nsRect.h" #include "nsIWidget.h" -#include "nsIEnumerator.h" #include "nsIMouseListener.h" #include "nsIEventListener.h" #include "nsIMenuListener.h" @@ -47,7 +46,6 @@ #include "nsIAppShell.h" #include "nsString.h" #include "nsVoidArray.h" -#include "nsCOMArray.h" #include "nsCOMPtr.h" #include "nsGUIEvent.h" @@ -80,7 +78,6 @@ public: NS_IMETHOD Destroy(); NS_IMETHOD SetParent(nsIWidget* aNewParent); virtual nsIWidget* GetParent(void); - virtual nsIEnumerator* GetChildren(); virtual void AddChild(nsIWidget* aChild); virtual void RemoveChild(nsIWidget* aChild); @@ -175,26 +172,7 @@ protected: nsRect* mOriginalBounds; PRInt32 mZIndex; nsSizeMode mSizeMode; - - // keep the list of children - nsCOMArray mChildren; - class Enumerator : public nsIBidirectionalEnumerator { - public: - NS_DECL_ISUPPORTS - - Enumerator(nsBaseWidget & inParent); - virtual ~Enumerator(); - - NS_DECL_NSIENUMERATOR - NS_DECL_NSIBIDIRECTIONALENUMERATOR - - private: - PRInt32 mCurrentPosition; - nsBaseWidget& mParent; - }; - friend class Enumerator; - // Enumeration of the methods which are accessable on the "main GUI thread" // via the CallMethod(...) mechanism... // see nsSwitchToUIThread