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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : *
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.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsView.h"
39 : #include "nsIWidget.h"
40 : #include "nsWidgetsCID.h"
41 : #include "nsViewManager.h"
42 : #include "nsGUIEvent.h"
43 : #include "nsIComponentManager.h"
44 : #include "nsGfxCIID.h"
45 : #include "nsIInterfaceRequestor.h"
46 :
47 : //mmptemp
48 :
49 : static nsEventStatus HandleEvent(nsGUIEvent *aEvent);
50 :
51 :
52 : //#define SHOW_VIEW_BORDERS
53 :
54 : #define VIEW_WRAPPER_IID \
55 : { 0xbf4e1841, 0xe9ec, 0x47f2, \
56 : { 0xb4, 0x77, 0x0f, 0xf6, 0x0f, 0x5a, 0xac, 0xbd } }
57 :
58 : /**
59 : * nsISupports-derived helper class that allows to store and get a view
60 : */
61 : class ViewWrapper : public nsIInterfaceRequestor
62 : {
63 : public:
64 : NS_DECLARE_STATIC_IID_ACCESSOR(VIEW_WRAPPER_IID)
65 : NS_DECL_ISUPPORTS
66 : NS_DECL_NSIINTERFACEREQUESTOR
67 :
68 0 : ViewWrapper(nsView* aView) : mView(aView) {}
69 :
70 0 : nsView* GetView() { return mView; }
71 : private:
72 : nsView* mView;
73 : };
74 :
75 : NS_DEFINE_STATIC_IID_ACCESSOR(ViewWrapper, VIEW_WRAPPER_IID)
76 :
77 0 : NS_IMPL_ADDREF(ViewWrapper)
78 0 : NS_IMPL_RELEASE(ViewWrapper)
79 : #ifndef DEBUG
80 : NS_IMPL_QUERY_INTERFACE2(ViewWrapper, ViewWrapper, nsIInterfaceRequestor)
81 :
82 : #else
83 0 : NS_IMETHODIMP ViewWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr)
84 : {
85 0 : NS_ENSURE_ARG_POINTER(aInstancePtr);
86 :
87 0 : NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsIView)),
88 : "Someone expects a viewwrapper to be a view!");
89 :
90 0 : *aInstancePtr = nsnull;
91 :
92 0 : if (aIID.Equals(NS_GET_IID(nsISupports))) {
93 0 : *aInstancePtr = static_cast<nsISupports*>(this);
94 : }
95 0 : else if (aIID.Equals(NS_GET_IID(ViewWrapper))) {
96 0 : *aInstancePtr = this;
97 : }
98 0 : else if (aIID.Equals(NS_GET_IID(nsIInterfaceRequestor))) {
99 0 : *aInstancePtr = this;
100 : }
101 :
102 :
103 0 : if (*aInstancePtr) {
104 0 : AddRef();
105 0 : return NS_OK;
106 : }
107 :
108 0 : return NS_NOINTERFACE;
109 : }
110 : #endif
111 :
112 0 : NS_IMETHODIMP ViewWrapper::GetInterface(REFNSIID aIID, void** aInstancePtr)
113 : {
114 0 : if (aIID.Equals(NS_GET_IID(nsIView))) {
115 0 : *aInstancePtr = mView;
116 0 : return NS_OK;
117 : }
118 0 : return QueryInterface(aIID, aInstancePtr);
119 : }
120 :
121 : /**
122 : * Given a widget, returns the stored ViewWrapper on it, or NULL if no
123 : * ViewWrapper is there.
124 : */
125 0 : static ViewWrapper* GetWrapperFor(nsIWidget* aWidget)
126 : {
127 : // The widget's client data points back to the owning view
128 0 : if (aWidget) {
129 : void* clientData;
130 0 : aWidget->GetClientData(clientData);
131 0 : nsISupports* data = (nsISupports*)clientData;
132 :
133 0 : if (data) {
134 : ViewWrapper* wrapper;
135 0 : CallQueryInterface(data, &wrapper);
136 : // Give a weak reference to the caller. There will still be at least one
137 : // reference left, since the wrapper was addrefed when set on the widget.
138 0 : if (wrapper)
139 0 : wrapper->Release();
140 0 : return wrapper;
141 : }
142 : }
143 0 : return nsnull;
144 : }
145 :
146 : // Main events handler
147 0 : static nsEventStatus HandleEvent(nsGUIEvent *aEvent)
148 : {
149 : #if 0
150 : printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->message);
151 : #endif
152 0 : nsEventStatus result = nsEventStatus_eIgnore;
153 0 : nsView *view = nsView::GetViewFor(aEvent->widget);
154 :
155 0 : if (view)
156 : {
157 0 : nsCOMPtr<nsIViewManager> vm = view->GetViewManager();
158 0 : vm->DispatchEvent(aEvent, view, &result);
159 : }
160 :
161 0 : return result;
162 : }
163 :
164 : // Attached widget event helpers
165 0 : static ViewWrapper* GetAttachedWrapperFor(nsIWidget* aWidget)
166 : {
167 0 : NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
168 0 : return aWidget->GetAttachedViewPtr();
169 : }
170 :
171 0 : static nsView* GetAttachedViewFor(nsIWidget* aWidget)
172 : {
173 0 : NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
174 :
175 0 : ViewWrapper* wrapper = GetAttachedWrapperFor(aWidget);
176 0 : if (!wrapper)
177 0 : return nsnull;
178 0 : return wrapper->GetView();
179 : }
180 :
181 : // event handler
182 0 : static nsEventStatus AttachedHandleEvent(nsGUIEvent *aEvent)
183 : {
184 0 : nsEventStatus result = nsEventStatus_eIgnore;
185 0 : nsView *view = GetAttachedViewFor(aEvent->widget);
186 :
187 0 : if (view)
188 : {
189 0 : nsCOMPtr<nsIViewManager> vm = view->GetViewManager();
190 0 : vm->DispatchEvent(aEvent, view, &result);
191 : }
192 :
193 0 : return result;
194 : }
195 :
196 0 : nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
197 : {
198 0 : MOZ_COUNT_CTOR(nsView);
199 :
200 0 : mVis = aVisibility;
201 : // Views should be transparent by default. Not being transparent is
202 : // a promise that the view will paint all its pixels opaquely. Views
203 : // should make this promise explicitly by calling
204 : // SetViewContentTransparency.
205 0 : mVFlags = 0;
206 0 : mViewManager = aViewManager;
207 0 : mDirtyRegion = nsnull;
208 0 : mDeletionObserver = nsnull;
209 0 : mHaveInvalidationDimensions = false;
210 0 : mWidgetIsTopLevel = false;
211 0 : }
212 :
213 0 : void nsView::DropMouseGrabbing()
214 : {
215 0 : nsIPresShell* presShell = mViewManager->GetPresShell();
216 0 : if (presShell)
217 0 : presShell->ClearMouseCaptureOnView(this);
218 0 : }
219 :
220 0 : nsView::~nsView()
221 : {
222 0 : MOZ_COUNT_DTOR(nsView);
223 :
224 0 : while (GetFirstChild())
225 : {
226 0 : nsView* child = GetFirstChild();
227 0 : if (child->GetViewManager() == mViewManager) {
228 0 : child->Destroy();
229 : } else {
230 : // just unhook it. Someone else will want to destroy this.
231 0 : RemoveChild(child);
232 : }
233 : }
234 :
235 0 : if (mViewManager)
236 : {
237 0 : DropMouseGrabbing();
238 :
239 0 : nsView *rootView = mViewManager->GetRootViewImpl();
240 :
241 0 : if (rootView)
242 : {
243 : // Root views can have parents!
244 0 : if (mParent)
245 : {
246 0 : mViewManager->RemoveChild(this);
247 : }
248 :
249 0 : if (rootView == this)
250 : {
251 : // Inform the view manager that the root view has gone away...
252 0 : mViewManager->SetRootView(nsnull);
253 : }
254 : }
255 0 : else if (mParent)
256 : {
257 0 : mParent->RemoveChild(this);
258 : }
259 :
260 0 : mViewManager = nsnull;
261 : }
262 0 : else if (mParent)
263 : {
264 0 : mParent->RemoveChild(this);
265 : }
266 :
267 : // Destroy and release the widget
268 0 : DestroyWidget();
269 :
270 0 : delete mDirtyRegion;
271 :
272 0 : if (mDeletionObserver) {
273 0 : mDeletionObserver->Clear();
274 : }
275 0 : }
276 :
277 0 : void nsView::DestroyWidget()
278 : {
279 0 : if (mWindow)
280 : {
281 : // Release memory for the view wrapper
282 0 : ViewWrapper* wrapper = GetWrapperFor(mWindow);
283 0 : NS_IF_RELEASE(wrapper);
284 :
285 : // If we are not attached to a base window, we're going to tear down our
286 : // widget here. However, if we're attached to somebody elses widget, we
287 : // want to leave the widget alone: don't reset the client data or call
288 : // Destroy. Just clear our event view ptr and free our reference to it.
289 0 : if (mWidgetIsTopLevel) {
290 0 : ViewWrapper* wrapper = GetAttachedWrapperFor(mWindow);
291 0 : NS_IF_RELEASE(wrapper);
292 :
293 0 : mWindow->SetAttachedViewPtr(nsnull);
294 : }
295 : else {
296 0 : mWindow->SetClientData(nsnull);
297 0 : mWindow->Destroy();
298 : }
299 :
300 0 : NS_RELEASE(mWindow);
301 : }
302 0 : }
303 :
304 0 : nsresult nsView::QueryInterface(const nsIID& aIID, void** aInstancePtr)
305 : {
306 0 : if (nsnull == aInstancePtr) {
307 0 : return NS_ERROR_NULL_POINTER;
308 : }
309 :
310 0 : NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)),
311 : "Someone expects views to be ISupports-derived!");
312 :
313 0 : *aInstancePtr = nsnull;
314 :
315 0 : if (aIID.Equals(NS_GET_IID(nsIView))) {
316 0 : *aInstancePtr = (void*)(nsIView*)this;
317 0 : return NS_OK;
318 : }
319 :
320 0 : return NS_NOINTERFACE;
321 : }
322 :
323 0 : nsIView* nsIView::GetViewFor(nsIWidget* aWidget)
324 : {
325 0 : NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
326 :
327 0 : ViewWrapper* wrapper = GetWrapperFor(aWidget);
328 :
329 0 : if (!wrapper) {
330 0 : wrapper = GetAttachedWrapperFor(aWidget);
331 : }
332 :
333 0 : if (wrapper) {
334 0 : return wrapper->GetView();
335 : }
336 :
337 0 : return nsnull;
338 : }
339 :
340 0 : void nsIView::Destroy()
341 : {
342 0 : delete this;
343 0 : }
344 :
345 0 : void nsView::SetPosition(nscoord aX, nscoord aY)
346 : {
347 0 : mDimBounds.x += aX - mPosX;
348 0 : mDimBounds.y += aY - mPosY;
349 0 : mPosX = aX;
350 0 : mPosY = aY;
351 :
352 0 : NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
353 : "Don't try to move the root widget to something non-zero");
354 :
355 0 : ResetWidgetBounds(true, false);
356 0 : }
357 :
358 0 : void nsIView::SetInvalidationDimensions(const nsRect* aRect)
359 : {
360 0 : return Impl()->SetInvalidationDimensions(aRect);
361 : }
362 :
363 0 : void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync)
364 : {
365 0 : if (mWindow) {
366 0 : if (!aForceSync) {
367 : // Don't change widget geometry synchronously, since that can
368 : // cause synchronous painting.
369 0 : mViewManager->PostPendingUpdate();
370 : } else {
371 0 : DoResetWidgetBounds(false, true);
372 : }
373 0 : return;
374 : }
375 :
376 0 : if (aRecurse) {
377 : // reposition any widgets under this view
378 0 : for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
379 0 : v->ResetWidgetBounds(true, aForceSync);
380 : }
381 : }
382 : }
383 :
384 0 : bool nsIView::IsEffectivelyVisible()
385 : {
386 0 : for (nsIView* v = this; v; v = v->mParent) {
387 0 : if (v->GetVisibility() == nsViewVisibility_kHide)
388 0 : return false;
389 : }
390 0 : return true;
391 : }
392 :
393 0 : nsIntRect nsIView::CalcWidgetBounds(nsWindowType aType)
394 : {
395 0 : PRInt32 p2a = mViewManager->AppUnitsPerDevPixel();
396 :
397 0 : nsRect viewBounds(mDimBounds);
398 :
399 0 : nsView* parent = GetParent()->Impl();
400 0 : if (parent) {
401 0 : nsPoint offset;
402 0 : nsIWidget* parentWidget = parent->GetNearestWidget(&offset, p2a);
403 : // make viewBounds be relative to the parent widget, in appunits
404 0 : viewBounds += offset;
405 :
406 0 : if (parentWidget && aType == eWindowType_popup &&
407 0 : IsEffectivelyVisible()) {
408 : // put offset into screen coordinates. (based on client area origin)
409 0 : nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset();
410 : viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
411 0 : NSIntPixelsToAppUnits(screenPoint.y, p2a));
412 : }
413 : }
414 :
415 : // Compute widget bounds in device pixels
416 0 : nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
417 :
418 : // Compute where the top-left of our widget ended up relative to the parent
419 : // widget, in appunits.
420 : nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a),
421 0 : NSIntPixelsToAppUnits(newBounds.y, p2a));
422 :
423 : // mViewToWidgetOffset is added to coordinates relative to the view origin
424 : // to get coordinates relative to the widget.
425 : // The view origin, relative to the parent widget, is at
426 : // (mPosX,mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft().
427 : // Our widget, relative to the parent widget, is roundedOffset.
428 : mViewToWidgetOffset = nsPoint(mPosX, mPosY)
429 0 : - mDimBounds.TopLeft() + viewBounds.TopLeft() - roundedOffset;
430 :
431 : return newBounds;
432 : }
433 :
434 0 : void nsView::DoResetWidgetBounds(bool aMoveOnly,
435 : bool aInvalidateChangedSize) {
436 : // The geometry of a root view's widget is controlled externally,
437 : // NOT by sizing or positioning the view
438 0 : if (mViewManager->GetRootViewImpl() == this) {
439 0 : return;
440 : }
441 :
442 0 : nsIntRect curBounds;
443 0 : mWindow->GetClientBounds(curBounds);
444 :
445 : nsWindowType type;
446 0 : mWindow->GetWindowType(type);
447 :
448 0 : if (curBounds.IsEmpty() && mDimBounds.IsEmpty() && type == eWindowType_popup) {
449 : // Don't manipulate empty popup widgets. For example there's no point
450 : // moving hidden comboboxes around, or doing X server roundtrips
451 : // to compute their true screen position. This could mean that WidgetToScreen
452 : // operations on these widgets don't return up-to-date values, but popup
453 : // positions aren't reliable anyway because of correction to be on or off-screen.
454 0 : return;
455 : }
456 :
457 0 : NS_PRECONDITION(mWindow, "Why was this called??");
458 :
459 0 : nsIntRect newBounds = CalcWidgetBounds(type);
460 :
461 0 : bool changedPos = curBounds.TopLeft() != newBounds.TopLeft();
462 0 : bool changedSize = curBounds.Size() != newBounds.Size();
463 :
464 : // Child views are never attached to top level widgets, this is safe.
465 0 : if (changedPos) {
466 0 : if (changedSize && !aMoveOnly) {
467 : mWindow->ResizeClient(newBounds.x, newBounds.y,
468 : newBounds.width, newBounds.height,
469 0 : aInvalidateChangedSize);
470 : } else {
471 0 : mWindow->MoveClient(newBounds.x, newBounds.y);
472 : }
473 : } else {
474 0 : if (changedSize && !aMoveOnly) {
475 : mWindow->ResizeClient(newBounds.width, newBounds.height,
476 0 : aInvalidateChangedSize);
477 : } // else do nothing!
478 : }
479 : }
480 :
481 0 : void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget)
482 : {
483 0 : nsRect dims = aRect;
484 0 : dims.MoveBy(mPosX, mPosY);
485 :
486 : // Don't use nsRect's operator== here, since it returns true when
487 : // both rects are empty even if they have different widths and we
488 : // have cases where that sort of thing matters to us.
489 0 : if (mDimBounds.TopLeft() == dims.TopLeft() &&
490 0 : mDimBounds.Size() == dims.Size()) {
491 : return;
492 : }
493 :
494 0 : mDimBounds = dims;
495 :
496 0 : if (aResizeWidget) {
497 0 : ResetWidgetBounds(false, false);
498 : }
499 : }
500 :
501 0 : void nsView::SetInvalidationDimensions(const nsRect* aRect)
502 : {
503 0 : if ((mHaveInvalidationDimensions = !!aRect)) {
504 0 : mInvalidationDimensions = *aRect;
505 : }
506 0 : }
507 :
508 0 : void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible)
509 : {
510 0 : if (!aEffectivelyVisible)
511 : {
512 0 : DropMouseGrabbing();
513 : }
514 :
515 0 : if (nsnull != mWindow)
516 : {
517 0 : if (aEffectivelyVisible)
518 : {
519 0 : DoResetWidgetBounds(false, true);
520 0 : mWindow->Show(true);
521 : }
522 : else
523 0 : mWindow->Show(false);
524 : }
525 :
526 0 : for (nsView* child = mFirstChild; child; child = child->mNextSibling) {
527 0 : if (child->mVis == nsViewVisibility_kHide) {
528 : // It was effectively hidden and still is
529 0 : continue;
530 : }
531 : // Our child is visible if we are
532 0 : child->NotifyEffectiveVisibilityChanged(aEffectivelyVisible);
533 : }
534 0 : }
535 :
536 0 : NS_IMETHODIMP nsView::SetVisibility(nsViewVisibility aVisibility)
537 : {
538 0 : mVis = aVisibility;
539 0 : NotifyEffectiveVisibilityChanged(IsEffectivelyVisible());
540 0 : return NS_OK;
541 : }
542 :
543 0 : NS_IMETHODIMP nsView::SetFloating(bool aFloatingView)
544 : {
545 0 : if (aFloatingView)
546 0 : mVFlags |= NS_VIEW_FLAG_FLOATING;
547 : else
548 0 : mVFlags &= ~NS_VIEW_FLAG_FLOATING;
549 :
550 : #if 0
551 : // recursively make all sub-views "floating" grr.
552 : for (nsView* child = mFirstChild; chlid; child = child->GetNextSibling()) {
553 : child->SetFloating(aFloatingView);
554 : }
555 : #endif
556 :
557 0 : return NS_OK;
558 : }
559 :
560 0 : void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent)
561 : {
562 0 : if (mViewManager->GetRootViewImpl() == this)
563 0 : mViewManager->InvalidateHierarchy();
564 :
565 0 : for (nsView *child = mFirstChild; child; child = child->GetNextSibling())
566 0 : child->InvalidateHierarchy(aViewManagerParent);
567 0 : }
568 :
569 0 : void nsView::InsertChild(nsView *aChild, nsView *aSibling)
570 : {
571 0 : NS_PRECONDITION(nsnull != aChild, "null ptr");
572 :
573 0 : if (nsnull != aChild)
574 : {
575 0 : if (nsnull != aSibling)
576 : {
577 : #ifdef NS_DEBUG
578 0 : NS_ASSERTION(aSibling->GetParent() == this, "tried to insert view with invalid sibling");
579 : #endif
580 : //insert after sibling
581 0 : aChild->SetNextSibling(aSibling->GetNextSibling());
582 0 : aSibling->SetNextSibling(aChild);
583 : }
584 : else
585 : {
586 0 : aChild->SetNextSibling(mFirstChild);
587 0 : mFirstChild = aChild;
588 : }
589 0 : aChild->SetParent(this);
590 :
591 : // If we just inserted a root view, then update the RootViewManager
592 : // on all view managers in the new subtree.
593 :
594 0 : nsViewManager *vm = aChild->GetViewManager();
595 0 : if (vm->GetRootViewImpl() == aChild)
596 : {
597 0 : aChild->InvalidateHierarchy(nsnull); // don't care about releasing grabs
598 : }
599 : }
600 0 : }
601 :
602 0 : void nsView::RemoveChild(nsView *child)
603 : {
604 0 : NS_PRECONDITION(nsnull != child, "null ptr");
605 :
606 0 : if (nsnull != child)
607 : {
608 0 : nsView* prevKid = nsnull;
609 0 : nsView* kid = mFirstChild;
610 0 : bool found = false;
611 0 : while (nsnull != kid) {
612 0 : if (kid == child) {
613 0 : if (nsnull != prevKid) {
614 0 : prevKid->SetNextSibling(kid->GetNextSibling());
615 : } else {
616 0 : mFirstChild = kid->GetNextSibling();
617 : }
618 0 : child->SetParent(nsnull);
619 0 : found = true;
620 0 : break;
621 : }
622 0 : prevKid = kid;
623 0 : kid = kid->GetNextSibling();
624 : }
625 0 : NS_ASSERTION(found, "tried to remove non child");
626 :
627 : // If we just removed a root view, then update the RootViewManager
628 : // on all view managers in the removed subtree.
629 :
630 0 : nsViewManager *vm = child->GetViewManager();
631 0 : if (vm->GetRootViewImpl() == child)
632 : {
633 0 : child->InvalidateHierarchy(GetViewManager());
634 : }
635 : }
636 0 : }
637 :
638 : // Native widgets ultimately just can't deal with the awesome power of
639 : // CSS2 z-index. However, we set the z-index on the widget anyway
640 : // because in many simple common cases the widgets do end up in the
641 : // right order. We set each widget's z-index to the z-index of the
642 : // nearest ancestor that has non-auto z-index.
643 0 : static void UpdateNativeWidgetZIndexes(nsView* aView, PRInt32 aZIndex)
644 : {
645 0 : if (aView->HasWidget()) {
646 0 : nsIWidget* widget = aView->GetWidget();
647 : PRInt32 curZ;
648 0 : widget->GetZIndex(&curZ);
649 0 : if (curZ != aZIndex) {
650 0 : widget->SetZIndex(aZIndex);
651 : }
652 : } else {
653 0 : for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
654 0 : if (v->GetZIndexIsAuto()) {
655 0 : UpdateNativeWidgetZIndexes(v, aZIndex);
656 : }
657 : }
658 : }
659 0 : }
660 :
661 0 : static PRInt32 FindNonAutoZIndex(nsView* aView)
662 : {
663 0 : while (aView) {
664 0 : if (!aView->GetZIndexIsAuto()) {
665 0 : return aView->GetZIndex();
666 : }
667 0 : aView = aView->GetParent();
668 : }
669 0 : return 0;
670 : }
671 :
672 0 : nsresult nsIView::CreateWidget(nsWidgetInitData *aWidgetInitData,
673 : bool aEnableDragDrop,
674 : bool aResetVisibility)
675 : {
676 : return Impl()->CreateWidget(aWidgetInitData,
677 0 : aEnableDragDrop, aResetVisibility);
678 : }
679 :
680 0 : nsresult nsIView::CreateWidgetForParent(nsIWidget* aParentWidget,
681 : nsWidgetInitData *aWidgetInitData,
682 : bool aEnableDragDrop,
683 : bool aResetVisibility)
684 : {
685 : return Impl()->CreateWidgetForParent(aParentWidget, aWidgetInitData,
686 0 : aEnableDragDrop, aResetVisibility);
687 : }
688 :
689 0 : nsresult nsIView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData,
690 : nsIWidget* aParentWidget,
691 : bool aEnableDragDrop,
692 : bool aResetVisibility)
693 : {
694 : return Impl()->CreateWidgetForPopup(aWidgetInitData, aParentWidget,
695 0 : aEnableDragDrop, aResetVisibility);
696 : }
697 :
698 0 : void nsIView::DestroyWidget()
699 : {
700 0 : Impl()->DestroyWidget();
701 0 : }
702 :
703 : struct DefaultWidgetInitData : public nsWidgetInitData {
704 0 : DefaultWidgetInitData() : nsWidgetInitData()
705 : {
706 0 : mWindowType = eWindowType_child;
707 0 : clipChildren = true;
708 0 : clipSiblings = true;
709 0 : }
710 : };
711 :
712 0 : nsresult nsView::CreateWidget(nsWidgetInitData *aWidgetInitData,
713 : bool aEnableDragDrop,
714 : bool aResetVisibility)
715 : {
716 0 : AssertNoWindow();
717 0 : NS_ABORT_IF_FALSE(!aWidgetInitData ||
718 : aWidgetInitData->mWindowType != eWindowType_popup,
719 : "Use CreateWidgetForPopup");
720 :
721 0 : DefaultWidgetInitData defaultInitData;
722 0 : bool initDataPassedIn = !!aWidgetInitData;
723 0 : aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData;
724 : defaultInitData.mListenForResizes =
725 0 : (!initDataPassedIn && GetParent() &&
726 0 : GetParent()->GetViewManager() != mViewManager);
727 :
728 0 : nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType);
729 :
730 0 : nsRefPtr<nsDeviceContext> dx;
731 0 : mViewManager->GetDeviceContext(*getter_AddRefs(dx));
732 :
733 : nsIWidget* parentWidget =
734 0 : GetParent() ? GetParent()->GetNearestWidget(nsnull) : nsnull;
735 0 : if (!parentWidget) {
736 0 : NS_ERROR("nsView::CreateWidget without suitable parent widget??");
737 0 : return NS_ERROR_FAILURE;
738 : }
739 :
740 : // XXX: using aForceUseIWidgetParent=true to preserve previous
741 : // semantics. It's not clear that it's actually needed.
742 : mWindow = parentWidget->CreateChild(trect, ::HandleEvent,
743 : dx, aWidgetInitData,
744 0 : true).get();
745 0 : if (!mWindow) {
746 0 : return NS_ERROR_FAILURE;
747 : }
748 :
749 0 : InitializeWindow(aEnableDragDrop, aResetVisibility);
750 :
751 0 : return NS_OK;
752 : }
753 :
754 0 : nsresult nsView::CreateWidgetForParent(nsIWidget* aParentWidget,
755 : nsWidgetInitData *aWidgetInitData,
756 : bool aEnableDragDrop,
757 : bool aResetVisibility)
758 : {
759 0 : AssertNoWindow();
760 0 : NS_ABORT_IF_FALSE(!aWidgetInitData ||
761 : aWidgetInitData->mWindowType != eWindowType_popup,
762 : "Use CreateWidgetForPopup");
763 0 : NS_ABORT_IF_FALSE(aParentWidget, "Parent widget required");
764 :
765 0 : DefaultWidgetInitData defaultInitData;
766 0 : aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData;
767 :
768 0 : nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType);
769 :
770 0 : nsRefPtr<nsDeviceContext> dx;
771 0 : mViewManager->GetDeviceContext(*getter_AddRefs(dx));
772 :
773 : mWindow =
774 : aParentWidget->CreateChild(trect, ::HandleEvent,
775 0 : dx, aWidgetInitData).get();
776 0 : if (!mWindow) {
777 0 : return NS_ERROR_FAILURE;
778 : }
779 :
780 0 : InitializeWindow(aEnableDragDrop, aResetVisibility);
781 :
782 0 : return NS_OK;
783 : }
784 :
785 0 : nsresult nsView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData,
786 : nsIWidget* aParentWidget,
787 : bool aEnableDragDrop,
788 : bool aResetVisibility)
789 : {
790 0 : AssertNoWindow();
791 0 : NS_ABORT_IF_FALSE(aWidgetInitData, "Widget init data required");
792 0 : NS_ABORT_IF_FALSE(aWidgetInitData->mWindowType == eWindowType_popup,
793 : "Use one of the other CreateWidget methods");
794 :
795 0 : nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType);
796 :
797 0 : nsRefPtr<nsDeviceContext> dx;
798 0 : mViewManager->GetDeviceContext(*getter_AddRefs(dx));
799 :
800 : // XXX/cjones: having these two separate creation cases seems ... um
801 : // ... unnecessary, but it's the way the old code did it. Please
802 : // unify them by first finding a suitable parent nsIWidget, then
803 : // getting rid of aForceUseIWidgetParent.
804 0 : if (aParentWidget) {
805 : // XXX: using aForceUseIWidgetParent=true to preserve previous
806 : // semantics. It's not clear that it's actually needed.
807 : mWindow = aParentWidget->CreateChild(trect, ::HandleEvent,
808 : dx, aWidgetInitData,
809 0 : true).get();
810 : }
811 : else {
812 0 : nsIWidget* nearestParent = GetParent() ? GetParent()->GetNearestWidget(nsnull)
813 0 : : nsnull;
814 0 : if (!nearestParent) {
815 : // Without a parent, we can't make a popup. This can happen
816 : // when printing
817 0 : return NS_ERROR_FAILURE;
818 : }
819 :
820 : mWindow =
821 : nearestParent->CreateChild(trect, ::HandleEvent,
822 0 : dx, aWidgetInitData).get();
823 : }
824 0 : if (!mWindow) {
825 0 : return NS_ERROR_FAILURE;
826 : }
827 :
828 0 : InitializeWindow(aEnableDragDrop, aResetVisibility);
829 :
830 0 : return NS_OK;
831 : }
832 :
833 : void
834 0 : nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility)
835 : {
836 0 : NS_ABORT_IF_FALSE(mWindow, "Must have a window to initialize");
837 :
838 0 : ViewWrapper* wrapper = new ViewWrapper(this);
839 0 : NS_ADDREF(wrapper); // Will be released in ~nsView
840 0 : mWindow->SetClientData(wrapper);
841 :
842 0 : if (aEnableDragDrop) {
843 0 : mWindow->EnableDragDrop(true);
844 : }
845 :
846 : // propagate the z-index to the widget.
847 0 : UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
848 :
849 : //make sure visibility state is accurate
850 :
851 0 : if (aResetVisibility) {
852 0 : SetVisibility(GetVisibility());
853 : }
854 0 : }
855 :
856 : // Attach to a top level widget and start receiving mirrored events.
857 0 : nsresult nsIView::AttachToTopLevelWidget(nsIWidget* aWidget)
858 : {
859 0 : NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
860 : /// XXXjimm This is a temporary workaround to an issue w/document
861 : // viewer (bug 513162).
862 0 : nsIView *oldView = GetAttachedViewFor(aWidget);
863 0 : if (oldView) {
864 0 : oldView->DetachFromTopLevelWidget();
865 : }
866 :
867 0 : nsRefPtr<nsDeviceContext> dx;
868 0 : mViewManager->GetDeviceContext(*getter_AddRefs(dx));
869 :
870 : // Note, the previous device context will be released. Detaching
871 : // will not restore the old one.
872 : nsresult rv = aWidget->AttachViewToTopLevel(
873 0 : nsIWidget::UsePuppetWidgets() ? ::HandleEvent : ::AttachedHandleEvent, dx);
874 0 : if (NS_FAILED(rv))
875 0 : return rv;
876 :
877 0 : mWindow = aWidget;
878 0 : NS_ADDREF(mWindow);
879 :
880 0 : ViewWrapper* wrapper = new ViewWrapper(Impl());
881 0 : NS_ADDREF(wrapper);
882 0 : mWindow->SetAttachedViewPtr(wrapper);
883 0 : mWindow->EnableDragDrop(true);
884 0 : mWidgetIsTopLevel = true;
885 :
886 : // Refresh the view bounds
887 : nsWindowType type;
888 0 : mWindow->GetWindowType(type);
889 0 : CalcWidgetBounds(type);
890 :
891 0 : return NS_OK;
892 : }
893 :
894 : // Detach this view from an attached widget.
895 0 : nsresult nsIView::DetachFromTopLevelWidget()
896 : {
897 0 : NS_PRECONDITION(mWidgetIsTopLevel, "Not attached currently!");
898 0 : NS_PRECONDITION(mWindow, "null mWindow for DetachFromTopLevelWidget!");
899 :
900 : // Release memory for the view wrapper
901 0 : ViewWrapper* wrapper = GetAttachedWrapperFor(mWindow);
902 0 : NS_IF_RELEASE(wrapper);
903 :
904 0 : mWindow->SetAttachedViewPtr(nsnull);
905 0 : NS_RELEASE(mWindow);
906 :
907 0 : mWidgetIsTopLevel = false;
908 :
909 0 : return NS_OK;
910 : }
911 :
912 0 : void nsView::SetZIndex(bool aAuto, PRInt32 aZIndex, bool aTopMost)
913 : {
914 0 : bool oldIsAuto = GetZIndexIsAuto();
915 0 : mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0);
916 0 : mZIndex = aZIndex;
917 0 : SetTopMost(aTopMost);
918 :
919 0 : if (HasWidget() || !oldIsAuto || !aAuto) {
920 0 : UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
921 : }
922 0 : }
923 :
924 0 : void nsView::AssertNoWindow()
925 : {
926 : // XXX: it would be nice to make this a strong assert
927 0 : if (NS_UNLIKELY(mWindow)) {
928 0 : NS_ERROR("We already have a window for this view? BAD");
929 0 : ViewWrapper* wrapper = GetWrapperFor(mWindow);
930 0 : NS_IF_RELEASE(wrapper);
931 0 : mWindow->SetClientData(nsnull);
932 0 : mWindow->Destroy();
933 0 : NS_RELEASE(mWindow);
934 : }
935 0 : }
936 :
937 : //
938 : // internal window creation functions
939 : //
940 0 : EVENT_CALLBACK nsIView::AttachWidgetEventHandler(nsIWidget* aWidget)
941 : {
942 : #ifdef DEBUG
943 0 : void* data = nsnull;
944 0 : aWidget->GetClientData(data);
945 0 : NS_ASSERTION(!data, "Already got client data");
946 : #endif
947 :
948 0 : ViewWrapper* wrapper = new ViewWrapper(Impl());
949 0 : if (!wrapper)
950 0 : return nsnull;
951 0 : NS_ADDREF(wrapper); // Will be released in DetachWidgetEventHandler
952 0 : aWidget->SetClientData(wrapper);
953 0 : return ::HandleEvent;
954 : }
955 :
956 0 : void nsIView::DetachWidgetEventHandler(nsIWidget* aWidget)
957 : {
958 0 : ViewWrapper* wrapper = GetWrapperFor(aWidget);
959 0 : NS_ASSERTION(!wrapper || wrapper->GetView() == this, "Wrong view");
960 0 : NS_IF_RELEASE(wrapper);
961 0 : aWidget->SetClientData(nsnull);
962 0 : }
963 :
964 : #ifdef DEBUG
965 0 : void nsIView::List(FILE* out, PRInt32 aIndent) const
966 : {
967 : PRInt32 i;
968 0 : for (i = aIndent; --i >= 0; ) fputs(" ", out);
969 0 : fprintf(out, "%p ", (void*)this);
970 0 : if (nsnull != mWindow) {
971 0 : nscoord p2a = mViewManager->AppUnitsPerDevPixel();
972 0 : nsIntRect rect;
973 0 : mWindow->GetClientBounds(rect);
974 0 : nsRect windowBounds = rect.ToAppUnits(p2a);
975 0 : mWindow->GetBounds(rect);
976 0 : nsRect nonclientBounds = rect.ToAppUnits(p2a);
977 0 : nsrefcnt widgetRefCnt = mWindow->AddRef() - 1;
978 0 : mWindow->Release();
979 : PRInt32 Z;
980 0 : mWindow->GetZIndex(&Z);
981 : fprintf(out, "(widget=%p[%d] z=%d pos={%d,%d,%d,%d}) ",
982 : (void*)mWindow, widgetRefCnt, Z,
983 : nonclientBounds.x, nonclientBounds.y,
984 0 : windowBounds.width, windowBounds.height);
985 : }
986 0 : nsRect brect = GetBounds();
987 : fprintf(out, "{%d,%d,%d,%d}",
988 0 : brect.x, brect.y, brect.width, brect.height);
989 : fprintf(out, " z=%d vis=%d frame=%p <\n",
990 0 : mZIndex, mVis, mFrame);
991 0 : for (nsView* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
992 0 : NS_ASSERTION(kid->GetParent() == this, "incorrect parent");
993 0 : kid->List(out, aIndent + 1);
994 : }
995 0 : for (i = aIndent; --i >= 0; ) fputs(" ", out);
996 0 : fputs(">\n", out);
997 0 : }
998 : #endif // DEBUG
999 :
1000 0 : nsPoint nsIView::GetOffsetTo(const nsIView* aOther) const
1001 : {
1002 : return Impl()->GetOffsetTo(static_cast<const nsView*>(aOther),
1003 0 : Impl()->GetViewManager()->AppUnitsPerDevPixel());
1004 : }
1005 :
1006 0 : nsPoint nsView::GetOffsetTo(const nsView* aOther) const
1007 : {
1008 0 : return GetOffsetTo(aOther, GetViewManager()->AppUnitsPerDevPixel());
1009 : }
1010 :
1011 0 : nsPoint nsView::GetOffsetTo(const nsView* aOther, const PRInt32 aAPD) const
1012 : {
1013 0 : NS_ABORT_IF_FALSE(GetParent() || !aOther || aOther->GetParent() ||
1014 : this == aOther, "caller of (outer) GetOffsetTo must not "
1015 : "pass unrelated views");
1016 : // We accumulate the final result in offset
1017 0 : nsPoint offset(0, 0);
1018 : // The offset currently accumulated at the current APD
1019 0 : nsPoint docOffset(0, 0);
1020 0 : const nsView* v = this;
1021 0 : nsViewManager* currVM = v->GetViewManager();
1022 0 : PRInt32 currAPD = currVM->AppUnitsPerDevPixel();
1023 0 : const nsView* root = nsnull;
1024 0 : for ( ; v != aOther && v; root = v, v = v->GetParent()) {
1025 0 : nsViewManager* newVM = v->GetViewManager();
1026 0 : if (newVM != currVM) {
1027 0 : PRInt32 newAPD = newVM->AppUnitsPerDevPixel();
1028 0 : if (newAPD != currAPD) {
1029 0 : offset += docOffset.ConvertAppUnits(currAPD, aAPD);
1030 0 : docOffset.x = docOffset.y = 0;
1031 0 : currAPD = newAPD;
1032 : }
1033 0 : currVM = newVM;
1034 : }
1035 0 : docOffset += v->GetPosition();
1036 : }
1037 0 : offset += docOffset.ConvertAppUnits(currAPD, aAPD);
1038 :
1039 0 : if (v != aOther) {
1040 : // Looks like aOther wasn't an ancestor of |this|. So now we have
1041 : // the root-VM-relative position of |this| in |offset|. Get the
1042 : // root-VM-relative position of aOther and subtract it.
1043 0 : nsPoint negOffset = aOther->GetOffsetTo(root, aAPD);
1044 0 : offset -= negOffset;
1045 : }
1046 :
1047 : return offset;
1048 : }
1049 :
1050 0 : nsPoint nsIView::GetOffsetToWidget(nsIWidget* aWidget) const
1051 : {
1052 0 : nsPoint pt;
1053 : // Get the view for widget
1054 0 : nsIView* widgetIView = GetViewFor(aWidget);
1055 0 : if (!widgetIView) {
1056 0 : return pt;
1057 : }
1058 0 : nsView* widgetView = widgetIView->Impl();
1059 :
1060 : // Get the offset to the widget view in the widget view's APD
1061 : // We get the offset in the widget view's APD first and then convert to our
1062 : // APD afterwards so that we can include the widget view's ViewToWidgetOffset
1063 : // in the sum in its native APD, and then convert the whole thing to our APD
1064 : // so that we don't have to convert the APD of the relatively small
1065 : // ViewToWidgetOffset by itself with a potentially large relative rounding
1066 : // error.
1067 0 : pt = -widgetView->GetOffsetTo(static_cast<const nsView*>(this));
1068 : // Add in the offset to the widget.
1069 0 : pt += widgetView->ViewToWidgetOffset();
1070 :
1071 : // Convert to our appunits.
1072 0 : PRInt32 widgetAPD = widgetView->GetViewManager()->AppUnitsPerDevPixel();
1073 : PRInt32 ourAPD = static_cast<const nsView*>(this)->
1074 0 : GetViewManager()->AppUnitsPerDevPixel();
1075 0 : pt = pt.ConvertAppUnits(widgetAPD, ourAPD);
1076 0 : return pt;
1077 : }
1078 :
1079 0 : nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
1080 : {
1081 : return Impl()->GetNearestWidget(aOffset,
1082 0 : Impl()->GetViewManager()->AppUnitsPerDevPixel());
1083 : }
1084 :
1085 0 : nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset) const
1086 : {
1087 0 : return GetNearestWidget(aOffset, GetViewManager()->AppUnitsPerDevPixel());
1088 : }
1089 :
1090 0 : nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset, const PRInt32 aAPD) const
1091 : {
1092 : // aOffset is based on the view's position, which ignores any chrome on
1093 : // attached parent widgets.
1094 :
1095 : // We accumulate the final result in pt
1096 0 : nsPoint pt(0, 0);
1097 : // The offset currently accumulated at the current APD
1098 0 : nsPoint docPt(0,0);
1099 0 : const nsView* v = this;
1100 0 : nsViewManager* currVM = v->GetViewManager();
1101 0 : PRInt32 currAPD = currVM->AppUnitsPerDevPixel();
1102 0 : for ( ; v && !v->HasWidget(); v = v->GetParent()) {
1103 0 : nsViewManager* newVM = v->GetViewManager();
1104 0 : if (newVM != currVM) {
1105 0 : PRInt32 newAPD = newVM->AppUnitsPerDevPixel();
1106 0 : if (newAPD != currAPD) {
1107 0 : pt += docPt.ConvertAppUnits(currAPD, aAPD);
1108 0 : docPt.x = docPt.y = 0;
1109 0 : currAPD = newAPD;
1110 : }
1111 0 : currVM = newVM;
1112 : }
1113 0 : docPt += v->GetPosition();
1114 : }
1115 0 : if (!v) {
1116 0 : if (aOffset) {
1117 0 : pt += docPt.ConvertAppUnits(currAPD, aAPD);
1118 0 : *aOffset = pt;
1119 : }
1120 0 : return nsnull;
1121 : }
1122 :
1123 : // pt is now the offset from v's origin to this view's origin.
1124 : // We add the ViewToWidgetOffset to get the offset to the widget.
1125 0 : if (aOffset) {
1126 0 : docPt += v->ViewToWidgetOffset();
1127 0 : pt += docPt.ConvertAppUnits(currAPD, aAPD);
1128 0 : *aOffset = pt;
1129 : }
1130 0 : return v->GetWidget();
1131 : }
1132 :
1133 0 : bool nsIView::IsRoot() const
1134 : {
1135 0 : NS_ASSERTION(mViewManager != nsnull," View manager is null in nsView::IsRoot()");
1136 0 : return mViewManager->GetRootViewImpl() == this;
1137 : }
1138 :
1139 0 : bool nsIView::ExternalIsRoot() const
1140 : {
1141 0 : return nsIView::IsRoot();
1142 : }
1143 :
1144 : void
1145 0 : nsIView::SetDeletionObserver(nsWeakView* aDeletionObserver)
1146 : {
1147 0 : if (mDeletionObserver && aDeletionObserver) {
1148 0 : aDeletionObserver->SetPrevious(mDeletionObserver);
1149 : }
1150 0 : mDeletionObserver = aDeletionObserver;
1151 0 : }
1152 :
1153 : nsView*
1154 0 : nsIView::Impl()
1155 : {
1156 0 : return static_cast<nsView*>(this);
1157 : }
1158 :
1159 : const nsView*
1160 0 : nsIView::Impl() const
1161 : {
1162 0 : return static_cast<const nsView*>(this);
1163 : }
1164 :
1165 : nsRect
1166 0 : nsView::GetBoundsInParentUnits() const
1167 : {
1168 0 : nsView* parent = GetParent();
1169 0 : nsViewManager* VM = GetViewManager();
1170 0 : if (this != VM->GetRootViewImpl() || !parent) {
1171 0 : return mDimBounds;
1172 : }
1173 0 : PRInt32 ourAPD = VM->AppUnitsPerDevPixel();
1174 0 : PRInt32 parentAPD = parent->GetViewManager()->AppUnitsPerDevPixel();
1175 0 : return mDimBounds.ConvertAppUnitsRoundOut(ourAPD, parentAPD);
1176 : }
1177 :
1178 : nsPoint
1179 0 : nsIView::ConvertFromParentCoords(nsPoint aPt) const
1180 : {
1181 0 : const nsView* view = static_cast<const nsView*>(this);
1182 0 : const nsView* parent = view->GetParent();
1183 0 : if (parent) {
1184 0 : aPt = aPt.ConvertAppUnits(parent->GetViewManager()->AppUnitsPerDevPixel(),
1185 0 : view->GetViewManager()->AppUnitsPerDevPixel());
1186 : }
1187 0 : aPt -= GetPosition();
1188 0 : return aPt;
1189 : }
|