xref: /haiku/src/servers/app/View.cpp (revision 04d1d2da0b27294f0f1e623071df310a0820d4b6)
1 /*
2  * Copyright (c) 2001-2015, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Adi Oanca <adioanca@gmail.com>
8  *		Axel Dörfler, axeld@pinc-software.de
9  *		Stephan Aßmus <superstippi@gmx.de>
10  *		Marcus Overhagen <marcus@overhagen.de>
11  *		Adrien Destugues <pulkomandy@pulkomandy.tk
12  *		Julian Harnath <julian.harnath@rwth-aachen.de>
13  *		Joseph Groover <looncraz@looncraz.net>
14  */
15 #include "View.h"
16 
17 #include <new>
18 #include <stdio.h>
19 
20 #include "AlphaMask.h"
21 #include "Desktop.h"
22 #include "DrawingEngine.h"
23 #include "DrawState.h"
24 #include "Layer.h"
25 #include "Overlay.h"
26 #include "ServerApp.h"
27 #include "ServerBitmap.h"
28 #include "ServerCursor.h"
29 #include "ServerPicture.h"
30 #include "ServerWindow.h"
31 #include "Window.h"
32 
33 #include "BitmapHWInterface.h"
34 #include "drawing_support.h"
35 
36 #include <List.h>
37 #include <Message.h>
38 #include <PortLink.h>
39 #include <View.h> // for resize modes
40 #include <WindowPrivate.h>
41 
42 #include <GradientLinear.h>
43 #include <GradientRadial.h>
44 #include <GradientRadialFocus.h>
45 #include <GradientDiamond.h>
46 #include <GradientConic.h>
47 
48 
49 using std::nothrow;
50 
51 
52 void
53 resize_frame(IntRect& frame, uint32 resizingMode, int32 x, int32 y)
54 {
55 	// follow with left side
56 	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
57 		frame.left += x;
58 	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
59 		frame.left += x / 2;
60 
61 	// follow with right side
62 	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
63 		frame.right += x;
64 	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
65 		frame.right += x / 2;
66 
67 	// follow with top side
68 	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
69 		frame.top += y;
70 	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
71 		frame.top += y / 2;
72 
73 	// follow with bottom side
74 	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
75 		frame.bottom += y;
76 	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
77 		frame.bottom += y / 2;
78 }
79 
80 
81 //	#pragma mark -
82 
83 
84 View::View(IntRect frame, IntPoint scrollingOffset, const char* name,
85 		int32 token, uint32 resizeMode, uint32 flags)
86 	:
87 	fName(name),
88 	fToken(token),
89 
90 	fFrame(frame),
91 	fScrollingOffset(scrollingOffset),
92 
93 	fViewColor((rgb_color){ 255, 255, 255, 255 }),
94 	fWhichViewColor(B_NO_COLOR),
95 	fWhichViewColorTint(B_NO_TINT),
96 	fViewBitmap(NULL),
97 	fBitmapResizingMode(0),
98 	fBitmapOptions(0),
99 
100 	fResizeMode(resizeMode),
101 	fFlags(flags),
102 
103 	// Views start visible by default
104 	fHidden(false),
105 	fVisible(true),
106 	fBackgroundDirty(true),
107 	fIsDesktopBackground(false),
108 
109 	fEventMask(0),
110 	fEventOptions(0),
111 
112 	fWindow(NULL),
113 	fParent(NULL),
114 
115 	fFirstChild(NULL),
116 	fPreviousSibling(NULL),
117 	fNextSibling(NULL),
118 	fLastChild(NULL),
119 
120 	fCursor(NULL),
121 	fPicture(NULL),
122 
123 	fLocalClipping((BRect)Bounds()),
124 	fScreenClipping(),
125 	fScreenClippingValid(false),
126 	fUserClipping(NULL),
127 	fScreenAndUserClipping(NULL)
128 {
129 	if (fDrawState)
130 		fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
131 }
132 
133 
134 View::~View()
135 {
136 	if (fViewBitmap != NULL)
137 		fViewBitmap->ReleaseReference();
138 
139 	delete fScreenAndUserClipping;
140 	delete fUserClipping;
141 	delete fDrawState;
142 
143 //	if (fWindow && this == fWindow->TopView())
144 //		fWindow->SetTopView(NULL);
145 
146 	if (fCursor)
147 		fCursor->ReleaseReference();
148 
149 	// iterate over children and delete each one
150 	View* view = fFirstChild;
151 	while (view) {
152 		View* toast = view;
153 		view = view->fNextSibling;
154 		delete toast;
155 	}
156 }
157 
158 
159 IntRect
160 View::Bounds() const
161 {
162 	IntRect bounds(fScrollingOffset.x, fScrollingOffset.y,
163 		fScrollingOffset.x + fFrame.Width(),
164 		fScrollingOffset.y + fFrame.Height());
165 	return bounds;
166 }
167 
168 
169 void
170 View::ConvertToVisibleInTopView(IntRect* bounds) const
171 {
172 	*bounds = *bounds & Bounds();
173 	// NOTE: this step is necessary even if we don't have a parent!
174 	bounds->OffsetBy(fFrame.left - fScrollingOffset.x,
175 		fFrame.top - fScrollingOffset.y);
176 
177 	if (fParent)
178 		fParent->ConvertToVisibleInTopView(bounds);
179 }
180 
181 
182 void
183 View::AttachedToWindow(::Window* window)
184 {
185 	fWindow = window;
186 
187 	// an ugly hack to detect the desktop background
188 	if (window->Feel() == kDesktopWindowFeel && Parent() == TopView())
189 		fIsDesktopBackground = true;
190 
191 	// insert view into local token space
192 	if (fWindow != NULL) {
193 		fWindow->ServerWindow()->App()->ViewTokens().SetToken(fToken,
194 			B_HANDLER_TOKEN, this);
195 	}
196 
197 	// attach child views as well
198 	for (View* child = FirstChild(); child; child = child->NextSibling())
199 		child->AttachedToWindow(window);
200 }
201 
202 
203 void
204 View::DetachedFromWindow()
205 {
206 	// remove view from local token space
207 	if (fWindow != NULL && fWindow->ServerWindow()->App() != NULL)
208 		fWindow->ServerWindow()->App()->ViewTokens().RemoveToken(fToken);
209 
210 	fWindow = NULL;
211 	// detach child views as well
212 	for (View* child = FirstChild(); child; child = child->NextSibling())
213 		child->DetachedFromWindow();
214 }
215 
216 
217 // #pragma mark -
218 
219 
220 DrawingEngine*
221 View::GetDrawingEngine() const
222 {
223 	return Window()->GetDrawingEngine();
224 }
225 
226 
227 ServerPicture*
228 View::GetPicture(int32 token) const
229 {
230 	return Window()->ServerWindow()->App()->GetPicture(token);
231 }
232 
233 
234 void
235 View::ResyncDrawState()
236 {
237 	return Window()->ServerWindow()->ResyncDrawState();
238 }
239 
240 
241 void
242 View::UpdateCurrentDrawingRegion()
243 {
244 	return Window()->ServerWindow()->UpdateCurrentDrawingRegion();
245 }
246 
247 
248 void
249 View::AddChild(View* view)
250 {
251 	if (view->fParent) {
252 		printf("View::AddChild() - View already has a parent\n");
253 		return;
254 	}
255 
256 	view->fParent = this;
257 
258 	if (!fLastChild) {
259 		// no children yet
260 		fFirstChild = view;
261 	} else {
262 		// append view to formerly last child
263 		fLastChild->fNextSibling = view;
264 		view->fPreviousSibling = fLastChild;
265 	}
266 	fLastChild = view;
267 
268 	view->UpdateVisibleDeep(fVisible);
269 
270 	if (view->IsVisible())
271 		RebuildClipping(false);
272 
273 	if (fWindow) {
274 		view->AttachedToWindow(fWindow);
275 
276 		if (view->IsVisible()) {
277 			// trigger redraw
278 			IntRect clippedFrame = view->Frame();
279 			ConvertToVisibleInTopView(&clippedFrame);
280 
281 			BRegion dirty;
282 			dirty.Set((clipping_rect)clippedFrame);
283 			fWindow->MarkContentDirtyAsync(dirty);
284 		}
285 	}
286 }
287 
288 
289 bool
290 View::RemoveChild(View* view)
291 {
292 	if (view == NULL || view->fParent != this) {
293 		printf("View::RemoveChild(%p - %s) - View is not child of "
294 			"this (%p) view!\n", view, view ? view->Name() : NULL, this);
295 		return false;
296 	}
297 
298 	view->fParent = NULL;
299 
300 	if (fLastChild == view)
301 		fLastChild = view->fPreviousSibling;
302 		// view->fNextSibling would be NULL
303 
304 	if (fFirstChild == view )
305 		fFirstChild = view->fNextSibling;
306 		// view->fPreviousSibling would be NULL
307 
308 	// connect child before and after view
309 	if (view->fPreviousSibling)
310 		view->fPreviousSibling->fNextSibling = view->fNextSibling;
311 
312 	if (view->fNextSibling)
313 		view->fNextSibling->fPreviousSibling = view->fPreviousSibling;
314 
315 	// view has no siblings anymore
316 	view->fPreviousSibling = NULL;
317 	view->fNextSibling = NULL;
318 
319 	if (view->IsVisible()) {
320 		Overlay* overlay = view->_Overlay();
321 		if (overlay != NULL)
322 			overlay->Hide();
323 
324 		RebuildClipping(false);
325 	}
326 
327 	if (fWindow) {
328 		view->DetachedFromWindow();
329 
330 		if (fVisible && view->IsVisible()) {
331 			// trigger redraw
332 			IntRect clippedFrame = view->Frame();
333 			ConvertToVisibleInTopView(&clippedFrame);
334 
335 			BRegion dirty;
336 			dirty.Set((clipping_rect)clippedFrame);
337 			fWindow->MarkContentDirtyAsync(dirty);
338 		}
339 	}
340 
341 	return true;
342 }
343 
344 
345 View*
346 View::TopView()
347 {
348 	// returns the top level view of the hirarchy,
349 	// it doesn't have to be the top level of a window
350 
351 	if (fParent)
352 		return fParent->TopView();
353 
354 	return this;
355 }
356 
357 
358 uint32
359 View::CountChildren(bool deep) const
360 {
361 	uint32 count = 0;
362 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
363 		count++;
364 		if (deep) {
365 			count += child->CountChildren(deep);
366 		}
367 	}
368 	return count;
369 }
370 
371 
372 void
373 View::CollectTokensForChildren(BList* tokenMap) const
374 {
375 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
376 		tokenMap->AddItem((void*)child);
377 		child->CollectTokensForChildren(tokenMap);
378 	}
379 }
380 
381 
382 #if 0
383 bool
384 View::MarkAt(DrawingEngine* engine, const BPoint& where, int32 level)
385 {
386 	BRect rect(fFrame.left, fFrame.top, fFrame.right, fFrame.bottom);
387 
388 	if (Parent() != NULL) {
389 		Parent()->ConvertToScreen(&rect);
390 		if (!rect.Contains(where))
391 			return false;
392 
393 		engine->StrokeRect(rect, (rgb_color){level * 30, level * 30, level * 30});
394 	}
395 
396 
397 	bool found = false;
398 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
399 		found |= child->MarkAt(engine, where, level + 1);
400 	}
401 
402 	if (!found) {
403 		rgb_color color = {0};
404 		switch (level % 2) {
405 			case 0: color.green = rand() % 256; break;
406 			case 1: color.blue = rand() % 256; break;
407 		}
408 
409 		rect.InsetBy(1, 1);
410 		//engine->FillRegion(fLocalClipping, (rgb_color){255, 255, 0, 10});
411 		engine->StrokeRect(rect, color);
412 		rect.InsetBy(1, 1);
413 		engine->StrokeRect(rect, color);
414 	}
415 
416 	return true;
417 }
418 #endif
419 
420 
421 void
422 View::FindViews(uint32 flags, BObjectList<View>& list, int32& left)
423 {
424 	if ((Flags() & flags) == flags) {
425 		list.AddItem(this);
426 		left--;
427 		return;
428 	}
429 
430 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
431 		child->FindViews(flags, list, left);
432 		if (left == 0)
433 			break;
434 	}
435 }
436 
437 
438 bool
439 View::HasView(View* view)
440 {
441 	if (view == this)
442 		return true;
443 
444 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
445 		if (child->HasView(view))
446 			return true;
447 	}
448 
449 	return false;
450 }
451 
452 
453 View*
454 View::ViewAt(const BPoint& where)
455 {
456 	if (!fVisible)
457 		return NULL;
458 
459 	IntRect frame = Frame();
460 	if (Parent() != NULL)
461 		Parent()->LocalToScreenTransform().Apply(&frame);
462 
463 	if (!frame.Contains(where))
464 		return NULL;
465 
466 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
467 		View* view = child->ViewAt(where);
468 		if (view != NULL)
469 			return view;
470 	}
471 
472 	return this;
473 }
474 
475 
476 // #pragma mark -
477 
478 
479 void
480 View::SetName(const char* string)
481 {
482 	fName.SetTo(string);
483 }
484 
485 
486 void
487 View::SetFlags(uint32 flags)
488 {
489 	uint32 oldFlags = fFlags;
490 	fFlags = flags;
491 
492 	// Child view with B_TRANSPARENT_BACKGROUND flag change clipping of
493 	// parent view.
494 	if (fParent != NULL
495 		&& IsVisible()
496 		&& (((oldFlags & B_TRANSPARENT_BACKGROUND) != 0)
497 			!= ((fFlags & B_TRANSPARENT_BACKGROUND) != 0))) {
498 		fParent->RebuildClipping(false);
499 	}
500 
501 	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
502 }
503 
504 
505 void
506 View::SetViewBitmap(ServerBitmap* bitmap, IntRect sourceRect,
507 	IntRect destRect, int32 resizingMode, int32 options)
508 {
509 	if (fViewBitmap != NULL) {
510 		Overlay* overlay = _Overlay();
511 
512 		if (bitmap != NULL) {
513 			// take over overlay token from current overlay (if it has any)
514 			Overlay* newOverlay = bitmap->Overlay();
515 
516 			if (overlay != NULL && newOverlay != NULL)
517 				newOverlay->TakeOverToken(overlay);
518 		} else if (overlay != NULL)
519 			overlay->Hide();
520 
521 		fViewBitmap->ReleaseReference();
522 	}
523 
524 	// the caller is allowed to delete the bitmap after setting the background
525 	if (bitmap != NULL)
526 		bitmap->AcquireReference();
527 
528 	fViewBitmap = bitmap;
529 	fBitmapSource = sourceRect;
530 	fBitmapDestination = destRect;
531 	fBitmapResizingMode = resizingMode;
532 	fBitmapOptions = options;
533 
534 	_UpdateOverlayView();
535 }
536 
537 
538 ::Overlay*
539 View::_Overlay() const
540 {
541 	if (fViewBitmap == NULL)
542 		return NULL;
543 
544 	return fViewBitmap->Overlay();
545 }
546 
547 
548 void
549 View::_UpdateOverlayView() const
550 {
551 	Overlay* overlay = _Overlay();
552 	if (overlay == NULL)
553 		return;
554 
555 	IntRect destination = fBitmapDestination;
556 	LocalToScreenTransform().Apply(&destination);
557 
558 	overlay->Configure(fBitmapSource, destination);
559 }
560 
561 
562 /*!
563 	This method is called whenever the window is resized or moved - would
564 	be nice to have a better solution for this, though.
565 */
566 void
567 View::UpdateOverlay()
568 {
569 	if (!IsVisible())
570 		return;
571 
572 	if (_Overlay() != NULL) {
573 		_UpdateOverlayView();
574 	} else {
575 		// recursively ask children of this view
576 
577 		for (View* child = FirstChild(); child; child = child->NextSibling()) {
578 			child->UpdateOverlay();
579 		}
580 	}
581 }
582 
583 
584 // #pragma mark -
585 
586 
587 void
588 View::_LocalToScreenTransform(SimpleTransform& transform) const
589 {
590 	const View* view = this;
591 	int32 offsetX = 0;
592 	int32 offsetY = 0;
593 	do {
594 		offsetX += view->fFrame.left - view->fScrollingOffset.x;
595 		offsetY += view->fFrame.top  - view->fScrollingOffset.y;
596 		view = view->fParent;
597 	} while (view != NULL);
598 
599 	transform.AddOffset(offsetX, offsetY);
600 }
601 
602 
603 void
604 View::_ScreenToLocalTransform(SimpleTransform& transform) const
605 {
606 	const View* view = this;
607 	int32 offsetX = 0;
608 	int32 offsetY = 0;
609 	do {
610 		offsetX += view->fScrollingOffset.x - view->fFrame.left;
611 		offsetY += view->fScrollingOffset.y - view->fFrame.top;
612 		view = view->fParent;
613 	} while (view != NULL);
614 
615 	transform.AddOffset(offsetX, offsetY);
616 }
617 
618 
619 // #pragma mark -
620 
621 
622 void
623 View::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
624 {
625 	if (x == 0 && y == 0)
626 		return;
627 
628 	fFrame.OffsetBy(x, y);
629 
630 	// to move on screen, we must not be hidden and we must have a parent
631 	if (fVisible && fParent && dirtyRegion) {
632 #if 1
633 // based on redraw on new location
634 		// the place were we are now visible
635 		IntRect newVisibleBounds(Bounds());
636 		// we can use the frame of the old
637 		// local clipping to see which parts need invalidation
638 		IntRect oldVisibleBounds(newVisibleBounds);
639 		oldVisibleBounds.OffsetBy(-x, -y);
640 		LocalToScreenTransform().Apply(&oldVisibleBounds);
641 
642 		ConvertToVisibleInTopView(&newVisibleBounds);
643 
644 		dirtyRegion->Include((clipping_rect)oldVisibleBounds);
645 		// newVisibleBounds already is in screen coords
646 		dirtyRegion->Include((clipping_rect)newVisibleBounds);
647 #else
648 // blitting version, invalidates
649 // old contents
650 		IntRect oldVisibleBounds(Bounds());
651 		IntRect newVisibleBounds(oldVisibleBounds);
652 		oldVisibleBounds.OffsetBy(-x, -y);
653 		LocalToScreenTransform().Apply(&oldVisibleBounds);
654 
655 		// NOTE: using ConvertToVisibleInTopView()
656 		// instead of ConvertToScreen()! see below
657 		ConvertToVisibleInTopView(&newVisibleBounds);
658 
659 		newVisibleBounds.OffsetBy(-x, -y);
660 
661 		// clipping oldVisibleBounds to newVisibleBounds
662 		// makes sure we don't copy parts hidden under
663 		// parent views
664 		BRegion* region = fWindow->GetRegion();
665 		if (region) {
666 			region->Set(oldVisibleBounds & newVisibleBounds);
667 			fWindow->CopyContents(region, x, y);
668 
669 			region->Set(oldVisibleBounds);
670 			newVisibleBounds.OffsetBy(x, y);
671 			region->Exclude((clipping_rect)newVisibleBounds);
672 			dirtyRegion->Include(dirty);
673 
674 			fWindow->RecycleRegion(region);
675 		}
676 
677 #endif
678 	}
679 
680 	if (!fParent) {
681 		// the top view's screen clipping does not change,
682 		// because no parts are clipped away from parent
683 		// views
684 		_MoveScreenClipping(x, y, true);
685 	} else {
686 		// parts might have been revealed from underneath
687 		// the parent, or might now be hidden underneath
688 		// the parent, this is taken care of when building
689 		// the screen clipping
690 		InvalidateScreenClipping();
691 	}
692 }
693 
694 
695 void
696 View::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
697 {
698 	if (x == 0 && y == 0)
699 		return;
700 
701 	fFrame.right += x;
702 	fFrame.bottom += y;
703 
704 	if (fVisible && dirtyRegion) {
705 		IntRect oldBounds(Bounds());
706 		oldBounds.right -= x;
707 		oldBounds.bottom -= y;
708 
709 		BRegion* dirty = fWindow->GetRegion();
710 		if (!dirty)
711 			return;
712 
713 		dirty->Set((clipping_rect)Bounds());
714 		dirty->Include((clipping_rect)oldBounds);
715 
716 		if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) {
717 			// the dirty region is just the difference of
718 			// old and new bounds
719 			dirty->Exclude((clipping_rect)(oldBounds & Bounds()));
720 		}
721 
722 		InvalidateScreenClipping();
723 
724 		if (dirty->CountRects() > 0) {
725 			if ((fFlags & B_DRAW_ON_CHILDREN) == 0) {
726 				// exclude children, they are expected to
727 				// include their own dirty regions in ParentResized()
728 				for (View* child = FirstChild(); child;
729 						child = child->NextSibling()) {
730 					if (!child->IsVisible()
731 						|| (child->fFlags & B_TRANSPARENT_BACKGROUND) != 0) {
732 						continue;
733 					}
734 					IntRect previousChildVisible(
735 						child->Frame() & oldBounds & Bounds());
736 					if (dirty->Frame().Intersects(previousChildVisible)) {
737 						dirty->Exclude((clipping_rect)previousChildVisible);
738 					}
739 				}
740 			}
741 
742 			LocalToScreenTransform().Apply(dirty);
743 			dirtyRegion->Include(dirty);
744 		}
745 		fWindow->RecycleRegion(dirty);
746 	}
747 
748 	// layout the children
749 	for (View* child = FirstChild(); child; child = child->NextSibling())
750 		child->ParentResized(x, y, dirtyRegion);
751 
752 	// view bitmap
753 	if (fViewBitmap != NULL)
754 		resize_frame(fBitmapDestination, fBitmapResizingMode, x, y);
755 
756 	// at this point, children are at their new locations,
757 	// so we can rebuild the clipping
758 	// TODO: when the implementation of Hide() and Show() is
759 	// complete, see if this should be avoided
760 	RebuildClipping(false);
761 }
762 
763 
764 void
765 View::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
766 {
767 	IntRect newFrame = fFrame;
768 	resize_frame(newFrame, fResizeMode & 0x0000ffff, x, y);
769 
770 	if (newFrame != fFrame) {
771 		// careful, MoveBy will change fFrame
772 		int32 widthDiff = (int32)(newFrame.Width() - fFrame.Width());
773 		int32 heightDiff = (int32)(newFrame.Height() - fFrame.Height());
774 
775 		MoveBy(newFrame.left - fFrame.left,
776 			newFrame.top - fFrame.top, dirtyRegion);
777 
778 		ResizeBy(widthDiff, heightDiff, dirtyRegion);
779 	} else {
780 		// TODO: this covers the fact that our screen clipping might change
781 		// when the parent changes its size, even though our frame stays
782 		// the same - there might be a way to test for this, but axeld doesn't
783 		// know, stippi should look into this when he's back :)
784 		InvalidateScreenClipping();
785 	}
786 }
787 
788 
789 void
790 View::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
791 {
792 	if (!fVisible || !fWindow) {
793 		fScrollingOffset.x += x;
794 		fScrollingOffset.y += y;
795 		return;
796 	}
797 
798 	// blitting version, invalidates
799 	// old contents
800 
801 	// remember old bounds for tracking dirty region
802 	IntRect oldBounds(Bounds());
803 
804 	// NOTE: using ConvertToVisibleInTopView()
805 	// instead of ConvertToScreen(), this makes
806 	// sure we don't try to move or invalidate an
807 	// area hidden underneath the parent view
808 	ConvertToVisibleInTopView(&oldBounds);
809 
810 	// find the area of the view that can be scrolled,
811 	// contents are shifted in the opposite direction from scrolling
812 	IntRect stillVisibleBounds(oldBounds);
813 	stillVisibleBounds.OffsetBy(x, y);
814 	stillVisibleBounds = stillVisibleBounds & oldBounds;
815 
816 	fScrollingOffset.x += x;
817 	fScrollingOffset.y += y;
818 
819 	// do the blit, this will make sure
820 	// that other more complex dirty regions
821 	// are taken care of
822 	BRegion* copyRegion = fWindow->GetRegion();
823 	if (!copyRegion)
824 		return;
825 	copyRegion->Set((clipping_rect)stillVisibleBounds);
826 	fWindow->CopyContents(copyRegion, -x, -y);
827 
828 	// find the dirty region as far as we are
829 	// concerned
830 	BRegion* dirty = copyRegion;
831 		// reuse copyRegion and call it dirty
832 
833 	dirty->Set((clipping_rect)oldBounds);
834 	stillVisibleBounds.OffsetBy(-x, -y);
835 	dirty->Exclude((clipping_rect)stillVisibleBounds);
836 	dirtyRegion->Include(dirty);
837 
838 	fWindow->RecycleRegion(dirty);
839 
840 	// the screen clipping of this view and it's
841 	// childs is no longer valid
842 	InvalidateScreenClipping();
843 	RebuildClipping(false);
844 }
845 
846 
847 void
848 View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping)
849 {
850 	if (!fVisible || !fWindow)
851 		return;
852 
853 	// TODO: figure out what to do when we have a transform which is not
854 	// a dilation
855 	BAffineTransform transform = CurrentState()->CombinedTransform();
856 	if (!transform.IsIdentity() && transform.IsDilation()) {
857 		BPoint points[4] = { src.LeftTop(), src.RightBottom(),
858 							 dst.LeftTop(), dst.RightBottom() };
859 		transform.Apply(&points[0], 4);
860 		src.Set(points[0].x, points[0].y, points[1].x, points[1].y);
861 		dst.Set(points[2].x, points[2].y, points[3].x, points[3].y);
862 	}
863 
864 	// TODO: confirm that in R5 this call is affected by origin and scale
865 
866 	// blitting version
867 
868 	int32 xOffset = dst.left - src.left;
869 	int32 yOffset = dst.top - src.top;
870 
871 	// figure out which part can be blittet
872 	IntRect visibleSrc(src);
873 	ConvertToVisibleInTopView(&visibleSrc);
874 
875 	IntRect visibleSrcAtDest(src);
876 	visibleSrcAtDest.OffsetBy(xOffset, yOffset);
877 	ConvertToVisibleInTopView(&visibleSrcAtDest);
878 
879 	// clip src to visible at dest
880 	visibleSrcAtDest.OffsetBy(-xOffset, -yOffset);
881 	visibleSrc = visibleSrc & visibleSrcAtDest;
882 
883 	// do the blit, this will make sure
884 	// that other more complex dirty regions
885 	// are taken care of
886 	BRegion* copyRegion = fWindow->GetRegion();
887 	if (!copyRegion)
888 		return;
889 
890 	// move src rect to destination here for efficiency reasons
891 	visibleSrc.OffsetBy(xOffset, yOffset);
892 
893 	// we need to interstect the copyRegion two times, onces
894 	// at the source and once at the destination (here done
895 	// the other way arround but it doesn't matter)
896 	// the reason for this is that we are not supposed to visually
897 	// copy children in the source rect and neither to copy onto
898 	// children in the destination rect...
899 	copyRegion->Set((clipping_rect)visibleSrc);
900 	BRegion *screenAndUserClipping
901 		= &ScreenAndUserClipping(&windowContentClipping);
902 	copyRegion->IntersectWith(screenAndUserClipping);
903 	copyRegion->OffsetBy(-xOffset, -yOffset);
904 	copyRegion->IntersectWith(screenAndUserClipping);
905 
906 	// do the actual blit
907 	fWindow->CopyContents(copyRegion, xOffset, yOffset);
908 
909 	// find the dirty region as far as we are concerned
910 	IntRect dirtyDst(dst);
911 	ConvertToVisibleInTopView(&dirtyDst);
912 
913 	BRegion* dirty = fWindow->GetRegion();
914 	if (!dirty) {
915 		fWindow->RecycleRegion(copyRegion);
916 		return;
917 	}
918 
919 	// offset copyRegion to destination again
920 	copyRegion->OffsetBy(xOffset, yOffset);
921 	// start with destination given by user
922 	dirty->Set((clipping_rect)dirtyDst);
923 	// exclude the part that we could copy
924 	dirty->Exclude(copyRegion);
925 
926 	dirty->IntersectWith(screenAndUserClipping);
927 	fWindow->MarkContentDirty(*dirty);
928 
929 	fWindow->RecycleRegion(dirty);
930 	fWindow->RecycleRegion(copyRegion);
931 }
932 
933 
934 // #pragma mark -
935 
936 
937 void
938 View::ColorUpdated(color_which which, rgb_color color)
939 {
940 	float tint = B_NO_TINT;
941 
942 	if (fWhichViewColor == which)
943 		SetViewColor(tint_color(color, fWhichViewColorTint));
944 
945 	if (CurrentState()->HighUIColor(&tint) == which)
946 		CurrentState()->SetHighColor(tint_color(color, tint));
947 
948 	if (CurrentState()->LowUIColor(&tint) == which)
949 		CurrentState()->SetLowColor(tint_color(color, tint));
950 
951 	for (View* child = FirstChild(); child != NULL;
952 			child = child->NextSibling()) {
953 
954 		child->ColorUpdated(which, color);
955 	}
956 }
957 
958 
959 void
960 View::SetViewUIColor(color_which which, float tint)
961 {
962 	if (which != B_NO_COLOR) {
963 		DesktopSettings settings(fWindow->Desktop());
964 		SetViewColor(tint_color(settings.UIColor(which), tint));
965 	}
966 
967 	fWhichViewColor = which;
968 	fWhichViewColorTint = tint;
969 }
970 
971 
972 color_which
973 View::ViewUIColor(float* tint)
974 {
975 	if (tint != NULL)
976 		*tint = fWhichViewColorTint;
977 
978 	return fWhichViewColor;
979 }
980 
981 
982 // #pragma mark -
983 
984 
985 void
986 View::PushState()
987 {
988 	DrawState* newState = fDrawState->PushState();
989 	if (newState) {
990 		fDrawState = newState;
991 		// In BeAPI, B_SUBPIXEL_PRECISE is a view flag, and not affected by the
992 		// view state. Our implementation moves it to the draw state, but let's
993 		// be compatible with the API here and make it survive accross state
994 		// changes.
995 		fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
996 	}
997 }
998 
999 
1000 void
1001 View::PopState()
1002 {
1003 	if (fDrawState->PreviousState() == NULL) {
1004 		fprintf(stderr, "WARNING: User called BView(%s)::PopState(), "
1005 			"but there is NO state on stack!\n", Name());
1006 		return;
1007 	}
1008 
1009 	bool rebuildClipping = fDrawState->HasAdditionalClipping();
1010 
1011 	fDrawState = fDrawState->PopState();
1012 	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
1013 
1014 	// rebuild clipping
1015 	// (the clipping from the popped state is not effective anymore)
1016 	if (rebuildClipping)
1017 		RebuildClipping(false);
1018 }
1019 
1020 
1021 // #pragma mark -
1022 
1023 
1024 void
1025 View::SetEventMask(uint32 eventMask, uint32 options)
1026 {
1027 	fEventMask = eventMask;
1028 	fEventOptions = options;
1029 }
1030 
1031 
1032 void
1033 View::SetCursor(ServerCursor* cursor)
1034 {
1035 	if (cursor == fCursor)
1036 		return;
1037 
1038 	if (fCursor)
1039 		fCursor->ReleaseReference();
1040 
1041 	fCursor = cursor;
1042 
1043 	if (fCursor)
1044 		fCursor->AcquireReference();
1045 }
1046 
1047 
1048 void
1049 View::SetPicture(ServerPicture* picture)
1050 {
1051 	if (picture == fPicture)
1052 		return;
1053 
1054 	if (fPicture != NULL)
1055 		fPicture->ReleaseReference();
1056 
1057 	fPicture = picture;
1058 
1059 	if (fPicture != NULL)
1060 		fPicture->AcquireReference();
1061 }
1062 
1063 
1064 void
1065 View::BlendAllLayers()
1066 {
1067 	if (fPicture == NULL)
1068 		return;
1069 	Layer* layer = dynamic_cast<Layer*>(fPicture);
1070 	if (layer == NULL)
1071 		return;
1072 	BlendLayer(layer);
1073 }
1074 
1075 
1076 void
1077 View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
1078 	BRegion* windowContentClipping, bool deep)
1079 {
1080 	if (!fVisible) {
1081 		// child views cannot be visible either
1082 		return;
1083 	}
1084 
1085 	if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) {
1086 		// we can only draw within our own area
1087 		BRegion* redraw;
1088 		if ((fFlags & B_DRAW_ON_CHILDREN) != 0) {
1089 			// The client may actually want to prevent the background to
1090 			// be painted outside the user clipping.
1091 			redraw = fWindow->GetRegion(
1092 				ScreenAndUserClipping(windowContentClipping));
1093 		} else {
1094 			// Ignore user clipping as in BeOS for painting the background.
1095 			redraw = fWindow->GetRegion(
1096 				_ScreenClipping(windowContentClipping));
1097 		}
1098 		if (!redraw)
1099 			return;
1100 		// add the current clipping
1101 		redraw->IntersectWith(effectiveClipping);
1102 
1103 		Overlay* overlayCookie = _Overlay();
1104 
1105 		if (fViewBitmap != NULL && overlayCookie == NULL) {
1106 			// draw view bitmap
1107 			// TODO: support other options!
1108 			BRect rect = fBitmapDestination;
1109 			PenToScreenTransform().Apply(&rect);
1110 
1111 			align_rect_to_pixels(&rect);
1112 
1113 			if (fBitmapOptions & B_TILE_BITMAP_Y) {
1114 				// move rect up as much as needed
1115 				while (rect.top > redraw->Frame().top)
1116 					rect.OffsetBy(0.0, -(rect.Height() + 1));
1117 			}
1118 			if (fBitmapOptions & B_TILE_BITMAP_X) {
1119 				// move rect left as much as needed
1120 				while (rect.left > redraw->Frame().left)
1121 					rect.OffsetBy(-(rect.Width() + 1), 0.0);
1122 			}
1123 
1124 // XXX: locking removed because the Window keeps the engine locked
1125 // because it keeps track of syncing right now
1126 
1127 			// lock the drawing engine for as long as we need the clipping
1128 			// to be valid
1129 			if (rect.IsValid()/* && drawingEngine->Lock()*/) {
1130 				drawingEngine->ConstrainClippingRegion(redraw);
1131 
1132 				drawing_mode oldMode;
1133 				drawingEngine->SetDrawingMode(B_OP_COPY, oldMode);
1134 
1135 				if (fBitmapOptions & B_TILE_BITMAP) {
1136 					// tile across entire view
1137 
1138 					float start = rect.left;
1139 					while (rect.top < redraw->Frame().bottom) {
1140 						while (rect.left < redraw->Frame().right) {
1141 							drawingEngine->DrawBitmap(fViewBitmap,
1142 								fBitmapSource, rect, fBitmapOptions);
1143 							rect.OffsetBy(rect.Width() + 1, 0.0);
1144 						}
1145 						rect.OffsetBy(start - rect.left, rect.Height() + 1);
1146 					}
1147 					// nothing left to be drawn
1148 					redraw->MakeEmpty();
1149 				} else if (fBitmapOptions & B_TILE_BITMAP_X) {
1150 					// tile in x direction
1151 
1152 					while (rect.left < redraw->Frame().right) {
1153 						drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1154 							rect, fBitmapOptions);
1155 						rect.OffsetBy(rect.Width() + 1, 0.0);
1156 					}
1157 					// remove horizontal stripe from clipping
1158 					rect.left = redraw->Frame().left;
1159 					rect.right = redraw->Frame().right;
1160 					redraw->Exclude(rect);
1161 				} else if (fBitmapOptions & B_TILE_BITMAP_Y) {
1162 					// tile in y direction
1163 
1164 					while (rect.top < redraw->Frame().bottom) {
1165 						drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1166 							rect, fBitmapOptions);
1167 						rect.OffsetBy(0.0, rect.Height() + 1);
1168 					}
1169 					// remove vertical stripe from clipping
1170 					rect.top = redraw->Frame().top;
1171 					rect.bottom = redraw->Frame().bottom;
1172 					redraw->Exclude(rect);
1173 				} else {
1174 					// no tiling at all
1175 
1176 					drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1177 						rect, fBitmapOptions);
1178 					redraw->Exclude(rect);
1179 				}
1180 
1181 				drawingEngine->SetDrawingMode(oldMode);
1182 
1183 				// NOTE: It is ok not to reset the clipping, that
1184 				// would only waste time
1185 //				drawingEngine->Unlock();
1186 			}
1187 
1188 		}
1189 
1190 		if (fViewColor != B_TRANSPARENT_COLOR) {
1191 			// fill visible region with view color,
1192 			// this version of FillRegion ignores any
1193 			// clipping, that's why "redraw" needs to
1194 			// be correct
1195 // see #634
1196 //			if (redraw->Frame().left < 0 || redraw->Frame().top < 0) {
1197 //				char message[1024];
1198 //				BRect c = effectiveClipping->Frame();
1199 //				BRect w = windowContentClipping->Frame();
1200 //				BRect r = redraw->Frame();
1201 //				sprintf(message, "invalid background: current clipping: (%d, %d)->(%d, %d), "
1202 //					"window content: (%d, %d)->(%d, %d), redraw: (%d, %d)->(%d, %d)",
1203 //					(int)c.left, (int)c.top, (int)c.right, (int)c.bottom,
1204 //					(int)w.left, (int)w.top, (int)w.right, (int)w.bottom,
1205 //					(int)r.left, (int)r.top, (int)r.right, (int)r.bottom);
1206 //				debugger(message);
1207 //			}
1208 
1209 			drawingEngine->FillRegion(*redraw, overlayCookie != NULL
1210 				? overlayCookie->Color() : fViewColor);
1211 		}
1212 
1213 		fWindow->RecycleRegion(redraw);
1214 	}
1215 
1216 	fBackgroundDirty = false;
1217 
1218 	// let children draw
1219 	if (deep) {
1220 		for (View* child = FirstChild(); child; child = child->NextSibling()) {
1221 			child->Draw(drawingEngine, effectiveClipping,
1222 				windowContentClipping, deep);
1223 		}
1224 	}
1225 }
1226 
1227 
1228 // #pragma mark -
1229 
1230 
1231 void
1232 View::MouseDown(BMessage* message, BPoint where)
1233 {
1234 	// empty hook method
1235 }
1236 
1237 
1238 void
1239 View::MouseUp(BMessage* message, BPoint where)
1240 {
1241 	// empty hook method
1242 }
1243 
1244 
1245 void
1246 View::MouseMoved(BMessage* message, BPoint where)
1247 {
1248 	// empty hook method
1249 }
1250 
1251 
1252 // #pragma mark -
1253 
1254 
1255 void
1256 View::SetHidden(bool hidden)
1257 {
1258 	if (fHidden != hidden) {
1259 		fHidden = hidden;
1260 
1261 		// recurse into children and update their visible flag
1262 		bool oldVisible = fVisible;
1263 		UpdateVisibleDeep(fParent ? fParent->IsVisible() : !fHidden);
1264 		if (oldVisible != fVisible) {
1265 			// Include or exclude us from the parent area, and update the
1266 			// children's clipping as well when the view will be visible
1267 			if (fParent)
1268 				fParent->RebuildClipping(fVisible);
1269 			else
1270 				RebuildClipping(fVisible);
1271 
1272 			if (fWindow) {
1273 				// trigger a redraw
1274 				IntRect clippedBounds = Bounds();
1275 				ConvertToVisibleInTopView(&clippedBounds);
1276 
1277 				BRegion dirty;
1278 				dirty.Set((clipping_rect)clippedBounds);
1279 				fWindow->MarkContentDirty(dirty);
1280 			}
1281 		}
1282 	}
1283 }
1284 
1285 
1286 bool
1287 View::IsHidden() const
1288 {
1289 	return fHidden;
1290 }
1291 
1292 
1293 void
1294 View::UpdateVisibleDeep(bool parentVisible)
1295 {
1296 	bool wasVisible = fVisible;
1297 
1298 	fVisible = parentVisible && !fHidden;
1299 	for (View* child = FirstChild(); child; child = child->NextSibling())
1300 		child->UpdateVisibleDeep(fVisible);
1301 
1302 	// overlay handling
1303 
1304 	Overlay* overlay = _Overlay();
1305 	if (overlay == NULL)
1306 		return;
1307 
1308 	if (fVisible && !wasVisible)
1309 		_UpdateOverlayView();
1310 	else if (!fVisible && wasVisible)
1311 		overlay->Hide();
1312 }
1313 
1314 
1315 // #pragma mark -
1316 
1317 
1318 void
1319 View::MarkBackgroundDirty()
1320 {
1321 	if (fBackgroundDirty)
1322 		return;
1323 	fBackgroundDirty = true;
1324 	for (View* child = FirstChild(); child; child = child->NextSibling())
1325 		child->MarkBackgroundDirty();
1326 }
1327 
1328 
1329 void
1330 View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region,
1331 	BRegion* windowContentClipping)
1332 {
1333 	if (!fVisible)
1334 		return;
1335 
1336 	{
1337 		// NOTE: use scope in order to reduce stack space requirements
1338 
1339 		// This check will prevent descending the view hierarchy
1340 		// any further than necessary
1341 		IntRect screenBounds(Bounds());
1342 		LocalToScreenTransform().Apply(&screenBounds);
1343 		if (!region.Intersects((clipping_rect)screenBounds))
1344 			return;
1345 
1346 		// Unfortunately, we intersecting another region, but otherwise
1347 		// we couldn't provide the exact update rect to the client
1348 		BRegion localDirty = _ScreenClipping(windowContentClipping);
1349 		localDirty.IntersectWith(&region);
1350 		if (localDirty.CountRects() > 0) {
1351 			link.Attach<int32>(fToken);
1352 			link.Attach<BRect>(localDirty.Frame());
1353 		}
1354 	}
1355 
1356 	for (View* child = FirstChild(); child; child = child->NextSibling())
1357 		child->AddTokensForViewsInRegion(link, region, windowContentClipping);
1358 }
1359 
1360 
1361 void
1362 View::PrintToStream() const
1363 {
1364 	printf("View:          %s\n", Name());
1365 	printf("  fToken:           %" B_PRId32 "\n", fToken);
1366 	printf("  fFrame:           IntRect(%" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ")\n",
1367 		fFrame.left, fFrame.top, fFrame.right, fFrame.bottom);
1368 	printf("  fScrollingOffset: IntPoint(%" B_PRId32 ", %" B_PRId32 ")\n",
1369 		fScrollingOffset.x, fScrollingOffset.y);
1370 	printf("  fHidden:          %d\n", fHidden);
1371 	printf("  fVisible:         %d\n", fVisible);
1372 	printf("  fWindow:          %p\n", fWindow);
1373 	printf("  fParent:          %p\n", fParent);
1374 	printf("  fLocalClipping:\n");
1375 	fLocalClipping.PrintToStream();
1376 	printf("  fScreenClipping:\n");
1377 	fScreenClipping.PrintToStream();
1378 	printf("  valid:            %d\n", fScreenClippingValid);
1379 
1380 	printf("  fUserClipping:\n");
1381 	if (fUserClipping != NULL)
1382 		fUserClipping->PrintToStream();
1383 	else
1384 		printf("  none\n");
1385 
1386 	printf("  fScreenAndUserClipping:\n");
1387 	if (fScreenAndUserClipping != NULL)
1388 		fScreenAndUserClipping->PrintToStream();
1389 	else
1390 		printf("  invalid\n");
1391 
1392 	printf("  state:\n");
1393 	printf("    user clipping:  %d\n", fDrawState->HasClipping());
1394 	BPoint origin = fDrawState->CombinedOrigin();
1395 	printf("    origin:         BPoint(%.1f, %.1f)\n", origin.x, origin.y);
1396 	printf("    scale:          %.2f\n", fDrawState->CombinedScale());
1397 	printf("\n");
1398 }
1399 
1400 
1401 void
1402 View::RebuildClipping(bool deep)
1403 {
1404 	// the clipping spans over the bounds area
1405 	fLocalClipping.Set((clipping_rect)Bounds());
1406 
1407 	if (View* child = FirstChild()) {
1408 		// if this view does not draw over children,
1409 		// exclude all children from the clipping
1410 		if ((fFlags & B_DRAW_ON_CHILDREN) == 0) {
1411 			BRegion* childrenRegion = fWindow->GetRegion();
1412 			if (!childrenRegion)
1413 				return;
1414 
1415 			for (; child; child = child->NextSibling()) {
1416 				if (child->IsVisible()
1417 					&& (child->fFlags & B_TRANSPARENT_BACKGROUND) == 0) {
1418 					childrenRegion->Include((clipping_rect)child->Frame());
1419 				}
1420 			}
1421 
1422 			fLocalClipping.Exclude(childrenRegion);
1423 			fWindow->RecycleRegion(childrenRegion);
1424 		}
1425 		// if the operation is "deep", make children rebuild their
1426 		// clipping too
1427 		if (deep) {
1428 			for (child = FirstChild(); child; child = child->NextSibling())
1429 				child->RebuildClipping(true);
1430 		}
1431 	}
1432 
1433 	// add the user clipping in case there is one
1434 	if (fDrawState->HasClipping()) {
1435 		// NOTE: in case the user sets a user defined clipping region,
1436 		// rebuilding the clipping is a bit more expensive because there
1437 		// is no separate "drawing region"... on the other
1438 		// hand, views for which this feature is actually used will
1439 		// probably not have any children, so it is not that expensive
1440 		// after all
1441 		if (fUserClipping == NULL) {
1442 			fUserClipping = new (nothrow) BRegion;
1443 			if (fUserClipping == NULL)
1444 				return;
1445 		}
1446 
1447 		fDrawState->GetCombinedClippingRegion(fUserClipping);
1448 	} else {
1449 		delete fUserClipping;
1450 		fUserClipping = NULL;
1451 	}
1452 
1453 	delete fScreenAndUserClipping;
1454 	fScreenAndUserClipping = NULL;
1455 	fScreenClippingValid = false;
1456 }
1457 
1458 
1459 BRegion&
1460 View::ScreenAndUserClipping(BRegion* windowContentClipping, bool force) const
1461 {
1462 	// no user clipping - return screen clipping directly
1463 	if (fUserClipping == NULL)
1464 		return _ScreenClipping(windowContentClipping, force);
1465 
1466 	// combined screen and user clipping already valid
1467 	if (fScreenAndUserClipping != NULL)
1468 		return *fScreenAndUserClipping;
1469 
1470 	// build a new combined user and screen clipping
1471 	fScreenAndUserClipping = new (nothrow) BRegion(*fUserClipping);
1472 	if (fScreenAndUserClipping == NULL)
1473 		return fScreenClipping;
1474 
1475 	LocalToScreenTransform().Apply(fScreenAndUserClipping);
1476 	fScreenAndUserClipping->IntersectWith(
1477 		&_ScreenClipping(windowContentClipping, force));
1478 	return *fScreenAndUserClipping;
1479 }
1480 
1481 
1482 void
1483 View::InvalidateScreenClipping()
1484 {
1485 // TODO: appearantly, we are calling ScreenClipping() on
1486 // views who's parents don't have a valid screen clipping yet,
1487 // this messes up the logic that for any given view with
1488 // fScreenClippingValid == false, all children have
1489 // fScreenClippingValid == false too. If this could be made the
1490 // case, we could save some performance here with the commented
1491 // out check, since InvalidateScreenClipping() might be called
1492 // frequently.
1493 // TODO: investigate, if InvalidateScreenClipping() could be
1494 // called in "deep" and "non-deep" mode, ie. see if there are
1495 // any cases where the children would still have valid screen
1496 // clipping, even though the parent's screen clipping becomes
1497 // invalid.
1498 //	if (!fScreenClippingValid)
1499 //		return;
1500 
1501 	delete fScreenAndUserClipping;
1502 	fScreenAndUserClipping = NULL;
1503 	fScreenClippingValid = false;
1504 	// invalidate the childrens screen clipping as well
1505 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
1506 		child->InvalidateScreenClipping();
1507 	}
1508 }
1509 
1510 
1511 BRegion&
1512 View::_ScreenClipping(BRegion* windowContentClipping, bool force) const
1513 {
1514 	if (!fScreenClippingValid || force) {
1515 		fScreenClipping = fLocalClipping;
1516 		LocalToScreenTransform().Apply(&fScreenClipping);
1517 
1518 		// see if parts of our bounds are hidden underneath
1519 		// the parent, the local clipping does not account for this
1520 		IntRect clippedBounds = Bounds();
1521 		ConvertToVisibleInTopView(&clippedBounds);
1522 		if (clippedBounds.Width() < fScreenClipping.Frame().Width()
1523 			|| clippedBounds.Height() < fScreenClipping.Frame().Height()) {
1524 			BRegion temp;
1525 			temp.Set((clipping_rect)clippedBounds);
1526 			fScreenClipping.IntersectWith(&temp);
1527 		}
1528 
1529 		fScreenClipping.IntersectWith(windowContentClipping);
1530 		fScreenClippingValid = true;
1531 	}
1532 
1533 	return fScreenClipping;
1534 }
1535 
1536 
1537 void
1538 View::_MoveScreenClipping(int32 x, int32 y, bool deep)
1539 {
1540 	if (fScreenClippingValid) {
1541 		fScreenClipping.OffsetBy(x, y);
1542 		delete fScreenAndUserClipping;
1543 		fScreenAndUserClipping = NULL;
1544 	}
1545 
1546 	if (deep) {
1547 		// move the childrens screen clipping as well
1548 		for (View* child = FirstChild(); child; child = child->NextSibling()) {
1549 			child->_MoveScreenClipping(x, y, deep);
1550 		}
1551 	}
1552 }
1553 
1554