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