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