xref: /haiku/src/servers/app/View.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
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 		fViewBitmap->ReleaseReference();
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->ReleaseReference();
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 		fViewBitmap->ReleaseReference();
526 	}
527 
528 	// the caller is allowed to delete the bitmap after setting the background
529 	if (bitmap != NULL)
530 		bitmap->AcquireReference();
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->ReleaseReference();
1301 
1302 	fCursor = cursor;
1303 
1304 	if (fCursor)
1305 		fCursor->AcquireReference();
1306 }
1307 
1308 
1309 void
1310 View::SetPicture(ServerPicture* picture)
1311 {
1312 	if (picture == fPicture)
1313 		return;
1314 
1315 	if (fPicture != NULL)
1316 		fPicture->ReleaseReference();
1317 
1318 	fPicture = picture;
1319 
1320 	if (fPicture != NULL)
1321 		fPicture->AcquireReference();
1322 }
1323 
1324 
1325 void
1326 View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
1327 	BRegion* windowContentClipping, bool deep)
1328 {
1329 	if (!fVisible) {
1330 		// child views cannot be visible either
1331 		return;
1332 	}
1333 
1334 	if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) {
1335 		// we can only draw within our own area
1336 		BRegion* redraw;
1337 		if ((fFlags & B_DRAW_ON_CHILDREN) != 0) {
1338 			// The client may actually want to prevent the background to
1339 			// be painted outside the user clipping.
1340 			redraw = fWindow->GetRegion(
1341 				ScreenAndUserClipping(windowContentClipping));
1342 		} else {
1343 			// Ignore user clipping as in BeOS for painting the background.
1344 			redraw = fWindow->GetRegion(
1345 				_ScreenClipping(windowContentClipping));
1346 		}
1347 		if (!redraw)
1348 			return;
1349 		// add the current clipping
1350 		redraw->IntersectWith(effectiveClipping);
1351 
1352 		Overlay* overlayCookie = _Overlay();
1353 
1354 		if (fViewBitmap != NULL && overlayCookie == NULL) {
1355 			// draw view bitmap
1356 			// TODO: support other options!
1357 			BRect rect = fBitmapDestination;
1358 			ConvertToScreenForDrawing(&rect);
1359 
1360 			align_rect_to_pixels(&rect);
1361 
1362 			if (fBitmapOptions & B_TILE_BITMAP_Y) {
1363 				// move rect up as much as needed
1364 				while (rect.top > redraw->Frame().top)
1365 					rect.OffsetBy(0.0, -(rect.Height() + 1));
1366 			}
1367 			if (fBitmapOptions & B_TILE_BITMAP_X) {
1368 				// move rect left as much as needed
1369 				while (rect.left > redraw->Frame().left)
1370 					rect.OffsetBy(-(rect.Width() + 1), 0.0);
1371 			}
1372 
1373 // XXX: locking removed because the Window keeps the engine locked
1374 // because it keeps track of syncing right now
1375 
1376 			// lock the drawing engine for as long as we need the clipping
1377 			// to be valid
1378 			if (rect.IsValid()/* && drawingEngine->Lock()*/) {
1379 				drawingEngine->ConstrainClippingRegion(redraw);
1380 
1381 				drawing_mode oldMode;
1382 				drawingEngine->SetDrawingMode(B_OP_COPY, oldMode);
1383 
1384 				if (fBitmapOptions & B_TILE_BITMAP) {
1385 					// tile across entire view
1386 
1387 					float start = rect.left;
1388 					while (rect.top < redraw->Frame().bottom) {
1389 						while (rect.left < redraw->Frame().right) {
1390 							drawingEngine->DrawBitmap(fViewBitmap,
1391 								fBitmapSource, rect, fBitmapOptions);
1392 							rect.OffsetBy(rect.Width() + 1, 0.0);
1393 						}
1394 						rect.OffsetBy(start - rect.left, rect.Height() + 1);
1395 					}
1396 					// nothing left to be drawn
1397 					redraw->MakeEmpty();
1398 				} else if (fBitmapOptions & B_TILE_BITMAP_X) {
1399 					// tile in x direction
1400 
1401 					while (rect.left < redraw->Frame().right) {
1402 						drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1403 							rect, fBitmapOptions);
1404 						rect.OffsetBy(rect.Width() + 1, 0.0);
1405 					}
1406 					// remove horizontal stripe from clipping
1407 					rect.left = redraw->Frame().left;
1408 					rect.right = redraw->Frame().right;
1409 					redraw->Exclude(rect);
1410 				} else if (fBitmapOptions & B_TILE_BITMAP_Y) {
1411 					// tile in y direction
1412 
1413 					while (rect.top < redraw->Frame().bottom) {
1414 						drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1415 							rect, fBitmapOptions);
1416 						rect.OffsetBy(0.0, rect.Height() + 1);
1417 					}
1418 					// remove vertical stripe from clipping
1419 					rect.top = redraw->Frame().top;
1420 					rect.bottom = redraw->Frame().bottom;
1421 					redraw->Exclude(rect);
1422 				} else {
1423 					// no tiling at all
1424 
1425 					drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1426 						rect, fBitmapOptions);
1427 					redraw->Exclude(rect);
1428 				}
1429 
1430 				drawingEngine->SetDrawingMode(oldMode);
1431 
1432 				// NOTE: It is ok not to reset the clipping, that
1433 				// would only waste time
1434 //				drawingEngine->Unlock();
1435 			}
1436 
1437 		}
1438 
1439 		if (fViewColor != B_TRANSPARENT_COLOR) {
1440 			// fill visible region with view color,
1441 			// this version of FillRegion ignores any
1442 			// clipping, that's why "redraw" needs to
1443 			// be correct
1444 // see #634
1445 //			if (redraw->Frame().left < 0 || redraw->Frame().top < 0) {
1446 //				char message[1024];
1447 //				BRect c = effectiveClipping->Frame();
1448 //				BRect w = windowContentClipping->Frame();
1449 //				BRect r = redraw->Frame();
1450 //				sprintf(message, "invalid background: current clipping: (%d, %d)->(%d, %d), "
1451 //					"window content: (%d, %d)->(%d, %d), redraw: (%d, %d)->(%d, %d)",
1452 //					(int)c.left, (int)c.top, (int)c.right, (int)c.bottom,
1453 //					(int)w.left, (int)w.top, (int)w.right, (int)w.bottom,
1454 //					(int)r.left, (int)r.top, (int)r.right, (int)r.bottom);
1455 //				debugger(message);
1456 //			}
1457 
1458 			drawingEngine->FillRegion(*redraw, overlayCookie != NULL
1459 				? overlayCookie->Color() : fViewColor);
1460 		}
1461 
1462 		fWindow->RecycleRegion(redraw);
1463 	}
1464 
1465 	fBackgroundDirty = false;
1466 
1467 	// let children draw
1468 	if (deep) {
1469 		for (View* child = FirstChild(); child; child = child->NextSibling()) {
1470 			child->Draw(drawingEngine, effectiveClipping,
1471 				windowContentClipping, deep);
1472 		}
1473 	}
1474 }
1475 
1476 
1477 // #pragma mark -
1478 
1479 
1480 void
1481 View::MouseDown(BMessage* message, BPoint where)
1482 {
1483 	// empty hook method
1484 }
1485 
1486 
1487 void
1488 View::MouseUp(BMessage* message, BPoint where)
1489 {
1490 	// empty hook method
1491 }
1492 
1493 
1494 void
1495 View::MouseMoved(BMessage* message, BPoint where)
1496 {
1497 	// empty hook method
1498 }
1499 
1500 
1501 // #pragma mark -
1502 
1503 
1504 void
1505 View::SetHidden(bool hidden)
1506 {
1507 	if (fHidden != hidden) {
1508 		fHidden = hidden;
1509 
1510 		// recurse into children and update their visible flag
1511 		bool oldVisible = fVisible;
1512 		UpdateVisibleDeep(fParent ? fParent->IsVisible() : !fHidden);
1513 		if (oldVisible != fVisible) {
1514 			// Include or exclude us from the parent area, and update the
1515 			// children's clipping as well when the view will be visible
1516 			if (fParent)
1517 				fParent->RebuildClipping(fVisible);
1518 			else
1519 				RebuildClipping(fVisible);
1520 
1521 			if (fWindow) {
1522 				// trigger a redraw
1523 				IntRect clippedBounds = Bounds();
1524 				ConvertToVisibleInTopView(&clippedBounds);
1525 				BRegion* dirty = fWindow->GetRegion();
1526 				if (!dirty)
1527 					return;
1528 				dirty->Set((clipping_rect)clippedBounds);
1529 				fWindow->MarkContentDirty(*dirty);
1530 				fWindow->RecycleRegion(dirty);
1531 			}
1532 		}
1533 	}
1534 }
1535 
1536 
1537 bool
1538 View::IsHidden() const
1539 {
1540 	return fHidden;
1541 }
1542 
1543 
1544 void
1545 View::UpdateVisibleDeep(bool parentVisible)
1546 {
1547 	bool wasVisible = fVisible;
1548 
1549 	fVisible = parentVisible && !fHidden;
1550 	for (View* child = FirstChild(); child; child = child->NextSibling())
1551 		child->UpdateVisibleDeep(fVisible);
1552 
1553 	// overlay handling
1554 
1555 	Overlay* overlay = _Overlay();
1556 	if (overlay == NULL)
1557 		return;
1558 
1559 	if (fVisible && !wasVisible)
1560 		_UpdateOverlayView();
1561 	else if (!fVisible && wasVisible)
1562 		overlay->Hide();
1563 }
1564 
1565 
1566 // #pragma mark -
1567 
1568 
1569 void
1570 View::MarkBackgroundDirty()
1571 {
1572 	if (fBackgroundDirty)
1573 		return;
1574 	fBackgroundDirty = true;
1575 	for (View* child = FirstChild(); child; child = child->NextSibling())
1576 		child->MarkBackgroundDirty();
1577 }
1578 
1579 
1580 void
1581 View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region,
1582 	BRegion* windowContentClipping)
1583 {
1584 	if (!fVisible)
1585 		return;
1586 
1587 	{
1588 		// NOTE: use scope in order to reduce stack space requirements
1589 
1590 		// This check will prevent descending the view hierarchy
1591 		// any further than necessary
1592 		IntRect screenBounds(Bounds());
1593 		ConvertToScreen(&screenBounds);
1594 		if (!region.Intersects((clipping_rect)screenBounds))
1595 			return;
1596 
1597 		// Unfortunately, we intersecting another region, but otherwise
1598 		// we couldn't provide the exact update rect to the client
1599 		BRegion localDirty = _ScreenClipping(windowContentClipping);
1600 		localDirty.IntersectWith(&region);
1601 		if (localDirty.CountRects() > 0) {
1602 			link.Attach<int32>(fToken);
1603 			link.Attach<BRect>(localDirty.Frame());
1604 		}
1605 	}
1606 
1607 	for (View* child = FirstChild(); child; child = child->NextSibling())
1608 		child->AddTokensForViewsInRegion(link, region, windowContentClipping);
1609 }
1610 
1611 
1612 void
1613 View::PrintToStream() const
1614 {
1615 	printf("View:          %s\n", Name());
1616 	printf("  fToken:           %ld\n", fToken);
1617 	printf("  fFrame:           IntRect(%ld, %ld, %ld, %ld)\n", fFrame.left, fFrame.top, fFrame.right, fFrame.bottom);
1618 	printf("  fScrollingOffset: IntPoint(%ld, %ld)\n", fScrollingOffset.x, fScrollingOffset.y);
1619 	printf("  fHidden:          %d\n", fHidden);
1620 	printf("  fVisible:         %d\n", fVisible);
1621 	printf("  fWindow:          %p\n", fWindow);
1622 	printf("  fParent:          %p\n", fParent);
1623 	printf("  fLocalClipping:\n");
1624 	fLocalClipping.PrintToStream();
1625 	printf("  fScreenClipping:\n");
1626 	fScreenClipping.PrintToStream();
1627 	printf("  valid:            %d\n", fScreenClippingValid);
1628 
1629 	printf("  fUserClipping:\n");
1630 	if (fUserClipping != NULL)
1631 		fUserClipping->PrintToStream();
1632 	else
1633 		printf("  none\n");
1634 
1635 	printf("  fScreenAndUserClipping:\n");
1636 	if (fScreenAndUserClipping != NULL)
1637 		fScreenAndUserClipping->PrintToStream();
1638 	else
1639 		printf("  invalid\n");
1640 
1641 	printf("  state:\n");
1642 	printf("    user clipping:  %d\n", fDrawState->HasClipping());
1643 	BPoint origin = fDrawState->CombinedOrigin();
1644 	printf("    origin:         BPoint(%.1f, %.1f)\n", origin.x, origin.y);
1645 	printf("    scale:          %.2f\n", fDrawState->CombinedScale());
1646 	printf("\n");
1647 }
1648 
1649 
1650 void
1651 View::RebuildClipping(bool deep)
1652 {
1653 	// the clipping spans over the bounds area
1654 	fLocalClipping.Set((clipping_rect)Bounds());
1655 
1656 	if (View* child = FirstChild()) {
1657 		// if this view does not draw over children,
1658 		// exclude all children from the clipping
1659 		if ((fFlags & B_DRAW_ON_CHILDREN) == 0) {
1660 			BRegion* childrenRegion = fWindow->GetRegion();
1661 			if (!childrenRegion)
1662 				return;
1663 
1664 			for (; child; child = child->NextSibling()) {
1665 				if (child->IsVisible())
1666 					childrenRegion->Include((clipping_rect)child->Frame());
1667 			}
1668 
1669 			fLocalClipping.Exclude(childrenRegion);
1670 			fWindow->RecycleRegion(childrenRegion);
1671 		}
1672 		// if the operation is "deep", make children rebuild their
1673 		// clipping too
1674 		if (deep) {
1675 			for (child = FirstChild(); child; child = child->NextSibling())
1676 				child->RebuildClipping(true);
1677 		}
1678 	}
1679 
1680 	// add the user clipping in case there is one
1681 	if (fDrawState->HasClipping()) {
1682 		// NOTE: in case the user sets a user defined clipping region,
1683 		// rebuilding the clipping is a bit more expensive because there
1684 		// is no separate "drawing region"... on the other
1685 		// hand, views for which this feature is actually used will
1686 		// probably not have any children, so it is not that expensive
1687 		// after all
1688 		if (fUserClipping == NULL) {
1689 			fUserClipping = new (nothrow) BRegion;
1690 			if (fUserClipping == NULL)
1691 				return;
1692 		}
1693 
1694 		fDrawState->GetCombinedClippingRegion(fUserClipping);
1695 	} else {
1696 		delete fUserClipping;
1697 		fUserClipping = NULL;
1698 	}
1699 
1700 	delete fScreenAndUserClipping;
1701 	fScreenAndUserClipping = NULL;
1702 	fScreenClippingValid = false;
1703 }
1704 
1705 
1706 BRegion&
1707 View::ScreenAndUserClipping(BRegion* windowContentClipping, bool force) const
1708 {
1709 	// no user clipping - return screen clipping directly
1710 	if (fUserClipping == NULL)
1711 		return _ScreenClipping(windowContentClipping, force);
1712 
1713 	// combined screen and user clipping already valid
1714 	if (fScreenAndUserClipping != NULL)
1715 		return *fScreenAndUserClipping;
1716 
1717 	// build a new combined user and screen clipping
1718 	fScreenAndUserClipping = new (nothrow) BRegion(*fUserClipping);
1719 	if (fScreenAndUserClipping == NULL)
1720 		return fScreenClipping;
1721 
1722 	ConvertToScreen(fScreenAndUserClipping);
1723 	fScreenAndUserClipping->IntersectWith(
1724 		&_ScreenClipping(windowContentClipping, force));
1725 	return *fScreenAndUserClipping;
1726 }
1727 
1728 
1729 void
1730 View::InvalidateScreenClipping()
1731 {
1732 // TODO: appearantly, we are calling ScreenClipping() on
1733 // views who's parents don't have a valid screen clipping yet,
1734 // this messes up the logic that for any given view with
1735 // fScreenClippingValid == false, all children have
1736 // fScreenClippingValid == false too. If this could be made the
1737 // case, we could save some performance here with the commented
1738 // out check, since InvalidateScreenClipping() might be called
1739 // frequently.
1740 // TODO: investigate, if InvalidateScreenClipping() could be
1741 // called in "deep" and "non-deep" mode, ie. see if there are
1742 // any cases where the children would still have valid screen
1743 // clipping, even though the parent's screen clipping becomes
1744 // invalid.
1745 //	if (!fScreenClippingValid)
1746 //		return;
1747 
1748 	delete fScreenAndUserClipping;
1749 	fScreenAndUserClipping = NULL;
1750 	fScreenClippingValid = false;
1751 	// invalidate the childrens screen clipping as well
1752 	for (View* child = FirstChild(); child; child = child->NextSibling()) {
1753 		child->InvalidateScreenClipping();
1754 	}
1755 }
1756 
1757 
1758 BRegion&
1759 View::_ScreenClipping(BRegion* windowContentClipping, bool force) const
1760 {
1761 	if (!fScreenClippingValid || force) {
1762 		fScreenClipping = fLocalClipping;
1763 		ConvertToScreen(&fScreenClipping);
1764 
1765 		// see if parts of our bounds are hidden underneath
1766 		// the parent, the local clipping does not account for this
1767 		IntRect clippedBounds = Bounds();
1768 		ConvertToVisibleInTopView(&clippedBounds);
1769 		if (clippedBounds.Width() < fScreenClipping.Frame().Width()
1770 			|| clippedBounds.Height() < fScreenClipping.Frame().Height()) {
1771 			BRegion* temp = fWindow->GetRegion();
1772 			if (temp) {
1773 				temp->Set((clipping_rect)clippedBounds);
1774 				fScreenClipping.IntersectWith(temp);
1775 				fWindow->RecycleRegion(temp);
1776 			}
1777 		}
1778 
1779 		fScreenClipping.IntersectWith(windowContentClipping);
1780 		fScreenClippingValid = true;
1781 	}
1782 
1783 	return fScreenClipping;
1784 }
1785 
1786 
1787 void
1788 View::_MoveScreenClipping(int32 x, int32 y, bool deep)
1789 {
1790 	if (fScreenClippingValid) {
1791 		fScreenClipping.OffsetBy(x, y);
1792 		delete fScreenAndUserClipping;
1793 		fScreenAndUserClipping = NULL;
1794 	}
1795 
1796 	if (deep) {
1797 		// move the childrens screen clipping as well
1798 		for (View* child = FirstChild(); child; child = child->NextSibling()) {
1799 			child->_MoveScreenClipping(x, y, deep);
1800 		}
1801 	}
1802 }
1803 
1804