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