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