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