Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / view / src / nsView.cpp
blob2a5715518599b824af94e85da7cb6ad65715e662
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsView.h"
39 #include "nsIWidget.h"
40 #include "nsViewManager.h"
41 #include "nsGUIEvent.h"
42 #include "nsIDeviceContext.h"
43 #include "nsIComponentManager.h"
44 #include "nsIScrollableView.h"
45 #include "nsGfxCIID.h"
46 #include "nsIRegion.h"
47 #include "nsIInterfaceRequestor.h"
49 //mmptemp
51 static nsEventStatus HandleEvent(nsGUIEvent *aEvent);
54 //#define SHOW_VIEW_BORDERS
55 //#define HIDE_ALL_WIDGETS
57 // {34297A07-A8FD-d811-87C6-000244212BCB}
58 #define VIEW_WRAPPER_IID \
59 { 0x34297a07, 0xa8fd, 0xd811, { 0x87, 0xc6, 0x0, 0x2, 0x44, 0x21, 0x2b, 0xcb } }
62 /**
63 * nsISupports-derived helper class that allows to store and get a view
65 class ViewWrapper : public nsIInterfaceRequestor
67 public:
68 NS_DECLARE_STATIC_IID_ACCESSOR(VIEW_WRAPPER_IID)
69 NS_DECL_ISUPPORTS
70 NS_DECL_NSIINTERFACEREQUESTOR
72 ViewWrapper(nsView* aView) : mView(aView) {}
74 nsView* GetView() { return mView; }
75 private:
76 nsView* mView;
79 NS_DEFINE_STATIC_IID_ACCESSOR(ViewWrapper, VIEW_WRAPPER_IID)
81 NS_IMPL_ADDREF(ViewWrapper)
82 NS_IMPL_RELEASE(ViewWrapper)
83 #ifndef DEBUG
84 NS_IMPL_QUERY_INTERFACE2(ViewWrapper, ViewWrapper, nsIInterfaceRequestor)
86 #else
87 NS_IMETHODIMP ViewWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr)
89 NS_ENSURE_ARG_POINTER(aInstancePtr);
91 NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsIView)) &&
92 !aIID.Equals(NS_GET_IID(nsIScrollableView)),
93 "Someone expects a viewwrapper to be a view!");
95 *aInstancePtr = nsnull;
97 if (aIID.Equals(NS_GET_IID(nsISupports))) {
98 *aInstancePtr = static_cast<nsISupports*>(this);
100 else if (aIID.Equals(NS_GET_IID(ViewWrapper))) {
101 *aInstancePtr = this;
103 else if (aIID.Equals(NS_GET_IID(nsIInterfaceRequestor))) {
104 *aInstancePtr = this;
108 if (*aInstancePtr) {
109 AddRef();
110 return NS_OK;
113 return NS_NOINTERFACE;
115 #endif
117 NS_IMETHODIMP ViewWrapper::GetInterface(REFNSIID aIID, void** aInstancePtr)
119 if (aIID.Equals(NS_GET_IID(nsIScrollableView))) {
120 *aInstancePtr = mView->ToScrollableView();
121 return NS_OK;
123 if (aIID.Equals(NS_GET_IID(nsIView))) {
124 *aInstancePtr = mView;
125 return NS_OK;
127 return QueryInterface(aIID, aInstancePtr);
131 * Given a widget, returns the stored ViewWrapper on it, or NULL if no
132 * ViewWrapper is there.
134 static ViewWrapper* GetWrapperFor(nsIWidget* aWidget)
136 // The widget's client data points back to the owning view
137 if (aWidget) {
138 void* clientData;
139 aWidget->GetClientData(clientData);
140 nsISupports* data = (nsISupports*)clientData;
142 if (data) {
143 ViewWrapper* wrapper;
144 CallQueryInterface(data, &wrapper);
145 // Give a weak reference to the caller. There will still be at least one
146 // reference left, since the wrapper was addrefed when set on the widget.
147 if (wrapper)
148 wrapper->Release();
149 return wrapper;
152 return nsnull;
156 // Main events handler
158 nsEventStatus HandleEvent(nsGUIEvent *aEvent)
160 //printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->widgetSupports,
161 // aEvent->message, aEvent->point.x, aEvent->point.y);
162 nsEventStatus result = nsEventStatus_eIgnore;
163 nsView *view = nsView::GetViewFor(aEvent->widget);
165 if (view)
167 view->GetViewManager()->DispatchEvent(aEvent, &result);
170 return result;
173 nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
175 MOZ_COUNT_CTOR(nsView);
177 mVis = aVisibility;
178 // Views should be transparent by default. Not being transparent is
179 // a promise that the view will paint all its pixels opaquely. Views
180 // should make this promise explicitly by calling
181 // SetViewContentTransparency.
182 mVFlags = 0;
183 mViewManager = aViewManager;
184 mDirtyRegion = nsnull;
185 mDeletionObserver = nsnull;
188 void nsView::DropMouseGrabbing() {
189 // check to see if we are grabbing events
190 if (mViewManager->GetMouseEventGrabber() == this) {
191 // we are grabbing events. Move the grab to the parent if we can.
192 PRBool boolResult; //not used
193 // if GetParent() returns null, then we release the grab, which is the best we can do
194 mViewManager->GrabMouseEvents(GetParent(), boolResult);
198 nsView::~nsView()
200 MOZ_COUNT_DTOR(nsView);
202 if (this == nsViewManager::GetViewFocusedBeforeSuppression()) {
203 #ifdef DEBUG_FOCUS_SUPPRESSION
204 if (GetViewManager()->IsFocusSuppressed()) {
205 printf("*** 0 INFO TODO [CPEARCE] destroying view focused before suppression, while suppressed\n");
207 #endif
208 nsViewManager::SetViewFocusedBeforeSuppression(nsnull);
210 if (this == nsViewManager::GetCurrentlyFocusedView()) {
211 #ifdef DEBUG_FOCUS_SUPPRESSION
212 if (GetViewManager()->IsFocusSuppressed()) {
213 printf("*** 0 INFO TODO [CPEARCE] destroying view currently focused, while suppressed\n");
215 #endif
216 nsViewManager::SetCurrentlyFocusedView(nsnull);
219 while (GetFirstChild())
221 nsView* child = GetFirstChild();
222 if (child->GetViewManager() == mViewManager) {
223 child->Destroy();
224 } else {
225 // just unhook it. Someone else will want to destroy this.
226 RemoveChild(child);
230 if (mViewManager)
232 DropMouseGrabbing();
234 nsView *rootView = mViewManager->GetRootView();
236 if (rootView)
238 // Root views can have parents!
239 if (mParent)
241 mViewManager->RemoveChild(this);
244 if (rootView == this)
246 // Inform the view manager that the root view has gone away...
247 mViewManager->SetRootView(nsnull);
250 else if (mParent)
252 mParent->RemoveChild(this);
255 mViewManager = nsnull;
257 else if (mParent)
259 mParent->RemoveChild(this);
262 // Destroy and release the widget
263 if (mWindow)
265 // Release memory for the view wrapper
266 ViewWrapper* wrapper = GetWrapperFor(mWindow);
267 NS_IF_RELEASE(wrapper);
269 mWindow->SetClientData(nsnull);
270 if (!(mVFlags & NS_VIEW_DISOWNS_WIDGET)) {
271 mWindow->Destroy();
273 NS_RELEASE(mWindow);
275 delete mDirtyRegion;
277 if (mDeletionObserver) {
278 mDeletionObserver->Clear();
282 nsresult nsView::QueryInterface(const nsIID& aIID, void** aInstancePtr)
284 if (nsnull == aInstancePtr) {
285 return NS_ERROR_NULL_POINTER;
288 NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)),
289 "Someone expects views to be ISupports-derived!");
291 *aInstancePtr = nsnull;
293 if (aIID.Equals(NS_GET_IID(nsIView))) {
294 *aInstancePtr = (void*)(nsIView*)this;
295 return NS_OK;
298 return NS_NOINTERFACE;
301 nsIView* nsIView::GetViewFor(nsIWidget* aWidget)
303 NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
305 ViewWrapper* wrapper = GetWrapperFor(aWidget);
306 if (wrapper)
307 return wrapper->GetView();
308 return nsnull;
311 void nsIView::Destroy()
313 delete this;
316 void nsView::SetPosition(nscoord aX, nscoord aY)
318 mDimBounds.x += aX - mPosX;
319 mDimBounds.y += aY - mPosY;
320 mPosX = aX;
321 mPosY = aY;
323 NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
324 "Don't try to move the root widget to something non-zero");
326 ResetWidgetBounds(PR_TRUE, PR_TRUE, PR_FALSE);
329 void nsView::SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY)
331 mDimBounds.x += aX - mPosX;
332 mDimBounds.y += aY - mPosY;
333 mPosX = aX;
334 mPosY = aY;
336 ResetWidgetBounds(PR_FALSE, PR_TRUE, PR_FALSE);
339 void nsView::ResetWidgetBounds(PRBool aRecurse, PRBool aMoveOnly,
340 PRBool aInvalidateChangedSize) {
341 if (mWindow) {
342 // If our view manager has refresh disabled, then do nothing; the view
343 // manager will set our position when refresh is reenabled. Just let it
344 // know that it has pending updates.
345 if (!mViewManager->IsRefreshEnabled()) {
346 mViewManager->PostPendingUpdate();
347 return;
350 DoResetWidgetBounds(aMoveOnly, aInvalidateChangedSize);
351 } else if (aRecurse) {
352 // reposition any widgets under this view
353 for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
354 v->ResetWidgetBounds(PR_TRUE, aMoveOnly, aInvalidateChangedSize);
359 nsRect nsView::CalcWidgetBounds(nsWindowType aType)
361 nsCOMPtr<nsIDeviceContext> dx;
362 mViewManager->GetDeviceContext(*getter_AddRefs(dx));
363 NS_ASSERTION(dx, "View manager can't be created without a device context");
364 PRInt32 p2a = dx->AppUnitsPerDevPixel();
366 nsRect viewBounds(mDimBounds);
368 if (GetParent()) {
369 // put offset into screen coordinates
370 nsPoint offset;
371 nsIWidget* parentWidget = GetParent()->GetNearestWidget(&offset);
372 viewBounds += offset;
374 if (parentWidget && aType == eWindowType_popup &&
375 mVis == nsViewVisibility_kShow) {
376 nsRect screenRect(0,0,1,1);
377 parentWidget->WidgetToScreen(screenRect, screenRect);
378 viewBounds += nsPoint(NSIntPixelsToAppUnits(screenRect.x, p2a),
379 NSIntPixelsToAppUnits(screenRect.y, p2a));
383 nsRect newBounds(viewBounds);
384 newBounds.ScaleRoundPreservingCentersInverse(p2a);
386 nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a),
387 NSIntPixelsToAppUnits(newBounds.y, p2a));
388 mViewToWidgetOffset = viewBounds.TopLeft() - roundedOffset;
390 return newBounds;
393 void nsView::DoResetWidgetBounds(PRBool aMoveOnly,
394 PRBool aInvalidateChangedSize) {
395 // The geometry of a root view's widget is controlled externally,
396 // NOT by sizing or positioning the view
397 if (mViewManager->GetRootView() == this) {
398 return;
401 nsRect curBounds;
402 mWindow->GetBounds(curBounds);
403 nsWindowType type;
404 mWindow->GetWindowType(type);
406 if (curBounds.IsEmpty() && mDimBounds.IsEmpty() && type == eWindowType_popup) {
407 // Don't manipulate empty popup widgets. For example there's no point
408 // moving hidden comboboxes around, or doing X server roundtrips
409 // to compute their true screen position. This could mean that WidgetToScreen
410 // operations on these widgets don't return up-to-date values, but popup
411 // positions aren't reliable anyway because of correction to be on or off-screen.
412 return;
415 NS_PRECONDITION(mWindow, "Why was this called??");
417 nsRect newBounds = CalcWidgetBounds(type);
419 PRBool changedPos = curBounds.TopLeft() != newBounds.TopLeft();
420 PRBool changedSize = curBounds.Size() != newBounds.Size();
422 if (changedPos) {
423 if (changedSize && !aMoveOnly) {
424 mWindow->Resize(newBounds.x, newBounds.y, newBounds.width, newBounds.height,
425 aInvalidateChangedSize);
426 } else {
427 mWindow->Move(newBounds.x, newBounds.y);
429 } else {
430 if (changedSize && !aMoveOnly) {
431 mWindow->Resize(newBounds.width, newBounds.height, aInvalidateChangedSize);
432 } // else do nothing!
436 void nsView::SetDimensions(const nsRect& aRect, PRBool aPaint, PRBool aResizeWidget)
438 nsRect dims = aRect;
439 dims.MoveBy(mPosX, mPosY);
441 // Don't use nsRect's operator== here, since it returns true when
442 // both rects are empty even if they have different widths and we
443 // have cases where that sort of thing matters to us.
444 if (mDimBounds.TopLeft() == dims.TopLeft() &&
445 mDimBounds.Size() == dims.Size()) {
446 return;
449 mDimBounds = dims;
451 if (aResizeWidget) {
452 ResetWidgetBounds(PR_FALSE, PR_FALSE, aPaint);
456 NS_IMETHODIMP nsView::SetVisibility(nsViewVisibility aVisibility)
459 mVis = aVisibility;
461 if (aVisibility == nsViewVisibility_kHide)
463 DropMouseGrabbing();
466 if (nsnull != mWindow)
468 #ifndef HIDE_ALL_WIDGETS
469 if (mVis == nsViewVisibility_kShow)
471 DoResetWidgetBounds(PR_FALSE, PR_TRUE);
472 mWindow->Show(PR_TRUE);
474 else
475 #endif
476 mWindow->Show(PR_FALSE);
479 return NS_OK;
482 NS_IMETHODIMP nsView::SetFloating(PRBool aFloatingView)
484 if (aFloatingView)
485 mVFlags |= NS_VIEW_FLAG_FLOATING;
486 else
487 mVFlags &= ~NS_VIEW_FLAG_FLOATING;
489 #if 0
490 // recursively make all sub-views "floating" grr.
491 for (nsView* child = mFirstChild; chlid; child = child->GetNextSibling()) {
492 child->SetFloating(aFloatingView);
494 #endif
496 return NS_OK;
499 void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent)
501 if (aViewManagerParent) {
502 // We're removed from the view hierarchy of aRemovalPoint, so make sure
503 // we're not still grabbing mouse events.
504 if (aViewManagerParent->GetMouseEventGrabber() == this) {
505 PRBool res;
506 aViewManagerParent->GrabMouseEvents(nsnull, res);
510 if (mViewManager->GetRootView() == this)
511 mViewManager->InvalidateHierarchy();
513 for (nsView *child = mFirstChild; child; child = child->GetNextSibling())
514 child->InvalidateHierarchy(aViewManagerParent);
517 void nsView::InsertChild(nsView *aChild, nsView *aSibling)
519 NS_PRECONDITION(nsnull != aChild, "null ptr");
521 if (nsnull != aChild)
523 if (nsnull != aSibling)
525 #ifdef NS_DEBUG
526 NS_ASSERTION(aSibling->GetParent() == this, "tried to insert view with invalid sibling");
527 #endif
528 //insert after sibling
529 aChild->SetNextSibling(aSibling->GetNextSibling());
530 aSibling->SetNextSibling(aChild);
532 else
534 aChild->SetNextSibling(mFirstChild);
535 mFirstChild = aChild;
537 aChild->SetParent(this);
539 // If we just inserted a root view, then update the RootViewManager
540 // on all view managers in the new subtree.
542 nsViewManager *vm = aChild->GetViewManager();
543 if (vm->GetRootView() == aChild)
545 aChild->InvalidateHierarchy(nsnull); // don't care about releasing grabs
550 void nsView::RemoveChild(nsView *child)
552 NS_PRECONDITION(nsnull != child, "null ptr");
554 if (nsnull != child)
556 nsView* prevKid = nsnull;
557 nsView* kid = mFirstChild;
558 PRBool found = PR_FALSE;
559 while (nsnull != kid) {
560 if (kid == child) {
561 if (nsnull != prevKid) {
562 prevKid->SetNextSibling(kid->GetNextSibling());
563 } else {
564 mFirstChild = kid->GetNextSibling();
566 child->SetParent(nsnull);
567 found = PR_TRUE;
568 break;
570 prevKid = kid;
571 kid = kid->GetNextSibling();
573 NS_ASSERTION(found, "tried to remove non child");
575 // If we just removed a root view, then update the RootViewManager
576 // on all view managers in the removed subtree.
578 nsViewManager *vm = child->GetViewManager();
579 if (vm->GetRootView() == child)
581 child->InvalidateHierarchy(GetViewManager());
586 // Native widgets ultimately just can't deal with the awesome power of
587 // CSS2 z-index. However, we set the z-index on the widget anyway
588 // because in many simple common cases the widgets do end up in the
589 // right order. We set each widget's z-index to the z-index of the
590 // nearest ancestor that has non-auto z-index.
591 static void UpdateNativeWidgetZIndexes(nsView* aView, PRInt32 aZIndex)
593 if (aView->HasWidget()) {
594 nsIWidget* widget = aView->GetWidget();
595 PRInt32 curZ;
596 widget->GetZIndex(&curZ);
597 if (curZ != aZIndex) {
598 widget->SetZIndex(aZIndex);
600 } else {
601 for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
602 if (v->GetZIndexIsAuto()) {
603 UpdateNativeWidgetZIndexes(v, aZIndex);
609 static PRInt32 FindNonAutoZIndex(nsView* aView)
611 while (aView) {
612 if (!aView->GetZIndexIsAuto()) {
613 return aView->GetZIndex();
615 aView = aView->GetParent();
617 return 0;
620 nsresult nsIView::CreateWidget(const nsIID &aWindowIID,
621 nsWidgetInitData *aWidgetInitData,
622 nsNativeWidget aNative,
623 PRBool aEnableDragDrop,
624 PRBool aResetVisibility,
625 nsContentType aContentType,
626 nsIWidget* aParentWidget)
628 if (NS_UNLIKELY(mWindow)) {
629 NS_ERROR("We already have a window for this view? BAD");
630 ViewWrapper* wrapper = GetWrapperFor(mWindow);
631 NS_IF_RELEASE(wrapper);
632 mWindow->SetClientData(nsnull);
633 mWindow->Destroy();
634 NS_RELEASE(mWindow);
637 nsView* v = static_cast<nsView*>(this);
639 nsRect trect = v->CalcWidgetBounds(aWidgetInitData
640 ? aWidgetInitData->mWindowType
641 : eWindowType_child);
643 if (NS_OK == v->LoadWidget(aWindowIID))
645 PRBool usewidgets;
646 nsCOMPtr<nsIDeviceContext> dx;
647 mViewManager->GetDeviceContext(*getter_AddRefs(dx));
648 dx->SupportsNativeWidgets(usewidgets);
650 if (PR_TRUE == usewidgets)
652 PRBool initDataPassedIn = PR_TRUE;
653 nsWidgetInitData initData;
654 if (!aWidgetInitData) {
655 // No initData, we're a child window
656 // Create initData to pass in params
657 initDataPassedIn = PR_FALSE;
658 initData.clipChildren = PR_TRUE; // Clip child window's children
659 initData.clipSiblings = PR_TRUE; // Clip child window's siblings
660 aWidgetInitData = &initData;
662 aWidgetInitData->mContentType = aContentType;
664 if (aNative && aWidgetInitData->mWindowType != eWindowType_popup)
665 mWindow->Create(aNative, trect, ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
666 else
668 if (!initDataPassedIn && GetParent() &&
669 GetParent()->GetViewManager() != mViewManager)
670 initData.mListenForResizes = PR_TRUE;
671 if (aParentWidget) {
672 NS_ASSERTION(aWidgetInitData->mWindowType == eWindowType_popup,
673 "popup widget type expected");
674 mWindow->Create(aParentWidget, trect,
675 ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
677 else {
678 nsIWidget* parentWidget = GetParent() ? GetParent()->GetNearestWidget(nsnull)
679 : nsnull;
680 if (aWidgetInitData->mWindowType == eWindowType_popup) {
681 // Without a parent, we can't make a popup. This can happen
682 // when printing
683 if (!parentWidget)
684 return NS_ERROR_FAILURE;
685 mWindow->Create(parentWidget->GetNativeData(NS_NATIVE_WIDGET), trect,
686 ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
687 } else {
688 mWindow->Create(parentWidget, trect,
689 ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
693 if (aEnableDragDrop) {
694 mWindow->EnableDragDrop(PR_TRUE);
697 // propagate the z-index to the widget.
698 UpdateNativeWidgetZIndexes(v, FindNonAutoZIndex(v));
699 } else {
700 // We should tell the widget its size even if we don't create a
701 // native widget. (At the moment, this doesn't really matter,
702 // but we might want it to work at some point.)
703 mWindow->Resize(trect.x, trect.y, trect.width, trect.height,
704 PR_FALSE);
708 //make sure visibility state is accurate
710 if (aResetVisibility) {
711 v->SetVisibility(GetVisibility());
714 return NS_OK;
717 void nsView::SetZIndex(PRBool aAuto, PRInt32 aZIndex, PRBool aTopMost)
719 PRBool oldIsAuto = GetZIndexIsAuto();
720 mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0);
721 mZIndex = aZIndex;
722 SetTopMost(aTopMost);
724 if (HasWidget() || !oldIsAuto || !aAuto) {
725 UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
730 // internal window creation functions
732 nsresult nsView::LoadWidget(const nsCID &aClassIID)
734 ViewWrapper* wrapper = new ViewWrapper(this);
735 if (!wrapper)
736 return NS_ERROR_OUT_OF_MEMORY;
737 NS_ADDREF(wrapper); // Will be released in ~nsView
739 nsresult rv = CallCreateInstance(aClassIID, &mWindow);
741 if (NS_SUCCEEDED(rv)) {
742 // Set the widget's client data
743 mWindow->SetClientData(wrapper);
744 } else {
745 delete wrapper;
748 return rv;
751 #ifdef DEBUG
752 void nsIView::List(FILE* out, PRInt32 aIndent) const
754 PRInt32 i;
755 for (i = aIndent; --i >= 0; ) fputs(" ", out);
756 fprintf(out, "%p ", (void*)this);
757 if (nsnull != mWindow) {
758 nsRect windowBounds;
759 nsRect nonclientBounds;
760 float p2t;
761 nsIDeviceContext *dx;
762 mViewManager->GetDeviceContext(dx);
763 p2t = (float) dx->AppUnitsPerDevPixel();
764 NS_RELEASE(dx);
765 mWindow->GetClientBounds(windowBounds);
766 windowBounds *= p2t;
767 mWindow->GetBounds(nonclientBounds);
768 nonclientBounds *= p2t;
769 nsrefcnt widgetRefCnt = mWindow->AddRef() - 1;
770 mWindow->Release();
771 PRInt32 Z;
772 mWindow->GetZIndex(&Z);
773 fprintf(out, "(widget=%p[%d] z=%d pos={%d,%d,%d,%d}) ",
774 (void*)mWindow, widgetRefCnt, Z,
775 nonclientBounds.x, nonclientBounds.y,
776 windowBounds.width, windowBounds.height);
778 nsRect brect = GetBounds();
779 fprintf(out, "{%d,%d,%d,%d}",
780 brect.x, brect.y, brect.width, brect.height);
781 fprintf(out, " z=%d vis=%d clientData=%p <\n",
782 mZIndex, mVis, mClientData);
783 for (nsView* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
784 NS_ASSERTION(kid->GetParent() == this, "incorrect parent");
785 kid->List(out, aIndent + 1);
787 for (i = aIndent; --i >= 0; ) fputs(" ", out);
788 fputs(">\n", out);
790 #endif // DEBUG
792 nsPoint nsIView::GetOffsetTo(const nsIView* aOther) const
794 nsPoint offset(0, 0);
795 const nsIView* v;
796 for (v = this; v != aOther && v; v = v->GetParent()) {
797 offset += v->GetPosition();
800 if (v != aOther) {
801 // Looks like aOther wasn't an ancestor of |this|. So now we have
802 // the root-VM-relative position of |this| in |offset|. Convert back
803 // to the coordinates of aOther
804 while (aOther) {
805 offset -= aOther->GetPosition();
806 aOther = aOther->GetParent();
810 return offset;
813 nsIntPoint nsIView::GetScreenPosition() const
815 nsIntRect screenRect(0,0,0,0);
816 nsPoint toWidgetOffset(0,0);
817 nsIWidget* widget = GetNearestWidget(&toWidgetOffset);
818 if (widget) {
819 nsCOMPtr<nsIDeviceContext> dx;
820 mViewManager->GetDeviceContext(*getter_AddRefs(dx));
821 PRInt32 p2a = dx->AppUnitsPerDevPixel();
822 nsIntRect ourRect(NSAppUnitsToIntPixels(toWidgetOffset.x, p2a),
823 NSAppUnitsToIntPixels(toWidgetOffset.y, p2a),
826 widget->WidgetToScreen(ourRect, screenRect);
829 return nsIntPoint(screenRect.x, screenRect.y);
832 nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
834 nsPoint pt(0, 0);
835 const nsView* v;
836 for (v = static_cast<const nsView*>(this);
837 v && !v->HasWidget(); v = v->GetParent()) {
838 pt += v->GetPosition();
840 if (!v) {
841 if (aOffset) {
842 *aOffset = pt;
844 return static_cast<const nsView*>(this)->GetViewManager()->GetWidget();
847 // pt is now the offset from v's origin to this's origin
848 // The widget's origin is the top left corner of v's bounds, which may
849 // not coincide with v's origin
850 if (aOffset) {
851 nsRect vBounds = v->GetBounds();
852 *aOffset = pt + v->GetPosition() - nsPoint(vBounds.x, vBounds.y) +
853 v->ViewToWidgetOffset();
855 return v->GetWidget();
858 PRBool nsIView::IsRoot() const
860 NS_ASSERTION(mViewManager != nsnull," View manager is null in nsView::IsRoot()");
861 return mViewManager->GetRootView() == this;
864 PRBool nsIView::ExternalIsRoot() const
866 return nsIView::IsRoot();
869 void
870 nsIView::SetDeletionObserver(nsWeakView* aDeletionObserver)
872 if (mDeletionObserver && aDeletionObserver) {
873 aDeletionObserver->SetPrevious(mDeletionObserver);
875 mDeletionObserver = aDeletionObserver;
878 /* We invalidate the frame on a scroll iff this frame is marked as such or if
879 * some parent is.
881 PRBool nsIView::NeedsInvalidateFrameOnScroll() const
883 for (const nsIView *currView = this; currView != nsnull; currView = currView->GetParent())
884 if (currView->mVFlags & NS_VIEW_FLAG_INVALIDATE_ON_SCROLL)
885 return PR_TRUE;
887 return PR_FALSE;