Layer.cpp revision 2899b880f6c1e9ba92bbd4e78f4dc63c720a5e24
1/*
2 * Copyright (c) 2001-2005, 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 *		Stephan A��mus <superstippi@gmx.de>
9 */
10
11/**	Class used for tracking drawing context and screen clipping.
12 *	One Layer per client BWindow (WindowBorder) and each BView therein.
13 */
14
15#include <string.h>
16#include <stdio.h>
17#include <stdlib.h>
18
19#include <AppDefs.h>
20#include <Message.h>
21#include <Region.h>
22#include <View.h>
23
24#include "DebugInfoManager.h"
25#include "DrawingEngine.h"
26#include "DrawState.h"
27#include "PortLink.h"
28#include "RootLayer.h"
29#include "ServerProtocol.h"
30#include "ServerWindow.h"
31#include "WinBorder.h"
32#include "Layer.h"
33#include "ServerBitmap.h"
34
35//#define DEBUG_LAYER
36#ifdef DEBUG_LAYER
37#	define STRACE(x) printf x
38#else
39#	define STRACE(x) ;
40#endif
41
42
43Layer::Layer(BRect frame, const char* name, int32 token,
44	uint32 resize, uint32 flags, DrawingEngine* driver)
45	:
46	fName(name),
47	fFrame(frame),
48
49	fDriver(driver),
50	fRootLayer(NULL),
51	fServerWin(NULL),
52	fOwner(NULL),
53
54	fDrawState(new DrawState),
55
56	fParent(NULL),
57	fPreviousSibling(NULL),
58	fNextSibling(NULL),
59	fFirstChild(NULL),
60	fLastChild(NULL),
61
62	fCurrent(NULL),
63
64	fViewToken(token),
65	fFlags(flags),
66	fAdFlags(0),
67	fResizeMode(resize),
68	fEventMask(0UL),
69	fEventOptions(0UL),
70
71	fHidden(false),
72	fIsTopLayer(false),
73	fViewColor(255, 255, 255, 255),
74
75	fBackgroundBitmap(NULL),
76	fOverlayBitmap(NULL)
77{
78	if (!frame.IsValid()) {
79		char helper[1024];
80		sprintf(helper, "Layer::Layer(BRect(%.1f, %.1f, %.1f, %.1f), name: %s, token: %ld) - frame is invalid\n",
81			frame.left, frame.top, frame.right, frame.bottom, name, token);
82		CRITICAL(helper);
83		fFrame.Set(0, 0, 1, 1);
84	}
85
86	if (!fDriver)
87		CRITICAL("You MUST have a valid driver to init a Layer object\n");
88
89	// NOTE: This flag is forwarded to a DrawState setting, even
90	// though it is actually not part of a "state". However,
91	// it is an important detail of a graphics context, and we
92	// have no other means to pass this setting on to the DrawingEngine
93	// other than through the DrawState. If we ever add a flag
94	// B_ANTI_ALIASING to the view flags, it would have to be passed
95	// in the same way. Though when breaking binary compatibility,
96	// we might want to make this an actual part of a "state" (with
97	// a different API to set these).
98	// Note that the flag is also tested (updated) in Push/PopState and
99	// SetFlags().
100	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
101
102	STRACE(("Layer(%s) successfuly created\n", Name()));
103}
104
105
106Layer::~Layer()
107{
108	delete fDrawState;
109
110	Layer* child = fFirstChild;
111
112	while (child != NULL) {
113		Layer* nextChild = child->fNextSibling;
114
115		delete child;
116		child = nextChild;
117	}
118}
119
120
121/*!
122	\brief Adds a child layer to the current one
123	\param layer a new child layer
124	\param serverWin the serverwindow to which the layer will belong
125
126	Unlike the BView version, if the layer already belongs to another, then
127	it spits an error to stdout and returns.
128*/
129void
130Layer::AddChild(Layer* layer, ServerWindow* serverWin)
131{
132	STRACE(("Layer(%s)::AddChild(%s) START\n", Name(), layer->Name()));
133
134	if (layer->fParent != NULL) {
135		printf("ERROR: AddChild(): Layer already has a parent\n");
136		return;
137	}
138
139	// 1) attach layer to the tree structure
140	layer->fParent = this;
141
142	// if we have children already, bump the current last child back one and
143	// make the new child the last layer
144	if (fLastChild) {
145		layer->fPreviousSibling = fLastChild;
146		fLastChild->fNextSibling = layer;
147	} else {
148		fFirstChild = layer;
149	}
150	fLastChild = layer;
151
152	// if we have no RootLayer yet, then there is no need to set any parameters --
153	// they will be set when the RootLayer for this tree will be added
154	// to the main tree structure.
155	if (!fRootLayer) {
156		STRACE(("Layer(%s)::AddChild(%s) END\n", Name(), layer->Name()));
157		return;
158	}
159
160	// 2) Iterate over the newly-added layer and all its children, setting the
161	//	root layer and server window and also rebuilding the full-size region
162	//	for every descendant of the newly-added layer
163
164	//c = short for: current
165	Layer* c = layer;
166	Layer* stop = layer;
167	while (true) {
168		// action block
169
170		// 2.1) set the RootLayer for this object.
171		c->SetRootLayer(c->fParent->fRootLayer);
172
173		// 2.2) this Layer must know if it has a ServerWindow object attached.
174		c->fServerWin=serverWin;
175
176		// tree parsing algorithm
177		if (c->fFirstChild) {
178			// go deep
179			c = c->fFirstChild;
180		} else {
181			// go right or up
182
183			if (c == stop) // our trip is over
184				break;
185
186			if (c->fNextSibling) {
187				// go right
188				c = c->fNextSibling;
189			} else {
190				// go up
191				while (!c->fParent->fNextSibling && c->fParent != stop)
192					c = c->fParent;
193
194				if (c->fParent == stop) // that's enough!
195					break;
196
197				c = c->fParent->fNextSibling;
198			}
199		}
200	}
201
202	STRACE(("Layer(%s)::AddChild(%s) END\n", Name(), layer->Name()));
203}
204
205/*!
206	\brief Removes a child layer from the current one
207	\param layer the layer to remove
208
209	If the layer does not belong to the the current layer, then this function
210	spits out an error to stdout and returns
211*/
212void
213Layer::RemoveChild(Layer *layer)
214{
215	STRACE(("Layer(%s)::RemoveChild(%s) START\n", Name(), layer->Name()));
216
217	if (!layer->fParent) {
218		printf("ERROR: RemoveChild(): Layer doesn't have a parent\n");
219		return;
220	}
221
222	if (layer->fParent != this) {
223		printf("ERROR: RemoveChild(): Layer is not a child of this layer\n");
224		return;
225	}
226
227	// 1) remove this layer from the main tree.
228
229	// Take care of fParent
230	layer->fParent = NULL;
231
232	if (fFirstChild == layer)
233		fFirstChild = layer->fNextSibling;
234
235	if (fLastChild == layer)
236		fLastChild = layer->fPreviousSibling;
237
238	// Take care of siblings
239	if (layer->fPreviousSibling != NULL)
240		layer->fPreviousSibling->fNextSibling	= layer->fNextSibling;
241
242	if (layer->fNextSibling != NULL)
243		layer->fNextSibling->fPreviousSibling = layer->fPreviousSibling;
244
245	layer->fPreviousSibling = NULL;
246	layer->fNextSibling = NULL;
247	layer->_ClearVisibleRegions();
248
249	// 2) Iterate over all of the removed-layer's descendants and unset the
250	//	root layer, server window, and all redraw-related regions
251
252	Layer* c = layer; //c = short for: current
253	Layer* stop = layer;
254
255	while (true) {
256		// action block
257		{
258			// 2.1) set the RootLayer for this object.
259			c->SetRootLayer(NULL);
260			// 2.2) this Layer must know if it has a ServerWindow object attached.
261			c->fServerWin = NULL;
262		}
263
264		// tree parsing algorithm
265		if (c->fFirstChild) {
266			// go deep
267			c = c->fFirstChild;
268		} else {
269			// go right or up
270			if (c == stop) // out trip is over
271				break;
272
273			if (c->fNextSibling) {
274				// go right
275				c = c->fNextSibling;
276			} else {
277				// go up
278				while(!c->fParent->fNextSibling && c->fParent != stop)
279					c = c->fParent;
280
281				if (c->fParent == stop) // that enough!
282					break;
283
284				c = c->fParent->fNextSibling;
285			}
286		}
287	}
288	STRACE(("Layer(%s)::RemoveChild(%s) END\n", Name(), layer->Name()));
289}
290
291//! Removes the calling layer from the tree
292void
293Layer::RemoveSelf()
294{
295	// A Layer removes itself from the tree (duh)
296	if (fParent == NULL) {
297		printf("ERROR: RemoveSelf(): Layer doesn't have a parent\n");
298		return;
299	}
300	fParent->RemoveChild(this);
301}
302
303/*!
304	\return true if the child is owned by this Layer, false if not
305*/
306bool
307Layer::HasChild(Layer* layer)
308{
309	for (Layer* child = FirstChild(); child; child = NextChild()) {
310		if (child == layer)
311			return true;
312	}
313	return false;
314}
315
316//! Returns the number of children
317uint32
318Layer::CountChildren() const
319{
320	uint32 count = 0;
321	Layer* child = FirstChild();
322	while (child != NULL) {
323		child = NextChild();
324		count++;
325	}
326	return count;
327}
328
329/*!
330	\brief Finds a child of the caller based on its token ID
331	\param token ID of the layer to find
332	\return Pointer to the layer or NULL if not found
333*/
334Layer*
335Layer::FindLayer(const int32 token)
336{
337	// (recursive) search for a layer based on its view token
338
339	// iterate only over direct child layers first
340	for (Layer* child = FirstChild(); child; child = NextChild()) {
341		if (child->fViewToken == token)
342			return child;
343	}
344
345	// try a recursive search
346	for (Layer* child = FirstChild(); child; child = NextChild()) {
347		if (Layer* layer = child->FindLayer(token))
348			return layer;
349	}
350
351	return NULL;
352}
353
354/*!
355	\brief Returns the layer at the given point
356	\param pt The point to look the layer at
357	\return The layer containing the point or NULL if no layer found
358*/
359Layer*
360Layer::LayerAt(const BPoint &pt, bool recursive)
361{
362	//printf("%p:%s:LayerAt(x = %g, y = %g)\n", this, Name(), pt.x, pt.y);
363	if (!recursive)	{
364		if (VisibleRegion().Contains(pt))
365			return this;
366
367		for (Layer* child = LastChild(); child; child = PreviousChild())
368			if (child->FullVisible().Contains(pt))
369				return child;
370
371		return NULL;
372	}
373
374	if (fVisible.Contains(pt))
375		return this;
376
377	if (fFullVisible.Contains(pt)) {
378		for (Layer* child = LastChild(); child; child = PreviousChild()) {
379			if (Layer* layer = child->LayerAt(pt))
380				return layer;
381		}
382	}
383
384	return NULL;
385}
386
387// FirstChild
388Layer*
389Layer::FirstChild() const
390{
391	fCurrent = fFirstChild;
392	return fCurrent;
393}
394
395// NextChild
396Layer*
397Layer::NextChild() const
398{
399	fCurrent = fCurrent->fNextSibling;
400	return fCurrent;
401}
402
403// PreviousChild
404Layer*
405Layer::PreviousChild() const
406{
407	fCurrent = fCurrent->fPreviousSibling;
408	return fCurrent;
409}
410
411// LastChild
412Layer*
413Layer::LastChild() const
414{
415	fCurrent = fLastChild;
416	return fCurrent;
417}
418
419// SetName
420void
421Layer::SetName(const char* name)
422{
423	fName.SetTo(name);
424}
425
426// SetUserClipping
427void
428Layer::SetUserClipping(const BRegion& region)
429{
430	fDrawState->SetClippingRegion(region);
431
432	// rebuild clipping
433	_RebuildDrawingRegion();
434}
435
436// SetFlags
437void
438Layer::SetFlags(uint32 flags)
439{
440	fFlags = flags;
441	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
442}
443
444// Draw
445void
446Layer::Draw(const BRect &rect)
447{
448#ifdef DEBUG_LAYER
449	printf("Layer(%s)::Draw: ", Name());
450	rect.PrintToStream();
451#endif
452
453	if (!ViewColor().IsTransparentMagic())
454		fDriver->FillRect(rect, ViewColor());
455}
456
457/*!
458	\brief Shows the layer
459	\param invalidate Invalidate the region when showing the layer. defaults to true
460*/
461void
462Layer::Show(bool invalidate)
463{
464	STRACE(("Layer(%s)::Show()\n", Name()));
465	if(!IsHidden()) {
466		// an ancestor may be hidden. OK, we're not visible,
467		// but we're changing our visibility state
468		fHidden	= false;
469		return;
470	}
471
472	fHidden	= false;
473
474	if (invalidate) {
475		// compute the region this layer wants for itself
476		BRegion	invalid;
477		GetOnScreenRegion(invalid);
478		if (invalid.CountRects() > 0) {
479			fParent->MarkForRebuild(invalid);
480			GetRootLayer()->MarkForRedraw(invalid);
481
482			fParent->TriggerRebuild();
483			GetRootLayer()->TriggerRedraw();
484		}
485	}
486}
487
488/*!
489	\brief Shows the layer
490	\param invalidate Invalidate the region when hiding the layer. defaults to true
491*/
492void
493Layer::Hide(bool invalidate)
494{
495	STRACE(("Layer(%s)::Hide()\n", Name()));
496	if (IsHidden()) {
497		// an ancestor may be hidden. OK, we're not visible,
498		// but we're changing our visibility state
499		fHidden	= true;
500		return;
501	}
502
503	fHidden	= true;
504	if (invalidate && fFullVisible.CountRects() > 0) {
505		BRegion invalid(fFullVisible);
506
507		fParent->MarkForRebuild(invalid);
508		GetRootLayer()->MarkForRedraw(invalid);
509
510		fParent->TriggerRebuild();
511		GetRootLayer()->TriggerRedraw();
512	}
513}
514
515//! Returns true if the layer is hidden
516bool
517Layer::IsHidden(void) const
518{
519	if (fHidden)
520		return true;
521
522	if (fParent)
523			return fParent->IsHidden();
524
525	return fHidden;
526}
527
528
529void
530Layer::PushState()
531{
532	fDrawState = fDrawState->PushState();
533	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
534}
535
536
537void
538Layer::PopState()
539{
540	if (fDrawState->PreviousState() == NULL) {
541		fprintf(stderr, "WARNING: User called BView(%s)::PopState(), but there is NO state on stack!\n", Name());
542		return;
543	}
544
545	bool rebuildClipping = fDrawState->ClippingRegion() != NULL;
546
547	fDrawState = fDrawState->PopState();
548	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
549
550	// rebuild clipping
551	// (the clipping from the popped state is not effective anymore)
552	if (rebuildClipping)
553		_RebuildDrawingRegion();
554}
555
556
557//! Matches the BView call of the same name
558BRect
559Layer::Bounds() const
560{
561	BRect r(fFrame);
562//	r.OffsetTo(fBoundsLeftTop);
563	r.OffsetTo(BoundsOrigin());
564	return r;
565}
566
567
568//! Matches the BView call of the same name
569BRect
570Layer::Frame() const
571{
572	return fFrame;
573}
574
575
576//! Moves the layer by specified values, complete with redraw
577void
578Layer::MoveBy(float x, float y)
579{
580	STRACE(("Layer(%s)::MoveBy()\n", Name()));
581
582	if (x == 0.0f && y == 0.0f)
583		return;
584
585	// must lock, even if we change frame coordinates
586	if (fParent && !IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) {
587		fFrame.OffsetBy(x, y);
588
589		BRegion oldFullVisible(fFullVisible);
590
591		// we'll invalidate the old position and the new, maxmial one.
592		BRegion invalid;
593		GetOnScreenRegion(invalid);
594		invalid.Include(&fFullVisible);
595
596		fParent->MarkForRebuild(invalid);
597		fParent->TriggerRebuild();
598
599		// done rebuilding regions, now copy common parts and redraw regions that became visible
600
601		// include the actual and the old fullVisible regions. later, we'll exclude the common parts.
602		BRegion	redrawReg(fFullVisible);
603		redrawReg.Include(&oldFullVisible);
604
605		// offset to layer's new location so that we can calculate the common region.
606		oldFullVisible.OffsetBy(x, y);
607
608		// finally we have the region that needs to be redrawn.
609		redrawReg.Exclude(&oldFullVisible);
610
611		// by intersecting the old fullVisible offseted to layer's new location, with the current
612		// fullVisible, we'll have the common region which can be copied using HW acceleration.
613		oldFullVisible.IntersectWith(&fFullVisible);
614
615		// offset back and instruct the HW to do the actual copying.
616		oldFullVisible.OffsetBy(-x, -y);
617		GetDrawingEngine()->CopyRegion(&oldFullVisible, x, y);
618
619		GetRootLayer()->MarkForRedraw(redrawReg);
620		GetRootLayer()->TriggerRedraw();
621
622		GetRootLayer()->Unlock();
623	}
624	else {
625		// just offset to the new position
626		fFrame.OffsetBy(x, y);
627	}
628
629	MovedByHook(x, y);
630
631	_SendViewCoordUpdateMsg();
632}
633
634
635//! Resize the layer by the specified amount, complete with redraw
636void
637Layer::ResizeBy(float x, float y)
638{
639	STRACE(("Layer(%s)::ResizeBy()\n", Name()));
640
641	if (x == 0.0f && y == 0.0f)
642		return;
643
644	// must lock, even if we change frame coordinates
645	if (fParent && !IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) {
646		fFrame.Set(fFrame.left, fFrame.top, fFrame.right+x, fFrame.bottom+y);
647
648// TODO: you should call this hook function AFTER all region rebuilding
649//		 and redrawing stuff
650		ResizedByHook(x, y, false);
651
652// TODO: ResizedByHook(x,y,true) is called from inside _ResizeLayerFrameBy
653//		 Should call this AFTER region rebuilding and redrawing.
654		// resize children using their resize_mask.
655		for (Layer *child = LastChild(); child != NULL; child = PreviousChild())
656			child->_ResizeLayerFrameBy(x, y);
657
658		BRegion oldFullVisible(fFullVisible);
659		// this is required to invalidate the old border
660		BRegion oldVisible(fVisible);
661
662		// in case they moved, bottom, right and center aligned layers must be redrawn
663		BRegion redrawMore;
664		_RezizeLayerRedrawMore(redrawMore, x, y);
665
666		// we'll invalidate the old area and the new, maxmial one.
667		BRegion invalid;
668		GetOnScreenRegion(invalid);
669		invalid.Include(&fFullVisible);
670
671		fParent->MarkForRebuild(invalid);
672		fParent->TriggerRebuild();
673
674		// done rebuilding regions, now redraw regions that became visible
675
676		// what's invalid, are the differences between to old and the new fullVisible region
677		// 1) in case we grow.
678		BRegion redrawReg(fFullVisible);
679		redrawReg.Exclude(&oldFullVisible);
680		// 2) in case we shrink
681		BRegion redrawReg2(oldFullVisible);
682		redrawReg2.Exclude(&fFullVisible);
683		// 3) combine.
684		redrawReg.Include(&redrawReg2);
685
686		// for center, right and bottom alligned layers, redraw their old positions
687		redrawReg.Include(&redrawMore);
688
689		// layers that had their frame modified must be entirely redrawn.
690		_RezizeLayerRedrawMore(redrawReg, x, y);
691
692		// include layer's visible region in case we want a full update on resize
693		if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) {
694			_ResizeLayerFullUpdateOnResize(redrawReg, x, y);
695
696			redrawReg.Include(&fVisible);
697			redrawReg.Include(&oldVisible);
698		}
699
700		GetRootLayer()->MarkForRedraw(redrawReg);
701		GetRootLayer()->TriggerRedraw();
702
703		GetRootLayer()->Unlock();
704	}
705	// just resize our frame and those of out descendants if their resize mask says so
706	else {
707		fFrame.Set(fFrame.left, fFrame.top, fFrame.right+x, fFrame.bottom+y);
708
709// TODO: you should call this hook function AFTER all region rebuilding
710//		 and redrawing stuff
711		ResizedByHook(x, y, false);
712
713// TODO: ResizedByHook(x,y,true) is called from inside _ResizeLayerFrameBy
714//		 Should call this AFTER region rebuilding and redrawing.
715		// resize children using their resize_mask.
716		for (Layer *child = LastChild(); child != NULL; child = PreviousChild())
717			child->_ResizeLayerFrameBy(x, y);
718	}
719
720	_SendViewCoordUpdateMsg();
721}
722
723
724//! scrolls the layer by the specified amount, complete with redraw
725void
726Layer::ScrollBy(float x, float y)
727{
728	STRACE(("Layer(%s)::ScrollBy()\n", Name()));
729
730	if (x == 0.0f && y == 0.0f)
731		return;
732
733	// must lock, even if we change frame/origin coordinates
734	if (!IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) {
735		fDrawState->OffsetOrigin(BPoint(x, y));
736
737		// set the region to be invalidated.
738		BRegion invalid(fFullVisible);
739
740		MarkForRebuild(invalid);
741
742		TriggerRebuild();
743
744		// for the moment we say that the whole surface needs to be redraw.
745		BRegion redrawReg(fFullVisible);
746
747		// offset old region so that we can start comparing.
748		invalid.OffsetBy(x, y);
749
750		// compute the common region. we'll use HW acc to copy this to the new location.
751		invalid.IntersectWith(&fFullVisible);
752		GetDrawingEngine()->CopyRegion(&invalid, -x, -y);
753
754		// common region goes back to its original location. then, by excluding
755		// it from curent fullVisible we'll obtain the region that needs to be redrawn.
756		invalid.OffsetBy(-x, -y);
757// TODO: a quick fix for the scrolling problem!!! FIX THIS!
758//		redrawReg.Exclude(&invalid);
759
760		GetRootLayer()->MarkForRedraw(redrawReg);
761		GetRootLayer()->TriggerRedraw();
762
763		GetRootLayer()->Unlock();
764	}
765	else {
766		fDrawState->OffsetOrigin(BPoint(x, y));
767	}
768
769	ScrolledByHook(x, y);
770
771// TODO: I think we should update the client-side that bounds rect has modified
772//	SendViewCoordUpdateMsg();
773}
774
775void
776Layer::CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset)
777{
778	// NOTE: The correct behaviour is this:
779	// * The region that is copied is the
780	//   src rectangle, no matter if it fits
781	//   into the dst rectangle. It is copied
782	//   by the offset dst.LeftTop() - src.LeftTop()
783	// * The dst rectangle is used for invalidation:
784	//   Any area in the dst rectangle that could
785	//   not be copied from src (because either the
786	//   src rectangle was not big enough, or because there
787	//   were parts cut off by the current layer clipping),
788	//   are triggering BView::Draw() to be called
789	//   and for these parts only.
790
791	if (!GetRootLayer())
792		return;
793
794	if (!IsHidden() && GetRootLayer()->Lock()) {
795		// the region that is going to be copied
796		BRegion copyRegion(src);
797
798		// apply the current clipping of the layer
799		copyRegion.IntersectWith(&fVisible);
800
801		// offset the region to the destination
802		// and apply the current clipping there as well
803		copyRegion.OffsetBy(xOffset, yOffset);
804		copyRegion.IntersectWith(&fVisible);
805
806		// the region at the destination that needs invalidation
807		BRegion redrawReg(dst);
808		// exclude the region drawn by the copy operation
809// TODO: quick fix for our scrolling problem. FIX THIS!
810//		redrawReg.Exclude(&copyRegion);
811		// apply the current clipping as well
812		redrawReg.IntersectWith(&fVisible);
813
814		// move the region back for the actual operation
815		copyRegion.OffsetBy(-xOffset, -yOffset);
816
817		GetDrawingEngine()->CopyRegion(&copyRegion, xOffset, yOffset);
818
819		// trigger the redraw
820		GetRootLayer()->MarkForRedraw(redrawReg);
821		GetRootLayer()->TriggerRedraw();
822
823		GetRootLayer()->Unlock();
824	}
825}
826
827void
828Layer::MouseDown(const BMessage *msg)
829{
830	if (Window() && !IsTopLayer()) {
831		Window()->SendMessageToClient(msg, fViewToken, false);
832	}
833}
834
835void
836Layer::MouseUp(const BMessage *msg)
837{
838	if (Window() && !IsTopLayer()) {
839		Window()->SendMessageToClient(msg, fViewToken, false);
840	}
841}
842
843void
844Layer::MouseMoved(const BMessage *msg)
845{
846	if (Window() && !IsTopLayer()) {
847		Window()->SendMessageToClient(msg, fViewToken, false);
848	}
849}
850
851void
852Layer::MouseWheelChanged(const BMessage *msg)
853{
854	if (Window() && !IsTopLayer()) {
855		Window()->SendMessageToClient(msg, fViewToken, false);
856	}
857}
858
859
860void
861Layer::WorkspaceActivated(int32 index, bool active)
862{
863	// Empty
864}
865
866void
867Layer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
868{
869	// Empty
870}
871
872void
873Layer::Activated(bool active)
874{
875	// Empty
876}
877
878
879BPoint
880Layer::BoundsOrigin() const
881{
882	BPoint origin(fDrawState->Origin());
883	float scale = Scale();
884
885	// TODO: Figure this out, BoundsOrigin()
886	// is used for BView::Bounds(), but I think
887	// that the scale has nothing to do with it
888	// "local coordinate system origin" does have
889	// something to do with scale.
890
891	origin.x *= scale;
892	origin.y *= scale;
893
894	return origin;
895}
896
897
898float
899Layer::Scale() const
900{
901	return CurrentState()->Scale();
902}
903
904void
905Layer::SetViewColor(const RGBColor& color)
906{
907	fViewColor = color;
908}
909
910
911void
912Layer::SetBackgroundBitmap(const ServerBitmap* bitmap)
913{
914	// TODO: What about reference counting?
915	// "Release" old fBackgroundBitmap and "Aquire" new one?
916	fBackgroundBitmap = bitmap;
917}
918
919// SetOverlayBitmap
920void
921Layer::SetOverlayBitmap(const ServerBitmap* bitmap)
922{
923	// TODO: What about reference counting?
924	// "Release" old fOverlayBitmap and "Aquire" new one?
925	fOverlayBitmap = bitmap;
926}
927
928void
929Layer::MovedByHook(float dx, float dy)
930{
931	if (Window() && !IsTopLayer())
932		_AddToViewsWithInvalidCoords();
933}
934
935void
936Layer::ResizedByHook(float dx, float dy, bool automatic)
937{
938	if (Window() && !IsTopLayer())
939		_AddToViewsWithInvalidCoords();
940}
941
942void
943Layer::ScrolledByHook(float dx, float dy)
944{
945	// empty.
946}
947
948//! converts a point from local to parent's coordinate system
949void
950Layer::ConvertToParent(BPoint* pt) const
951{
952	if (fParent) {
953		BPoint origin = BoundsOrigin();
954		pt->x -= origin.x;
955		pt->y -= origin.y;
956		pt->x += fFrame.left;
957		pt->y += fFrame.top;
958	}
959}
960
961//! converts a rect from local to parent's coordinate system
962void
963Layer::ConvertToParent(BRect* rect) const
964{
965	if (fParent) {
966		BPoint origin = BoundsOrigin();
967		rect->OffsetBy(-origin.x, -origin.y);
968		rect->OffsetBy(fFrame.left, fFrame.top);
969	}
970}
971
972//! converts a region from local to parent's coordinate system
973void
974Layer::ConvertToParent(BRegion* reg) const
975{
976	if (fParent) {
977		BPoint origin = BoundsOrigin();
978		reg->OffsetBy(-origin.x, -origin.y);
979		reg->OffsetBy(fFrame.left, fFrame.top);
980	}
981}
982
983//! converts a point from parent's to local coordinate system
984void
985Layer::ConvertFromParent(BPoint* pt) const
986{
987	if (fParent) {
988		BPoint origin = BoundsOrigin();
989		pt->x += origin.x;
990		pt->y += origin.y;
991		pt->x -= fFrame.left;
992		pt->y -= fFrame.top;
993	}
994}
995
996//! converts a rect from parent's to local coordinate system
997void
998Layer::ConvertFromParent(BRect* rect) const
999{
1000	if (fParent) {
1001		BPoint origin = BoundsOrigin();
1002		rect->OffsetBy(origin.x, origin.y);
1003		rect->OffsetBy(-fFrame.left, -fFrame.top);
1004	}
1005}
1006
1007//! converts a region from parent's to local coordinate system
1008void
1009Layer::ConvertFromParent(BRegion* reg) const
1010{
1011	if (fParent) {
1012		BPoint origin = BoundsOrigin();
1013		reg->OffsetBy(origin.x, origin.y);
1014		reg->OffsetBy(-fFrame.left, -fFrame.top);
1015	}
1016}
1017
1018//! converts a point from local to screen coordinate system
1019void
1020Layer::ConvertToScreen(BPoint* pt) const
1021{
1022	if (fParent) {
1023		ConvertToParent(pt);
1024		fParent->ConvertToScreen(pt);
1025	}
1026}
1027
1028//! converts a rect from local to screen coordinate system
1029void
1030Layer::ConvertToScreen(BRect* rect) const
1031{
1032	if (fParent) {
1033		ConvertToParent(rect);
1034		fParent->ConvertToScreen(rect);
1035	}
1036}
1037
1038//! converts a region from local to screen coordinate system
1039void
1040Layer::ConvertToScreen(BRegion* reg) const
1041{
1042	if (fParent) {
1043		ConvertToParent(reg);
1044		fParent->ConvertToScreen(reg);
1045	}
1046}
1047
1048//! converts a point from screen to local coordinate system
1049void
1050Layer::ConvertFromScreen(BPoint* pt) const
1051{
1052	if (fParent) {
1053		ConvertFromParent(pt);
1054		fParent->ConvertFromScreen(pt);
1055	}
1056}
1057
1058//! converts a rect from screen to local coordinate system
1059void
1060Layer::ConvertFromScreen(BRect* rect) const
1061{
1062	if (fParent) {
1063		ConvertFromParent(rect);
1064		fParent->ConvertFromScreen(rect);
1065	}
1066}
1067
1068//! converts a region from screen to local coordinate system
1069void
1070Layer::ConvertFromScreen(BRegion* reg) const
1071{
1072	if (fParent) {
1073		ConvertFromParent(reg);
1074		fParent->ConvertFromScreen(reg);
1075	}
1076}
1077
1078void
1079Layer::_ResizeLayerFrameBy(float x, float y)
1080{
1081	uint16 rm = fResizeMode & 0x0000FFFF;
1082	BRect newFrame = fFrame;
1083
1084	if ((rm & 0x0F00U) == _VIEW_LEFT_ << 8)
1085		newFrame.left += 0.0f;
1086	else if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8)
1087		newFrame.left += x;
1088	else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8)
1089		newFrame.left += x/2;
1090
1091	if ((rm & 0x000FU) == _VIEW_LEFT_)
1092		newFrame.right += 0.0f;
1093	else if ((rm & 0x000FU) == _VIEW_RIGHT_)
1094		newFrame.right += x;
1095	else if ((rm & 0x000FU) == _VIEW_CENTER_)
1096		newFrame.right += x/2;
1097
1098	if ((rm & 0xF000U) == _VIEW_TOP_ << 12)
1099		newFrame.top += 0.0f;
1100	else if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12)
1101		newFrame.top += y;
1102	else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12)
1103		newFrame.top += y/2;
1104
1105	if ((rm & 0x00F0U) == _VIEW_TOP_ << 4)
1106		newFrame.bottom += 0.0f;
1107	else if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4)
1108		newFrame.bottom += y;
1109	else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4)
1110		newFrame.bottom += y/2;
1111
1112	if (newFrame != fFrame) {
1113		float offsetX, offsetY;
1114		float dx, dy;
1115
1116		dx = newFrame.Width() - fFrame.Width();
1117		dy = newFrame.Height() - fFrame.Height();
1118		offsetX = newFrame.left - fFrame.left;
1119		offsetY = newFrame.top - fFrame.top;
1120
1121		fFrame = newFrame;
1122
1123		if (offsetX != 0.0f || offsetY != 0.0f) {
1124			MovedByHook(offsetX, offsetY);
1125		}
1126
1127		if (dx != 0.0f || dy != 0.0f) {
1128			// call hook function
1129			ResizedByHook(dx, dy, true); // automatic
1130
1131			for (Layer* child = LastChild(); child; child = PreviousChild())
1132				child->_ResizeLayerFrameBy(dx, dy);
1133		}
1134	}
1135}
1136
1137
1138void
1139Layer::_RezizeLayerRedrawMore(BRegion &reg, float dx, float dy)
1140{
1141	if (dx == 0 && dy == 0)
1142		return;
1143
1144	for (Layer* child = LastChild(); child; child = PreviousChild()) {
1145		uint16 rm = child->fResizeMode & 0x0000FFFF;
1146
1147		if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) {
1148			// NOTE: this is not exactly corect, but it works :-)
1149			// Normaly we shoud've used the child's old, required region - the one returned
1150			// from get_user_region() with the old frame, and the current one. child->Bounds()
1151			// works for the moment so we leave it like this.
1152
1153			// calculate the old bounds.
1154			BRect	oldBounds(child->Bounds());
1155			if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT)
1156				oldBounds.right -=dx;
1157			if ((rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM)
1158				oldBounds.bottom -=dy;
1159
1160			// compute the region that became visible because we got bigger OR smaller.
1161			BRegion	regZ(child->Bounds());
1162			regZ.Include(oldBounds);
1163			regZ.Exclude(oldBounds & child->Bounds());
1164
1165			child->ConvertToScreen(&regZ);
1166
1167			// intersect that with this'(not child's) fullVisible region
1168			regZ.IntersectWith(&fFullVisible);
1169			reg.Include(&regZ);
1170
1171			child->_RezizeLayerRedrawMore(reg,
1172				(rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0,
1173				(rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0);
1174
1175			// above, OR this:
1176			// reg.Include(&child->fFullVisible);
1177		} else if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0)
1178			|| ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0)
1179			|| ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)
1180			|| ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0)) {
1181			reg.Include(&child->fFullVisible);
1182		}
1183	}
1184}
1185
1186
1187void
1188Layer::_ResizeLayerFullUpdateOnResize(BRegion &reg, float dx, float dy)
1189{
1190	if (dx == 0 && dy == 0)
1191		return;
1192
1193	for (Layer* child = LastChild(); child; child = PreviousChild()) {
1194		uint16 rm = child->fResizeMode & 0x0000FFFF;
1195
1196		if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) {
1197			if (child->fFlags & B_FULL_UPDATE_ON_RESIZE && child->fVisible.CountRects() > 0)
1198				reg.Include(&child->fVisible);
1199
1200			child->_ResizeLayerFullUpdateOnResize(reg,
1201				(rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0,
1202				(rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0);
1203		}
1204	}
1205}
1206
1207
1208/*!
1209	\brief Returns the region of the layer that is within the screen region
1210*/
1211void
1212Layer::GetOnScreenRegion(BRegion &region)
1213{
1214	// 1) set to frame in screen coords
1215	BRect frame(Bounds());
1216	ConvertToScreen(&frame);
1217	region.Set(frame);
1218
1219	// 2) intersect with screen region
1220	BRegion screenRegion(GetRootLayer()->Bounds());
1221	region.IntersectWith(&screenRegion);
1222
1223/*
1224	// 3) impose user constrained regions
1225	DrawState *stackData = fDrawState;
1226	while (stackData) {
1227		if (stackData->ClippingRegion()) {
1228			reg.IntersectWith(stackData->ClippingRegion());
1229		}
1230		stackData = stackData->PreviousState();
1231	}*/
1232}
1233
1234
1235void
1236Layer::_RebuildVisibleRegions(const BRegion &invalid,
1237	const BRegion &parentLocalVisible, const Layer *startFrom)
1238{
1239/*
1240	// no point in continuing if this layer is hidden.
1241	if (fHidden)
1242		return;
1243
1244	// no need to go deeper if the parent doesn't have a visible region anymore
1245	// and our fullVisible region is also empty.
1246	if (!parentLocalVisible.Frame().IsValid() && !(fFullVisible.CountRects() > 0))
1247		return;
1248
1249	bool fullRebuild = false;
1250
1251	// intersect maximum wanted region with the invalid region
1252	BRegion common;
1253	GetOnScreenRegion(common);
1254	common.IntersectWith(&invalid);
1255
1256	// if the resulted region is not valid, this layer is not in the catchment area
1257	// of the region being invalidated
1258	if (!common.CountRects() > 0)
1259		return;
1260
1261	// now intersect with parent's visible part of the region that was/is invalidated
1262	common.IntersectWith(&parentLocalVisible);
1263
1264	// exclude the invalid region
1265	fFullVisible.Exclude(&invalid);
1266	fVisible.Exclude(&invalid);
1267
1268	// put in what's really visible
1269	fFullVisible.Include(&common);
1270
1271	// allow this layer to hide some parts from its children
1272	_ReserveRegions(common);
1273
1274	for (Layer *child = LastChild(); child; child = PreviousChild()) {
1275		if (child == startFrom)
1276			fullRebuild = true;
1277
1278		if (fullRebuild)
1279			child->_RebuildVisibleRegions(invalid, common, child->LastChild());
1280
1281		// to let children know much they can take from parent's visible region
1282		common.Exclude(&child->fFullVisible);
1283	}
1284
1285	// include what's left after all children took what they could.
1286	fVisible.Include(&common);
1287*/
1288
1289// NOTE: I modified this method for the moment because of some issues that I have
1290//		 with the new public methods that I recently introduced.
1291//		 This code works very well, the single problem that it has it's that it
1292//		 rebuilds all the visible regions of its descendants.
1293// TODO: only rebuild what's needed. See above code.
1294// NOTE2: this does not affect the redrawing code.
1295
1296	// no point in continuing if this layer is hidden.
1297	if (fHidden)
1298		return;
1299
1300	// no need to go deeper if the parent doesn't have a visible region anymore
1301	if (!parentLocalVisible.Frame().IsValid())
1302		return;
1303
1304	BRegion common;
1305	GetOnScreenRegion(common);
1306
1307	// see how much you can take
1308	common.IntersectWith(&parentLocalVisible);
1309	fFullVisible = common;
1310	fVisible.MakeEmpty();
1311
1312	// allow this layer to hide some parts from its children
1313	_ReserveRegions(common);
1314
1315	for (Layer *child = LastChild(); child; child = PreviousChild()) {
1316		child->_RebuildVisibleRegions(invalid, common, child->LastChild());
1317
1318		// to let children know much they can take from parent's visible region
1319		common.Exclude(&child->fFullVisible);
1320	}
1321
1322	// include what's left after all children took what they could.
1323	fVisible.Include(&common);
1324
1325	_RebuildDrawingRegion();
1326}
1327
1328// _RebuildDrawingRegion
1329void
1330Layer::_RebuildDrawingRegion()
1331{
1332	fDrawingRegion = fVisible;
1333	// apply user clipping which is in native coordinate system
1334	if (const BRegion* userClipping = fDrawState->ClippingRegion()) {
1335		BRegion screenUserClipping(*userClipping);
1336		ConvertToScreen(&screenUserClipping);
1337		fDrawingRegion.IntersectWith(&screenUserClipping);
1338	}
1339}
1340
1341void
1342Layer::_ReserveRegions(BRegion &reg)
1343{
1344	// Empty for Layer objects
1345}
1346
1347void
1348Layer::_ClearVisibleRegions()
1349{
1350	fDrawingRegion.MakeEmpty();
1351
1352	fVisible.MakeEmpty();
1353	fFullVisible.MakeEmpty();
1354	for (Layer *child = LastChild(); child; child = PreviousChild())
1355		child->_ClearVisibleRegions();
1356}
1357
1358// mark a region dirty so that the next region rebuild for us
1359// and our children will take this into account
1360void
1361Layer::MarkForRebuild(const BRegion &dirty)
1362{
1363	fDirtyForRebuild.Include(&dirty);
1364}
1365
1366// this will trigger visible region recalculation for us and
1367// our descendants.
1368void
1369Layer::TriggerRebuild()
1370{
1371	BRegion totalInvalidReg;
1372
1373	_GetAllRebuildDirty(&totalInvalidReg);
1374
1375	if (totalInvalidReg.CountRects() > 0) {
1376		BRegion localFullVisible(fFullVisible);
1377
1378//		localFullVisible.IntersectWith(&totalInvalidReg);
1379
1380		_ClearVisibleRegions();
1381
1382		_RebuildVisibleRegions(totalInvalidReg, localFullVisible, LastChild());
1383	}
1384}
1385
1386// find out the region for which we must rebuild the visible regions
1387void
1388Layer::_GetAllRebuildDirty(BRegion *totalReg)
1389{
1390	totalReg->Include(&fDirtyForRebuild);
1391
1392	for (Layer *child = LastChild(); child; child = PreviousChild())
1393		child->_GetAllRebuildDirty(totalReg);
1394
1395	fDirtyForRebuild.MakeEmpty();
1396}
1397
1398void
1399Layer::_AllRedraw(const BRegion &invalid)
1400{
1401	// couldn't find a simpler way to send _UPDATE_ message to client.
1402	WinBorder *wb = dynamic_cast<WinBorder*>(this);
1403	if (wb)
1404		wb->RequestClientRedraw(invalid);
1405
1406	if (fVisible.CountRects() > 0) {
1407		BRegion	updateReg(fVisible);
1408		updateReg.IntersectWith(&invalid);
1409
1410		if (updateReg.CountRects() > 0) {
1411			fDriver->ConstrainClippingRegion(&updateReg);
1412			Draw(updateReg.Frame());
1413			fDriver->ConstrainClippingRegion(NULL);
1414		}
1415	}
1416
1417	for (Layer *child = LastChild(); child != NULL; child = PreviousChild()) {
1418		if (!(child->IsHidden())) {
1419			BRegion common(child->fFullVisible);
1420			common.IntersectWith(&invalid);
1421
1422			if (common.CountRects() > 0)
1423				child->_AllRedraw(invalid);
1424		}
1425	}
1426}
1427
1428void
1429Layer::_AddToViewsWithInvalidCoords() const
1430{
1431	if (fServerWin) {
1432		fServerWin->ClientViewsWithInvalidCoords().AddInt32("_token", fViewToken);
1433		fServerWin->ClientViewsWithInvalidCoords().AddPoint("where", fFrame.LeftTop());
1434		fServerWin->ClientViewsWithInvalidCoords().AddFloat("width", fFrame.Width());
1435		fServerWin->ClientViewsWithInvalidCoords().AddFloat("height", fFrame.Height());
1436	}
1437}
1438
1439
1440void
1441Layer::_SendViewCoordUpdateMsg() const
1442{
1443	if (fServerWin && !fServerWin->ClientViewsWithInvalidCoords().IsEmpty()) {
1444		fServerWin->SendMessageToClient(&fServerWin->ClientViewsWithInvalidCoords());
1445		fServerWin->ClientViewsWithInvalidCoords().MakeEmpty();
1446	}
1447}
1448