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