Bug 451504 js/src/jslock.cpp failed to compile on Solaris x86 r=igor
[wine-gecko.git] / view / src / nsView.cpp
blob3ddecae1a57a02a85998534afc33abf4c3e7af81
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"
50 //mmptemp
52 static nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent);
55 //#define SHOW_VIEW_BORDERS
56 //#define HIDE_ALL_WIDGETS
58 // {34297A07-A8FD-d811-87C6-000244212BCB}
59 #define VIEW_WRAPPER_IID \
60 { 0x34297a07, 0xa8fd, 0xd811, { 0x87, 0xc6, 0x0, 0x2, 0x44, 0x21, 0x2b, 0xcb } }
63 /**
64 * nsISupports-derived helper class that allows to store and get a view
66 class ViewWrapper : public nsIInterfaceRequestor
68 public:
69 NS_DECLARE_STATIC_IID_ACCESSOR(VIEW_WRAPPER_IID)
70 NS_DECL_ISUPPORTS
71 NS_DECL_NSIINTERFACEREQUESTOR
73 ViewWrapper(nsView* aView) : mView(aView) {}
75 nsView* GetView() { return mView; }
76 private:
77 nsView* mView;
80 NS_DEFINE_STATIC_IID_ACCESSOR(ViewWrapper, VIEW_WRAPPER_IID)
82 NS_IMPL_ADDREF(ViewWrapper)
83 NS_IMPL_RELEASE(ViewWrapper)
84 #ifndef DEBUG
85 NS_IMPL_QUERY_INTERFACE2(ViewWrapper, ViewWrapper, nsIInterfaceRequestor)
87 #else
88 NS_IMETHODIMP ViewWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr)
90 NS_ENSURE_ARG_POINTER(aInstancePtr);
92 NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsIView)) &&
93 !aIID.Equals(NS_GET_IID(nsIScrollableView)),
94 "Someone expects a viewwrapper to be a view!");
96 *aInstancePtr = nsnull;
98 if (aIID.Equals(NS_GET_IID(nsISupports))) {
99 *aInstancePtr = static_cast<nsISupports*>(this);
101 else if (aIID.Equals(NS_GET_IID(ViewWrapper))) {
102 *aInstancePtr = this;
104 else if (aIID.Equals(NS_GET_IID(nsIInterfaceRequestor))) {
105 *aInstancePtr = this;
109 if (*aInstancePtr) {
110 AddRef();
111 return NS_OK;
114 return NS_NOINTERFACE;
116 #endif
118 NS_IMETHODIMP ViewWrapper::GetInterface(REFNSIID aIID, void** aInstancePtr)
120 if (aIID.Equals(NS_GET_IID(nsIScrollableView))) {
121 *aInstancePtr = mView->ToScrollableView();
122 return NS_OK;
124 if (aIID.Equals(NS_GET_IID(nsIView))) {
125 *aInstancePtr = mView;
126 return NS_OK;
128 return QueryInterface(aIID, aInstancePtr);
132 * Given a widget, returns the stored ViewWrapper on it, or NULL if no
133 * ViewWrapper is there.
135 static ViewWrapper* GetWrapperFor(nsIWidget* aWidget)
137 // The widget's client data points back to the owning view
138 if (aWidget) {
139 void* clientData;
140 aWidget->GetClientData(clientData);
141 nsISupports* data = (nsISupports*)clientData;
143 if (data) {
144 ViewWrapper* wrapper;
145 CallQueryInterface(data, &wrapper);
146 // Give a weak reference to the caller. There will still be at least one
147 // reference left, since the wrapper was addrefed when set on the widget.
148 if (wrapper)
149 wrapper->Release();
150 return wrapper;
153 return nsnull;
157 // Main events handler
159 nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent)
161 //printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->widgetSupports,
162 // aEvent->message, aEvent->point.x, aEvent->point.y);
163 nsEventStatus result = nsEventStatus_eIgnore;
164 nsView *view = nsView::GetViewFor(aEvent->widget);
166 if (view)
168 view->GetViewManager()->DispatchEvent(aEvent, &result);
171 return result;
174 nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
176 MOZ_COUNT_CTOR(nsView);
178 mVis = aVisibility;
179 // Views should be transparent by default. Not being transparent is
180 // a promise that the view will paint all its pixels opaquely. Views
181 // should make this promise explicitly by calling
182 // SetViewContentTransparency.
183 mVFlags = 0;
184 mViewManager = aViewManager;
185 mDirtyRegion = nsnull;
186 mDeletionObserver = nsnull;
189 void nsView::DropMouseGrabbing() {
190 // check to see if we are grabbing events
191 if (mViewManager->GetMouseEventGrabber() == this) {
192 // we are grabbing events. Move the grab to the parent if we can.
193 PRBool boolResult; //not used
194 // if GetParent() returns null, then we release the grab, which is the best we can do
195 mViewManager->GrabMouseEvents(GetParent(), boolResult);
199 nsView::~nsView()
201 MOZ_COUNT_DTOR(nsView);
203 if (this == nsViewManager::GetViewFocusedBeforeSuppression()) {
204 #ifdef DEBUG_FOCUS_SUPPRESSION
205 if (GetViewManager()->IsFocusSuppressed()) {
206 printf("*** 0 INFO TODO [CPEARCE] destroying view focused before suppression, while suppressed\n");
208 #endif
209 nsViewManager::SetViewFocusedBeforeSuppression(nsnull);
211 if (this == nsViewManager::GetCurrentlyFocusedView()) {
212 #ifdef DEBUG_FOCUS_SUPPRESSION
213 if (GetViewManager()->IsFocusSuppressed()) {
214 printf("*** 0 INFO TODO [CPEARCE] destroying view currently focused, while suppressed\n");
216 #endif
217 nsViewManager::SetCurrentlyFocusedView(nsnull);
220 while (GetFirstChild())
222 nsView* child = GetFirstChild();
223 if (child->GetViewManager() == mViewManager) {
224 child->Destroy();
225 } else {
226 // just unhook it. Someone else will want to destroy this.
227 RemoveChild(child);
231 if (mViewManager)
233 DropMouseGrabbing();
235 nsView *rootView = mViewManager->GetRootView();
237 if (rootView)
239 // Root views can have parents!
240 if (mParent)
242 mViewManager->RemoveChild(this);
245 if (rootView == this)
247 // Inform the view manager that the root view has gone away...
248 mViewManager->SetRootView(nsnull);
251 else if (mParent)
253 mParent->RemoveChild(this);
256 mViewManager = nsnull;
258 else if (mParent)
260 mParent->RemoveChild(this);
263 // Destroy and release the widget
264 if (mWindow)
266 // Release memory for the view wrapper
267 ViewWrapper* wrapper = GetWrapperFor(mWindow);
268 NS_IF_RELEASE(wrapper);
270 mWindow->SetClientData(nsnull);
271 if (!(mVFlags & NS_VIEW_DISOWNS_WIDGET)) {
272 mWindow->Destroy();
274 NS_RELEASE(mWindow);
276 delete mDirtyRegion;
278 if (mDeletionObserver) {
279 mDeletionObserver->Clear();
283 nsresult nsView::QueryInterface(const nsIID& aIID, void** aInstancePtr)
285 if (nsnull == aInstancePtr) {
286 return NS_ERROR_NULL_POINTER;
289 NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)),
290 "Someone expects views to be ISupports-derived!");
292 *aInstancePtr = nsnull;
294 if (aIID.Equals(NS_GET_IID(nsIView))) {
295 *aInstancePtr = (void*)(nsIView*)this;
296 return NS_OK;
299 return NS_NOINTERFACE;
302 nsIView* nsIView::GetViewFor(nsIWidget* aWidget)
304 NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
306 ViewWrapper* wrapper = GetWrapperFor(aWidget);
307 if (wrapper)
308 return wrapper->GetView();
309 return nsnull;
312 void nsIView::Destroy()
314 delete this;
317 void nsView::SetPosition(nscoord aX, nscoord aY)
319 mDimBounds.x += aX - mPosX;
320 mDimBounds.y += aY - mPosY;
321 mPosX = aX;
322 mPosY = aY;
324 NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
325 "Don't try to move the root widget to something non-zero");
327 ResetWidgetBounds(PR_TRUE, PR_TRUE, PR_FALSE);
330 void nsView::SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY)
332 mDimBounds.x += aX - mPosX;
333 mDimBounds.y += aY - mPosY;
334 mPosX = aX;
335 mPosY = aY;
337 ResetWidgetBounds(PR_FALSE, PR_TRUE, PR_FALSE);
340 void nsView::ResetWidgetBounds(PRBool aRecurse, PRBool aMoveOnly,
341 PRBool aInvalidateChangedSize) {
342 if (mWindow) {
343 // If our view manager has refresh disabled, then do nothing; the view
344 // manager will set our position when refresh is reenabled. Just let it
345 // know that it has pending updates.
346 if (!mViewManager->IsRefreshEnabled()) {
347 mViewManager->PostPendingUpdate();
348 return;
351 DoResetWidgetBounds(aMoveOnly, aInvalidateChangedSize);
352 } else if (aRecurse) {
353 // reposition any widgets under this view
354 for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
355 v->ResetWidgetBounds(PR_TRUE, aMoveOnly, aInvalidateChangedSize);
360 nsRect nsView::CalcWidgetBounds(nsWindowType aType)
362 nsCOMPtr<nsIDeviceContext> dx;
363 mViewManager->GetDeviceContext(*getter_AddRefs(dx));
364 NS_ASSERTION(dx, "View manager can't be created without a device context");
365 PRInt32 p2a = dx->AppUnitsPerDevPixel();
367 nsRect viewBounds(mDimBounds);
369 if (GetParent()) {
370 // put offset into screen coordinates
371 nsPoint offset;
372 nsIWidget* parentWidget = GetParent()->GetNearestWidget(&offset);
373 viewBounds += offset;
375 if (parentWidget && aType == eWindowType_popup &&
376 mVis == nsViewVisibility_kShow) {
377 nsRect screenRect(0,0,1,1);
378 parentWidget->WidgetToScreen(screenRect, screenRect);
379 viewBounds += nsPoint(NSIntPixelsToAppUnits(screenRect.x, p2a),
380 NSIntPixelsToAppUnits(screenRect.y, p2a));
384 nsRect newBounds(viewBounds);
385 newBounds.ScaleRoundPreservingCentersInverse(p2a);
387 nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a),
388 NSIntPixelsToAppUnits(newBounds.y, p2a));
389 mViewToWidgetOffset = viewBounds.TopLeft() - roundedOffset;
391 return newBounds;
394 void nsView::DoResetWidgetBounds(PRBool aMoveOnly,
395 PRBool aInvalidateChangedSize) {
396 // The geometry of a root view's widget is controlled externally,
397 // NOT by sizing or positioning the view
398 if (mViewManager->GetRootView() == this) {
399 return;
402 nsRect curBounds;
403 mWindow->GetBounds(curBounds);
404 nsWindowType type;
405 mWindow->GetWindowType(type);
407 if (curBounds.IsEmpty() && mDimBounds.IsEmpty() && type == eWindowType_popup) {
408 // Don't manipulate empty popup widgets. For example there's no point
409 // moving hidden comboboxes around, or doing X server roundtrips
410 // to compute their true screen position. This could mean that WidgetToScreen
411 // operations on these widgets don't return up-to-date values, but popup
412 // positions aren't reliable anyway because of correction to be on or off-screen.
413 return;
416 NS_PRECONDITION(mWindow, "Why was this called??");
418 nsRect newBounds = CalcWidgetBounds(type);
420 PRBool changedPos = curBounds.TopLeft() != newBounds.TopLeft();
421 PRBool changedSize = curBounds.Size() != newBounds.Size();
423 if (changedPos) {
424 if (changedSize && !aMoveOnly) {
425 mWindow->Resize(newBounds.x, newBounds.y, newBounds.width, newBounds.height,
426 aInvalidateChangedSize);
427 } else {
428 mWindow->Move(newBounds.x, newBounds.y);
430 } else {
431 if (changedSize && !aMoveOnly) {
432 mWindow->Resize(newBounds.width, newBounds.height, aInvalidateChangedSize);
433 } // else do nothing!
437 void nsView::SetDimensions(const nsRect& aRect, PRBool aPaint, PRBool aResizeWidget)
439 nsRect dims = aRect;
440 dims.MoveBy(mPosX, mPosY);
442 // Don't use nsRect's operator== here, since it returns true when
443 // both rects are empty even if they have different widths and we
444 // have cases where that sort of thing matters to us.
445 if (mDimBounds.TopLeft() == dims.TopLeft() &&
446 mDimBounds.Size() == dims.Size()) {
447 return;
450 mDimBounds = dims;
452 if (aResizeWidget) {
453 ResetWidgetBounds(PR_FALSE, PR_FALSE, aPaint);
457 NS_IMETHODIMP nsView::SetVisibility(nsViewVisibility aVisibility)
460 mVis = aVisibility;
462 if (aVisibility == nsViewVisibility_kHide)
464 DropMouseGrabbing();
467 if (nsnull != mWindow)
469 #ifndef HIDE_ALL_WIDGETS
470 if (mVis == nsViewVisibility_kShow)
472 DoResetWidgetBounds(PR_FALSE, PR_TRUE);
473 mWindow->Show(PR_TRUE);
475 else
476 #endif
477 mWindow->Show(PR_FALSE);
480 return NS_OK;
483 NS_IMETHODIMP nsView::SetFloating(PRBool aFloatingView)
485 if (aFloatingView)
486 mVFlags |= NS_VIEW_FLAG_FLOATING;
487 else
488 mVFlags &= ~NS_VIEW_FLAG_FLOATING;
490 #if 0
491 // recursively make all sub-views "floating" grr.
492 for (nsView* child = mFirstChild; chlid; child = child->GetNextSibling()) {
493 child->SetFloating(aFloatingView);
495 #endif
497 return NS_OK;
500 void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent)
502 if (aViewManagerParent) {
503 // We're removed from the view hierarchy of aRemovalPoint, so make sure
504 // we're not still grabbing mouse events.
505 if (aViewManagerParent->GetMouseEventGrabber() == this) {
506 PRBool res;
507 aViewManagerParent->GrabMouseEvents(nsnull, res);
511 if (mViewManager->GetRootView() == this)
512 mViewManager->InvalidateHierarchy();
514 for (nsView *child = mFirstChild; child; child = child->GetNextSibling())
515 child->InvalidateHierarchy(aViewManagerParent);
518 void nsView::InsertChild(nsView *aChild, nsView *aSibling)
520 NS_PRECONDITION(nsnull != aChild, "null ptr");
522 if (nsnull != aChild)
524 if (nsnull != aSibling)
526 #ifdef NS_DEBUG
527 NS_ASSERTION(aSibling->GetParent() == this, "tried to insert view with invalid sibling");
528 #endif
529 //insert after sibling
530 aChild->SetNextSibling(aSibling->GetNextSibling());
531 aSibling->SetNextSibling(aChild);
533 else
535 aChild->SetNextSibling(mFirstChild);
536 mFirstChild = aChild;
538 aChild->SetParent(this);
540 // If we just inserted a root view, then update the RootViewManager
541 // on all view managers in the new subtree.
543 nsViewManager *vm = aChild->GetViewManager();
544 if (vm->GetRootView() == aChild)
546 aChild->InvalidateHierarchy(nsnull); // don't care about releasing grabs
551 void nsView::RemoveChild(nsView *child)
553 NS_PRECONDITION(nsnull != child, "null ptr");
555 if (nsnull != child)
557 nsView* prevKid = nsnull;
558 nsView* kid = mFirstChild;
559 PRBool found = PR_FALSE;
560 while (nsnull != kid) {
561 if (kid == child) {
562 if (nsnull != prevKid) {
563 prevKid->SetNextSibling(kid->GetNextSibling());
564 } else {
565 mFirstChild = kid->GetNextSibling();
567 child->SetParent(nsnull);
568 found = PR_TRUE;
569 break;
571 prevKid = kid;
572 kid = kid->GetNextSibling();
574 NS_ASSERTION(found, "tried to remove non child");
576 // If we just removed a root view, then update the RootViewManager
577 // on all view managers in the removed subtree.
579 nsViewManager *vm = child->GetViewManager();
580 if (vm->GetRootView() == child)
582 child->InvalidateHierarchy(GetViewManager());
587 // Native widgets ultimately just can't deal with the awesome power of
588 // CSS2 z-index. However, we set the z-index on the widget anyway
589 // because in many simple common cases the widgets do end up in the
590 // right order. We set each widget's z-index to the z-index of the
591 // nearest ancestor that has non-auto z-index.
592 static void UpdateNativeWidgetZIndexes(nsView* aView, PRInt32 aZIndex)
594 if (aView->HasWidget()) {
595 nsIWidget* widget = aView->GetWidget();
596 PRInt32 curZ;
597 widget->GetZIndex(&curZ);
598 if (curZ != aZIndex) {
599 widget->SetZIndex(aZIndex);
601 } else {
602 for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
603 if (v->GetZIndexIsAuto()) {
604 UpdateNativeWidgetZIndexes(v, aZIndex);
610 static PRInt32 FindNonAutoZIndex(nsView* aView)
612 while (aView) {
613 if (!aView->GetZIndexIsAuto()) {
614 return aView->GetZIndex();
616 aView = aView->GetParent();
618 return 0;
621 nsresult nsIView::CreateWidget(const nsIID &aWindowIID,
622 nsWidgetInitData *aWidgetInitData,
623 nsNativeWidget aNative,
624 PRBool aEnableDragDrop,
625 PRBool aResetVisibility,
626 nsContentType aContentType,
627 nsIWidget* aParentWidget)
629 if (NS_UNLIKELY(mWindow)) {
630 NS_ERROR("We already have a window for this view? BAD");
631 ViewWrapper* wrapper = GetWrapperFor(mWindow);
632 NS_IF_RELEASE(wrapper);
633 mWindow->SetClientData(nsnull);
634 mWindow->Destroy();
635 NS_RELEASE(mWindow);
638 nsView* v = static_cast<nsView*>(this);
640 nsRect trect = v->CalcWidgetBounds(aWidgetInitData
641 ? aWidgetInitData->mWindowType
642 : eWindowType_child);
644 if (NS_OK == v->LoadWidget(aWindowIID))
646 PRBool usewidgets;
647 nsCOMPtr<nsIDeviceContext> dx;
648 mViewManager->GetDeviceContext(*getter_AddRefs(dx));
649 dx->SupportsNativeWidgets(usewidgets);
651 if (PR_TRUE == usewidgets)
653 PRBool initDataPassedIn = PR_TRUE;
654 nsWidgetInitData initData;
655 if (!aWidgetInitData) {
656 // No initData, we're a child window
657 // Create initData to pass in params
658 initDataPassedIn = PR_FALSE;
659 initData.clipChildren = PR_TRUE; // Clip child window's children
660 initData.clipSiblings = PR_TRUE; // Clip child window's siblings
661 aWidgetInitData = &initData;
663 aWidgetInitData->mContentType = aContentType;
665 if (aNative && aWidgetInitData->mWindowType != eWindowType_popup)
666 mWindow->Create(aNative, trect, ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
667 else
669 if (!initDataPassedIn && GetParent() &&
670 GetParent()->GetViewManager() != mViewManager)
671 initData.mListenForResizes = PR_TRUE;
672 if (aParentWidget) {
673 NS_ASSERTION(aWidgetInitData->mWindowType == eWindowType_popup,
674 "popup widget type expected");
675 mWindow->Create(aParentWidget, trect,
676 ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
678 else {
679 nsIWidget* parentWidget = GetParent() ? GetParent()->GetNearestWidget(nsnull)
680 : nsnull;
681 if (aWidgetInitData->mWindowType == eWindowType_popup) {
682 // Without a parent, we can't make a popup. This can happen
683 // when printing
684 if (!parentWidget)
685 return NS_ERROR_FAILURE;
686 mWindow->Create(parentWidget->GetNativeData(NS_NATIVE_WIDGET), trect,
687 ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
688 } else {
689 mWindow->Create(parentWidget, trect,
690 ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);
694 if (aEnableDragDrop) {
695 mWindow->EnableDragDrop(PR_TRUE);
698 // propagate the z-index to the widget.
699 UpdateNativeWidgetZIndexes(v, FindNonAutoZIndex(v));
700 } else {
701 // We should tell the widget its size even if we don't create a
702 // native widget. (At the moment, this doesn't really matter,
703 // but we might want it to work at some point.)
704 mWindow->Resize(trect.x, trect.y, trect.width, trect.height,
705 PR_FALSE);
709 //make sure visibility state is accurate
711 if (aResetVisibility) {
712 v->SetVisibility(GetVisibility());
715 return NS_OK;
718 void nsView::SetZIndex(PRBool aAuto, PRInt32 aZIndex, PRBool aTopMost)
720 PRBool oldIsAuto = GetZIndexIsAuto();
721 mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0);
722 mZIndex = aZIndex;
723 SetTopMost(aTopMost);
725 if (HasWidget() || !oldIsAuto || !aAuto) {
726 UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
731 // internal window creation functions
733 nsresult nsView::LoadWidget(const nsCID &aClassIID)
735 ViewWrapper* wrapper = new ViewWrapper(this);
736 if (!wrapper)
737 return NS_ERROR_OUT_OF_MEMORY;
738 NS_ADDREF(wrapper); // Will be released in ~nsView
740 nsresult rv = CallCreateInstance(aClassIID, &mWindow);
742 if (NS_SUCCEEDED(rv)) {
743 // Set the widget's client data
744 mWindow->SetClientData(wrapper);
745 } else {
746 delete wrapper;
749 return rv;
752 #ifdef DEBUG
753 void nsIView::List(FILE* out, PRInt32 aIndent) const
755 PRInt32 i;
756 for (i = aIndent; --i >= 0; ) fputs(" ", out);
757 fprintf(out, "%p ", (void*)this);
758 if (nsnull != mWindow) {
759 nsRect windowBounds;
760 nsRect nonclientBounds;
761 float p2t;
762 nsIDeviceContext *dx;
763 mViewManager->GetDeviceContext(dx);
764 p2t = (float) dx->AppUnitsPerDevPixel();
765 NS_RELEASE(dx);
766 mWindow->GetClientBounds(windowBounds);
767 windowBounds *= p2t;
768 mWindow->GetBounds(nonclientBounds);
769 nonclientBounds *= p2t;
770 nsrefcnt widgetRefCnt = mWindow->AddRef() - 1;
771 mWindow->Release();
772 PRInt32 Z;
773 mWindow->GetZIndex(&Z);
774 fprintf(out, "(widget=%p[%d] z=%d pos={%d,%d,%d,%d}) ",
775 (void*)mWindow, widgetRefCnt, Z,
776 nonclientBounds.x, nonclientBounds.y,
777 windowBounds.width, windowBounds.height);
779 nsRect brect = GetBounds();
780 fprintf(out, "{%d,%d,%d,%d}",
781 brect.x, brect.y, brect.width, brect.height);
782 fprintf(out, " z=%d vis=%d clientData=%p <\n",
783 mZIndex, mVis, mClientData);
784 for (nsView* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
785 NS_ASSERTION(kid->GetParent() == this, "incorrect parent");
786 kid->List(out, aIndent + 1);
788 for (i = aIndent; --i >= 0; ) fputs(" ", out);
789 fputs(">\n", out);
791 #endif // DEBUG
793 nsPoint nsIView::GetOffsetTo(const nsIView* aOther) const
795 nsPoint offset(0, 0);
796 const nsIView* v;
797 for (v = this; v != aOther && v; v = v->GetParent()) {
798 offset += v->GetPosition();
801 if (v != aOther) {
802 // Looks like aOther wasn't an ancestor of |this|. So now we have
803 // the root-VM-relative position of |this| in |offset|. Convert back
804 // to the coordinates of aOther
805 while (aOther) {
806 offset -= aOther->GetPosition();
807 aOther = aOther->GetParent();
811 return offset;
814 nsIntPoint nsIView::GetScreenPosition() const
816 nsIntRect screenRect(0,0,0,0);
817 nsPoint toWidgetOffset(0,0);
818 nsIWidget* widget = GetNearestWidget(&toWidgetOffset);
819 if (widget) {
820 nsCOMPtr<nsIDeviceContext> dx;
821 mViewManager->GetDeviceContext(*getter_AddRefs(dx));
822 PRInt32 p2a = dx->AppUnitsPerDevPixel();
823 nsIntRect ourRect(NSAppUnitsToIntPixels(toWidgetOffset.x, p2a),
824 NSAppUnitsToIntPixels(toWidgetOffset.y, p2a),
827 widget->WidgetToScreen(ourRect, screenRect);
830 return nsIntPoint(screenRect.x, screenRect.y);
833 nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
835 nsPoint pt(0, 0);
836 const nsView* v;
837 for (v = static_cast<const nsView*>(this);
838 v && !v->HasWidget(); v = v->GetParent()) {
839 pt += v->GetPosition();
841 if (!v) {
842 if (aOffset) {
843 *aOffset = pt;
845 return static_cast<const nsView*>(this)->GetViewManager()->GetWidget();
848 // pt is now the offset from v's origin to this's origin
849 // The widget's origin is the top left corner of v's bounds, which may
850 // not coincide with v's origin
851 if (aOffset) {
852 nsRect vBounds = v->GetBounds();
853 *aOffset = pt + v->GetPosition() - nsPoint(vBounds.x, vBounds.y) +
854 v->ViewToWidgetOffset();
856 return v->GetWidget();
859 PRBool nsIView::IsRoot() const
861 NS_ASSERTION(mViewManager != nsnull," View manager is null in nsView::IsRoot()");
862 return mViewManager->GetRootView() == this;
865 PRBool nsIView::ExternalIsRoot() const
867 return nsIView::IsRoot();
870 void
871 nsIView::SetDeletionObserver(nsWeakView* aDeletionObserver)
873 if (mDeletionObserver && aDeletionObserver) {
874 aDeletionObserver->SetPrevious(mDeletionObserver);
876 mDeletionObserver = aDeletionObserver;