1/*
2 * Copyright 2001-2012, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Adrian Oanca <adioanca@cotty.iren.ro>
7 *		Axel Dörfler, axeld@pinc-software.de
8 *		Stephan Aßmus <superstippi@gmx.de>
9 *		Ingo Weinhold <ingo_weinhold@gmx.de>
10 */
11
12
13#include <View.h>
14
15#include <new>
16
17#include <math.h>
18#include <stdio.h>
19
20#include <Application.h>
21#include <Bitmap.h>
22#include <Button.h>
23#include <Cursor.h>
24#include <File.h>
25#include <GradientLinear.h>
26#include <GradientRadial.h>
27#include <GradientRadialFocus.h>
28#include <GradientDiamond.h>
29#include <GradientConic.h>
30#include <InterfaceDefs.h>
31#include <Layout.h>
32#include <LayoutContext.h>
33#include <LayoutUtils.h>
34#include <MenuBar.h>
35#include <Message.h>
36#include <MessageQueue.h>
37#include <ObjectList.h>
38#include <Picture.h>
39#include <Point.h>
40#include <Polygon.h>
41#include <PropertyInfo.h>
42#include <Region.h>
43#include <ScrollBar.h>
44#include <Shape.h>
45#include <Shelf.h>
46#include <String.h>
47#include <Window.h>
48
49#include <AppMisc.h>
50#include <AppServerLink.h>
51#include <binary_compatibility/Interface.h>
52#include <binary_compatibility/Support.h>
53#include <MessagePrivate.h>
54#include <MessageUtils.h>
55#include <PortLink.h>
56#include <ServerProtocol.h>
57#include <ServerProtocolStructs.h>
58#include <ShapePrivate.h>
59#include <ToolTip.h>
60#include <ToolTipManager.h>
61#include <TokenSpace.h>
62#include <ViewPrivate.h>
63
64using std::nothrow;
65
66//#define DEBUG_BVIEW
67#ifdef DEBUG_BVIEW
68#	include <stdio.h>
69#	define STRACE(x) printf x
70#	define BVTRACE _PrintToStream()
71#else
72#	define STRACE(x) ;
73#	define BVTRACE ;
74#endif
75
76
77static property_info sViewPropInfo[] = {
78	{ "Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
79		{ B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0,
80		{ B_RECT_TYPE }
81	},
82	{ "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
83		{ B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.",
84		0, { B_BOOL_TYPE }
85	},
86	{ "Shelf", { 0 },
87		{ B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the "
88			"shelf.", 0
89	},
90	{ "View", { B_COUNT_PROPERTIES, 0 },
91		{ B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0,
92		{ B_INT32_TYPE }
93	},
94	{ "View", { 0 },
95		{ B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 },
96		"Directs the scripting message to the specified view.", 0
97	},
98
99	{ 0, { 0 }, { 0 }, 0, 0 }
100};
101
102
103//	#pragma mark -
104
105
106static inline uint32
107get_uint32_color(rgb_color color)
108{
109	return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color);
110		// rgb_color is always in rgba format, no matter what endian;
111		// we always return the int32 value in host endian.
112}
113
114
115static inline rgb_color
116get_rgb_color(uint32 value)
117{
118	value = B_HOST_TO_BENDIAN_INT32(value);
119	return *(rgb_color*)&value;
120}
121
122
123//	#pragma mark -
124
125
126namespace BPrivate {
127
128ViewState::ViewState()
129{
130	pen_location.Set(0, 0);
131	pen_size = 1.0;
132
133	// NOTE: the clipping_region is empty
134	// on construction but it is not used yet,
135	// we avoid having to keep track of it via
136	// this flag
137	clipping_region_used = false;
138
139	high_color = (rgb_color){ 0, 0, 0, 255 };
140	low_color = (rgb_color){ 255, 255, 255, 255 };
141	view_color = low_color;
142
143	pattern = B_SOLID_HIGH;
144	drawing_mode = B_OP_COPY;
145
146	origin.Set(0, 0);
147
148	line_join = B_MITER_JOIN;
149	line_cap = B_BUTT_CAP;
150	miter_limit = B_DEFAULT_MITER_LIMIT;
151
152	alpha_source_mode = B_PIXEL_ALPHA;
153	alpha_function_mode = B_ALPHA_OVERLAY;
154
155	scale = 1.0;
156
157	font = *be_plain_font;
158	font_flags = font.Flags();
159	font_aliasing = false;
160
161	// We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated,
162	// because we should get the clipping region from app_server.
163	// The other flags do not need to be included because the data they
164	// represent is already in sync with app_server - app_server uses the
165	// same init (default) values.
166	valid_flags = ~B_VIEW_CLIP_REGION_BIT;
167
168	archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT;
169}
170
171
172void
173ViewState::UpdateServerFontState(BPrivate::PortLink &link)
174{
175	link.StartMessage(AS_VIEW_SET_FONT_STATE);
176	link.Attach<uint16>(font_flags);
177		// always present
178
179	if (font_flags & B_FONT_FAMILY_AND_STYLE)
180		link.Attach<uint32>(font.FamilyAndStyle());
181
182	if (font_flags & B_FONT_SIZE)
183		link.Attach<float>(font.Size());
184
185	if (font_flags & B_FONT_SHEAR)
186		link.Attach<float>(font.Shear());
187
188	if (font_flags & B_FONT_ROTATION)
189		link.Attach<float>(font.Rotation());
190
191	if (font_flags & B_FONT_FALSE_BOLD_WIDTH)
192		link.Attach<float>(font.FalseBoldWidth());
193
194	if (font_flags & B_FONT_SPACING)
195		link.Attach<uint8>(font.Spacing());
196
197	if (font_flags & B_FONT_ENCODING)
198		link.Attach<uint8>(font.Encoding());
199
200	if (font_flags & B_FONT_FACE)
201		link.Attach<uint16>(font.Face());
202
203	if (font_flags & B_FONT_FLAGS)
204		link.Attach<uint32>(font.Flags());
205}
206
207
208void
209ViewState::UpdateServerState(BPrivate::PortLink &link)
210{
211	UpdateServerFontState(link);
212
213	link.StartMessage(AS_VIEW_SET_STATE);
214
215	ViewSetStateInfo info;
216	info.penLocation = pen_location;
217	info.penSize = pen_size;
218	info.highColor = high_color;
219	info.lowColor = low_color;
220	info.pattern = pattern;
221	info.drawingMode = drawing_mode;
222	info.origin = origin;
223	info.scale = scale;
224	info.lineJoin = line_join;
225	info.lineCap = line_cap;
226	info.miterLimit = miter_limit;
227	info.alphaSourceMode = alpha_source_mode;
228	info.alphaFunctionMode = alpha_function_mode;
229	info.fontAntialiasing = font_aliasing;
230	link.Attach<ViewSetStateInfo>(info);
231
232	// we send the 'local' clipping region... if we have one...
233	// TODO: Could be optimized, but is low prio, since most views won't
234	// have a custom clipping region.
235	if (clipping_region_used) {
236		int32 count = clipping_region.CountRects();
237		link.Attach<int32>(count);
238		for (int32 i = 0; i < count; i++)
239			link.Attach<BRect>(clipping_region.RectAt(i));
240	} else {
241		// no clipping region
242		link.Attach<int32>(-1);
243	}
244
245	// Although we might have a 'local' clipping region, when we call
246	// BView::GetClippingRegion() we ask for the 'global' one and it
247	// is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag
248
249	valid_flags = ~B_VIEW_CLIP_REGION_BIT;
250}
251
252
253void
254ViewState::UpdateFrom(BPrivate::PortLink &link)
255{
256	link.StartMessage(AS_VIEW_GET_STATE);
257
258	int32 code;
259	if (link.FlushWithReply(code) != B_OK
260		|| code != B_OK)
261		return;
262
263	ViewGetStateInfo info;
264	link.Read<ViewGetStateInfo>(&info);
265
266	// set view's font state
267	font_flags = B_FONT_ALL;
268	font.SetFamilyAndStyle(info.fontID);
269	font.SetSize(info.fontSize);
270	font.SetShear(info.fontShear);
271	font.SetRotation(info.fontRotation);
272	font.SetFalseBoldWidth(info.fontFalseBoldWidth);
273	font.SetSpacing(info.fontSpacing);
274	font.SetEncoding(info.fontEncoding);
275	font.SetFace(info.fontFace);
276	font.SetFlags(info.fontFlags);
277
278	// set view's state
279	pen_location = info.viewStateInfo.penLocation;
280	pen_size = info.viewStateInfo.penSize;
281	high_color = info.viewStateInfo.highColor;
282	low_color = info.viewStateInfo.lowColor;
283	pattern = info.viewStateInfo.pattern;
284	drawing_mode = info.viewStateInfo.drawingMode;
285	origin = info.viewStateInfo.origin;
286	scale = info.viewStateInfo.scale;
287	line_join = info.viewStateInfo.lineJoin;
288	line_cap = info.viewStateInfo.lineCap;
289	miter_limit = info.viewStateInfo.miterLimit;
290	alpha_source_mode = info.viewStateInfo.alphaSourceMode;
291	alpha_function_mode = info.viewStateInfo.alphaFunctionMode;
292	font_aliasing = info.viewStateInfo.fontAntialiasing;
293
294	// read the user clipping
295	// (that's NOT the current View visible clipping but the additional
296	// user specified clipping!)
297	int32 clippingRectCount;
298	link.Read<int32>(&clippingRectCount);
299	if (clippingRectCount >= 0) {
300		clipping_region.MakeEmpty();
301		for (int32 i = 0; i < clippingRectCount; i++) {
302			BRect rect;
303			link.Read<BRect>(&rect);
304			clipping_region.Include(rect);
305		}
306	} else {
307		// no user clipping used
308		clipping_region_used = false;
309	}
310
311	valid_flags = ~B_VIEW_CLIP_REGION_BIT;
312}
313
314}	// namespace BPrivate
315
316
317//	#pragma mark -
318
319
320// archiving constants
321namespace {
322	const char* const kSizesField = "BView:sizes";
323		// kSizesField = {min, max, pref}
324	const char* const kAlignmentField = "BView:alignment";
325	const char* const kLayoutField = "BView:layout";
326}
327
328
329struct BView::LayoutData {
330	LayoutData()
331		:
332		fMinSize(),
333		fMaxSize(),
334		fPreferredSize(),
335		fAlignment(),
336		fLayoutInvalidationDisabled(0),
337		fLayout(NULL),
338		fLayoutContext(NULL),
339		fLayoutItems(5, false),
340		fLayoutValid(true),		// TODO: Rethink these initial values!
341		fMinMaxValid(true),		//
342		fLayoutInProgress(false),
343		fNeedsRelayout(true)
344	{
345	}
346
347	status_t
348	AddDataToArchive(BMessage* archive)
349	{
350		status_t err = archive->AddSize(kSizesField, fMinSize);
351
352		if (err == B_OK)
353			err = archive->AddSize(kSizesField, fMaxSize);
354
355		if (err == B_OK)
356			err = archive->AddSize(kSizesField, fPreferredSize);
357
358		if (err == B_OK)
359			err = archive->AddAlignment(kAlignmentField, fAlignment);
360
361		return err;
362	}
363
364	void
365	PopulateFromArchive(BMessage* archive)
366	{
367		archive->FindSize(kSizesField, 0, &fMinSize);
368		archive->FindSize(kSizesField, 1, &fMaxSize);
369		archive->FindSize(kSizesField, 2, &fPreferredSize);
370		archive->FindAlignment(kAlignmentField, &fAlignment);
371	}
372
373	BSize			fMinSize;
374	BSize			fMaxSize;
375	BSize			fPreferredSize;
376	BAlignment		fAlignment;
377	int				fLayoutInvalidationDisabled;
378	BLayout*		fLayout;
379	BLayoutContext*	fLayoutContext;
380	BObjectList<BLayoutItem> fLayoutItems;
381	bool			fLayoutValid;
382	bool			fMinMaxValid;
383	bool			fLayoutInProgress;
384	bool			fNeedsRelayout;
385};
386
387
388BView::BView(const char* name, uint32 flags, BLayout* layout)
389	:
390	BHandler(name)
391{
392	_InitData(BRect(0, 0, 0, 0), name, B_FOLLOW_NONE,
393		flags | B_SUPPORTS_LAYOUT);
394	SetLayout(layout);
395}
396
397
398BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags)
399	:
400	BHandler(name)
401{
402	_InitData(frame, name, resizingMode, flags);
403}
404
405
406BView::BView(BMessage* archive)
407	:
408	BHandler(BUnarchiver::PrepareArchive(archive))
409{
410	BUnarchiver unarchiver(archive);
411	if (!archive)
412		debugger("BView cannot be constructed from a NULL archive.");
413
414	BRect frame;
415	archive->FindRect("_frame", &frame);
416
417	uint32 resizingMode;
418	if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK)
419		resizingMode = 0;
420
421	uint32 flags;
422	if (archive->FindInt32("_flags", (int32*)&flags) != B_OK)
423		flags = 0;
424
425	_InitData(frame, Name(), resizingMode, flags);
426
427	font_family family;
428	font_style style;
429	if (archive->FindString("_fname", 0, (const char**)&family) == B_OK
430		&& archive->FindString("_fname", 1, (const char**)&style) == B_OK) {
431		BFont font;
432		font.SetFamilyAndStyle(family, style);
433
434		float size;
435		if (archive->FindFloat("_fflt", 0, &size) == B_OK)
436			font.SetSize(size);
437
438		float shear;
439		if (archive->FindFloat("_fflt", 1, &shear) == B_OK
440			&& shear >= 45.0 && shear <= 135.0)
441			font.SetShear(shear);
442
443		float rotation;
444		if (archive->FindFloat("_fflt", 2, &rotation) == B_OK
445			&& rotation >=0 && rotation <= 360)
446			font.SetRotation(rotation);
447
448		SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE
449			| B_FONT_SHEAR | B_FONT_ROTATION);
450	}
451
452	int32 color;
453	if (archive->FindInt32("_color", 0, &color) == B_OK)
454		SetHighColor(get_rgb_color(color));
455	if (archive->FindInt32("_color", 1, &color) == B_OK)
456		SetLowColor(get_rgb_color(color));
457	if (archive->FindInt32("_color", 2, &color) == B_OK)
458		SetViewColor(get_rgb_color(color));
459
460	uint32 evMask;
461	uint32 options;
462	if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK
463		&& archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK)
464		SetEventMask(evMask, options);
465
466	BPoint origin;
467	if (archive->FindPoint("_origin", &origin) == B_OK)
468		SetOrigin(origin);
469
470	float penSize;
471	if (archive->FindFloat("_psize", &penSize) == B_OK)
472		SetPenSize(penSize);
473
474	BPoint penLocation;
475	if (archive->FindPoint("_ploc", &penLocation) == B_OK)
476		MovePenTo(penLocation);
477
478	int16 lineCap;
479	int16 lineJoin;
480	float lineMiter;
481	if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK
482		&& archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK
483		&& archive->FindFloat("_lmmiter", &lineMiter) == B_OK)
484		SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter);
485
486	int16 alphaBlend;
487	int16 modeBlend;
488	if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK
489		&& archive->FindInt16("_blend", 1, &modeBlend) == B_OK)
490		SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend);
491
492	uint32 drawingMode;
493	if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK)
494		SetDrawingMode((drawing_mode)drawingMode);
495
496	fLayoutData->PopulateFromArchive(archive);
497
498	if (archive->FindInt16("_show", &fShowLevel) != B_OK)
499		fShowLevel = 0;
500
501	if (BUnarchiver::IsArchiveManaged(archive)) {
502		int32 i = 0;
503		while (unarchiver.EnsureUnarchived("_views", i++) == B_OK)
504				;
505		unarchiver.EnsureUnarchived(kLayoutField);
506
507	} else {
508		BMessage msg;
509		for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK;
510			i++) {
511			BArchivable* object = instantiate_object(&msg);
512			if (BView* child = dynamic_cast<BView*>(object))
513				AddChild(child);
514		}
515	}
516}
517
518
519BArchivable*
520BView::Instantiate(BMessage* data)
521{
522	if (!validate_instantiation(data , "BView"))
523		return NULL;
524
525	return new(std::nothrow) BView(data);
526}
527
528
529status_t
530BView::Archive(BMessage* data, bool deep) const
531{
532	BArchiver archiver(data);
533	status_t ret = BHandler::Archive(data, deep);
534
535	if (ret != B_OK)
536		return ret;
537
538	if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0)
539		ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset));
540
541	if (ret == B_OK)
542		ret = data->AddInt32("_resize_mode", ResizingMode());
543
544	if (ret == B_OK)
545		ret = data->AddInt32("_flags", Flags());
546
547	if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) {
548		ret = data->AddInt32("_evmask", fEventMask);
549		if (ret == B_OK)
550			ret = data->AddInt32("_evmask", fEventOptions);
551	}
552
553	if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) {
554		BFont font;
555		GetFont(&font);
556
557		font_family family;
558		font_style style;
559		font.GetFamilyAndStyle(&family, &style);
560		ret = data->AddString("_fname", family);
561		if (ret == B_OK)
562			ret = data->AddString("_fname", style);
563		if (ret == B_OK)
564			ret = data->AddFloat("_fflt", font.Size());
565		if (ret == B_OK)
566			ret = data->AddFloat("_fflt", font.Shear());
567		if (ret == B_OK)
568			ret = data->AddFloat("_fflt", font.Rotation());
569	}
570
571	// colors
572	if (ret == B_OK)
573		ret = data->AddInt32("_color", get_uint32_color(HighColor()));
574	if (ret == B_OK)
575		ret = data->AddInt32("_color", get_uint32_color(LowColor()));
576	if (ret == B_OK)
577		ret = data->AddInt32("_color", get_uint32_color(ViewColor()));
578
579//	NOTE: we do not use this flag any more
580//	if ( 1 ){
581//		ret = data->AddInt32("_dbuf", 1);
582//	}
583
584	if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0)
585		ret = data->AddPoint("_origin", Origin());
586
587	if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0)
588		ret = data->AddFloat("_psize", PenSize());
589
590	if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0)
591		ret = data->AddPoint("_ploc", PenLocation());
592
593	if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) {
594		ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode());
595		if (ret == B_OK)
596			ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode());
597		if (ret == B_OK)
598			ret = data->AddFloat("_lmmiter", LineMiterLimit());
599	}
600
601	if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) {
602		source_alpha alphaSourceMode;
603		alpha_function alphaFunctionMode;
604		GetBlendingMode(&alphaSourceMode, &alphaFunctionMode);
605
606		ret = data->AddInt16("_blend", (int16)alphaSourceMode);
607		if (ret == B_OK)
608			ret = data->AddInt16("_blend", (int16)alphaFunctionMode);
609	}
610
611	if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0)
612		ret = data->AddInt32("_dmod", DrawingMode());
613
614	if (ret == B_OK)
615		ret = fLayoutData->AddDataToArchive(data);
616
617	if (ret == B_OK)
618		ret = data->AddInt16("_show", fShowLevel);
619
620	if (deep && ret == B_OK) {
621		for (BView* child = fFirstChild; child != NULL && ret == B_OK;
622			child = child->fNextSibling)
623			ret = archiver.AddArchivable("_views", child, deep);
624
625		if (ret == B_OK)
626			ret = archiver.AddArchivable(kLayoutField, GetLayout(), deep);
627	}
628
629	return archiver.Finish(ret);
630}
631
632
633status_t
634BView::AllUnarchived(const BMessage* from)
635{
636	BUnarchiver unarchiver(from);
637	status_t err = B_OK;
638
639	int32 count;
640	from->GetInfo("_views", NULL, &count);
641
642	for (int32 i = 0; err == B_OK && i < count; i++) {
643		BView* child;
644		err = unarchiver.FindObject<BView>("_views", i, child);
645		if (err == B_OK)
646			err = _AddChild(child, NULL) ? B_OK : B_ERROR;
647	}
648
649	if (err == B_OK) {
650		BLayout*& layout = fLayoutData->fLayout;
651		err = unarchiver.FindObject(kLayoutField, layout);
652		if (err == B_OK && layout) {
653			fFlags |= B_SUPPORTS_LAYOUT;
654			fLayoutData->fLayout->SetOwner(this);
655		}
656	}
657
658	return err;
659}
660
661
662status_t
663BView::AllArchived(BMessage* into) const
664{
665	return BHandler::AllArchived(into);
666}
667
668
669BView::~BView()
670{
671	STRACE(("BView(%s)::~BView()\n", this->Name()));
672
673	if (fOwner) {
674		debugger("Trying to delete a view that belongs to a window. "
675			"Call RemoveSelf first.");
676	}
677
678	RemoveSelf();
679
680	if (fToolTip != NULL)
681		fToolTip->ReleaseReference();
682
683	// TODO: see about BShelf! must I delete it here? is it deleted by
684	// the window?
685
686	// we also delete all our children
687
688	BView* child = fFirstChild;
689	while (child) {
690		BView* nextChild = child->fNextSibling;
691
692		delete child;
693		child = nextChild;
694	}
695
696	// delete the layout and the layout data
697	delete fLayoutData->fLayout;
698	delete fLayoutData;
699
700	if (fVerScroller)
701		fVerScroller->SetTarget((BView*)NULL);
702	if (fHorScroller)
703		fHorScroller->SetTarget((BView*)NULL);
704
705	SetName(NULL);
706
707	_RemoveCommArray();
708	delete fState;
709}
710
711
712BRect
713BView::Bounds() const
714{
715	_CheckLock();
716
717	if (fIsPrinting)
718		return fState->print_rect;
719
720	return fBounds;
721}
722
723
724void
725BView::_ConvertToParent(BPoint* point, bool checkLock) const
726{
727	if (!fParent)
728		return;
729
730	if (checkLock)
731		_CheckLock();
732
733	// - our scrolling offset
734	// + our bounds location within the parent
735	point->x += -fBounds.left + fParentOffset.x;
736	point->y += -fBounds.top + fParentOffset.y;
737}
738
739
740void
741BView::ConvertToParent(BPoint* point) const
742{
743	_ConvertToParent(point, true);
744}
745
746
747BPoint
748BView::ConvertToParent(BPoint point) const
749{
750	ConvertToParent(&point);
751
752	return point;
753}
754
755
756void
757BView::_ConvertFromParent(BPoint* point, bool checkLock) const
758{
759	if (!fParent)
760		return;
761
762	if (checkLock)
763		_CheckLock();
764
765	// - our bounds location within the parent
766	// + our scrolling offset
767	point->x += -fParentOffset.x + fBounds.left;
768	point->y += -fParentOffset.y + fBounds.top;
769}
770
771
772void
773BView::ConvertFromParent(BPoint* point) const
774{
775	_ConvertFromParent(point, true);
776}
777
778
779BPoint
780BView::ConvertFromParent(BPoint point) const
781{
782	ConvertFromParent(&point);
783
784	return point;
785}
786
787
788void
789BView::ConvertToParent(BRect* rect) const
790{
791	if (!fParent)
792		return;
793
794	_CheckLock();
795
796	// - our scrolling offset
797	// + our bounds location within the parent
798	rect->OffsetBy(-fBounds.left + fParentOffset.x,
799		-fBounds.top + fParentOffset.y);
800}
801
802
803BRect
804BView::ConvertToParent(BRect rect) const
805{
806	ConvertToParent(&rect);
807
808	return rect;
809}
810
811
812void
813BView::ConvertFromParent(BRect* rect) const
814{
815	if (!fParent)
816		return;
817
818	_CheckLock();
819
820	// - our bounds location within the parent
821	// + our scrolling offset
822	rect->OffsetBy(-fParentOffset.x + fBounds.left,
823		-fParentOffset.y + fBounds.top);
824}
825
826
827BRect
828BView::ConvertFromParent(BRect rect) const
829{
830	ConvertFromParent(&rect);
831
832	return rect;
833}
834
835
836void
837BView::_ConvertToScreen(BPoint* pt, bool checkLock) const
838{
839	if (!fParent) {
840		if (fOwner)
841			fOwner->ConvertToScreen(pt);
842
843		return;
844	}
845
846	if (checkLock)
847		_CheckOwnerLock();
848
849	_ConvertToParent(pt, false);
850	fParent->_ConvertToScreen(pt, false);
851}
852
853
854void
855BView::ConvertToScreen(BPoint* pt) const
856{
857	_ConvertToScreen(pt, true);
858}
859
860
861BPoint
862BView::ConvertToScreen(BPoint pt) const
863{
864	ConvertToScreen(&pt);
865
866	return pt;
867}
868
869
870void
871BView::_ConvertFromScreen(BPoint* pt, bool checkLock) const
872{
873	if (!fParent) {
874		if (fOwner)
875			fOwner->ConvertFromScreen(pt);
876
877		return;
878	}
879
880	if (checkLock)
881		_CheckOwnerLock();
882
883	_ConvertFromParent(pt, false);
884	fParent->_ConvertFromScreen(pt, false);
885}
886
887
888void
889BView::ConvertFromScreen(BPoint* pt) const
890{
891	_ConvertFromScreen(pt, true);
892}
893
894
895BPoint
896BView::ConvertFromScreen(BPoint pt) const
897{
898	ConvertFromScreen(&pt);
899
900	return pt;
901}
902
903
904void
905BView::ConvertToScreen(BRect* rect) const
906{
907	BPoint offset(0.0, 0.0);
908	ConvertToScreen(&offset);
909	rect->OffsetBy(offset);
910}
911
912
913BRect
914BView::ConvertToScreen(BRect rect) const
915{
916	ConvertToScreen(&rect);
917
918	return rect;
919}
920
921
922void
923BView::ConvertFromScreen(BRect* rect) const
924{
925	BPoint offset(0.0, 0.0);
926	ConvertFromScreen(&offset);
927	rect->OffsetBy(offset);
928}
929
930
931BRect
932BView::ConvertFromScreen(BRect rect) const
933{
934	ConvertFromScreen(&rect);
935
936	return rect;
937}
938
939
940uint32
941BView::Flags() const
942{
943	_CheckLock();
944	return fFlags & ~_RESIZE_MASK_;
945}
946
947
948void
949BView::SetFlags(uint32 flags)
950{
951	if (Flags() == flags)
952		return;
953
954	if (fOwner) {
955		if (flags & B_PULSE_NEEDED) {
956			_CheckLock();
957			if (fOwner->fPulseRunner == NULL)
958				fOwner->SetPulseRate(fOwner->PulseRate());
959		}
960
961		uint32 changesFlags = flags ^ fFlags;
962		if (changesFlags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
963				| B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) {
964			_CheckLockAndSwitchCurrent();
965
966			fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS);
967			fOwner->fLink->Attach<uint32>(flags);
968			fOwner->fLink->Flush();
969		}
970	}
971
972	/* Some useful info:
973		fFlags is a unsigned long (32 bits)
974		* bits 1-16 are used for BView's flags
975		* bits 17-32 are used for BView' resize mask
976		* _RESIZE_MASK_ is used for that. Look into View.h to see how
977			it's defined
978	*/
979	fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_);
980
981	fState->archiving_flags |= B_VIEW_FLAGS_BIT;
982}
983
984
985BRect
986BView::Frame() const
987{
988	return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y);
989}
990
991
992void
993BView::Hide()
994{
995	if (fOwner && fShowLevel == 0) {
996		_CheckLockAndSwitchCurrent();
997		fOwner->fLink->StartMessage(AS_VIEW_HIDE);
998		fOwner->fLink->Flush();
999	}
1000	fShowLevel++;
1001
1002	if (fShowLevel == 1)
1003		_InvalidateParentLayout();
1004}
1005
1006
1007void
1008BView::Show()
1009{
1010	fShowLevel--;
1011	if (fOwner && fShowLevel == 0) {
1012		_CheckLockAndSwitchCurrent();
1013		fOwner->fLink->StartMessage(AS_VIEW_SHOW);
1014		fOwner->fLink->Flush();
1015	}
1016
1017	if (fShowLevel == 0)
1018		_InvalidateParentLayout();
1019}
1020
1021
1022bool
1023BView::IsFocus() const
1024{
1025	if (fOwner) {
1026		_CheckLock();
1027		return fOwner->CurrentFocus() == this;
1028	} else
1029		return false;
1030}
1031
1032
1033bool
1034BView::IsHidden(const BView* lookingFrom) const
1035{
1036	if (fShowLevel > 0)
1037		return true;
1038
1039	// may we be egocentric?
1040	if (lookingFrom == this)
1041		return false;
1042
1043	// we have the same visibility state as our
1044	// parent, if there is one
1045	if (fParent)
1046		return fParent->IsHidden(lookingFrom);
1047
1048	// if we're the top view, and we're interested
1049	// in the "global" view, we're inheriting the
1050	// state of the window's visibility
1051	if (fOwner && lookingFrom == NULL)
1052		return fOwner->IsHidden();
1053
1054	return false;
1055}
1056
1057
1058bool
1059BView::IsHidden() const
1060{
1061	return IsHidden(NULL);
1062}
1063
1064
1065bool
1066BView::IsPrinting() const
1067{
1068	return fIsPrinting;
1069}
1070
1071
1072BPoint
1073BView::LeftTop() const
1074{
1075	return Bounds().LeftTop();
1076}
1077
1078
1079void
1080BView::SetResizingMode(uint32 mode)
1081{
1082	if (fOwner) {
1083		_CheckLockAndSwitchCurrent();
1084
1085		fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE);
1086		fOwner->fLink->Attach<uint32>(mode);
1087	}
1088
1089	// look at SetFlags() for more info on the below line
1090	fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_);
1091}
1092
1093
1094uint32
1095BView::ResizingMode() const
1096{
1097	return fFlags & _RESIZE_MASK_;
1098}
1099
1100
1101void
1102BView::SetViewCursor(const BCursor* cursor, bool sync)
1103{
1104	if (cursor == NULL || fOwner == NULL)
1105		return;
1106
1107	_CheckLock();
1108
1109	ViewSetViewCursorInfo info;
1110	info.cursorToken = cursor->fServerToken;
1111	info.viewToken = _get_object_token_(this);
1112	info.sync = sync;
1113
1114	BPrivate::AppServerLink link;
1115	link.StartMessage(AS_SET_VIEW_CURSOR);
1116	link.Attach<ViewSetViewCursorInfo>(info);
1117
1118	if (sync) {
1119		// Make sure the server has processed the message.
1120		int32 code;
1121		link.FlushWithReply(code);
1122	}
1123}
1124
1125
1126void
1127BView::Flush() const
1128{
1129	if (fOwner)
1130		fOwner->Flush();
1131}
1132
1133
1134void
1135BView::Sync() const
1136{
1137	_CheckOwnerLock();
1138	if (fOwner)
1139		fOwner->Sync();
1140}
1141
1142
1143BWindow*
1144BView::Window() const
1145{
1146	return fOwner;
1147}
1148
1149
1150//	#pragma mark - Hook Functions
1151
1152
1153void
1154BView::AttachedToWindow()
1155{
1156	// Hook function
1157	STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name()));
1158}
1159
1160
1161void
1162BView::AllAttached()
1163{
1164	// Hook function
1165	STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name()));
1166}
1167
1168
1169void
1170BView::DetachedFromWindow()
1171{
1172	// Hook function
1173	STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name()));
1174}
1175
1176
1177void
1178BView::AllDetached()
1179{
1180	// Hook function
1181	STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name()));
1182}
1183
1184
1185void
1186BView::Draw(BRect updateRect)
1187{
1188	// Hook function
1189	STRACE(("\tHOOK: BView(%s)::Draw()\n", Name()));
1190}
1191
1192
1193void
1194BView::DrawAfterChildren(BRect r)
1195{
1196	// Hook function
1197	STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name()));
1198}
1199
1200
1201void
1202BView::FrameMoved(BPoint newPosition)
1203{
1204	// Hook function
1205	STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name()));
1206}
1207
1208
1209void
1210BView::FrameResized(float newWidth, float newHeight)
1211{
1212	// Hook function
1213	STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name()));
1214}
1215
1216
1217void
1218BView::GetPreferredSize(float* _width, float* _height)
1219{
1220	STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name()));
1221
1222	if (_width != NULL)
1223		*_width = fBounds.Width();
1224	if (_height != NULL)
1225		*_height = fBounds.Height();
1226}
1227
1228
1229void
1230BView::ResizeToPreferred()
1231{
1232	STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name()));
1233
1234	float width;
1235	float height;
1236	GetPreferredSize(&width, &height);
1237
1238	ResizeTo(width, height);
1239}
1240
1241
1242void
1243BView::KeyDown(const char* bytes, int32 numBytes)
1244{
1245	// Hook function
1246	STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name()));
1247
1248	if (Window())
1249		Window()->_KeyboardNavigation();
1250}
1251
1252
1253void
1254BView::KeyUp(const char* bytes, int32 numBytes)
1255{
1256	// Hook function
1257	STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name()));
1258}
1259
1260
1261void
1262BView::MouseDown(BPoint where)
1263{
1264	// Hook function
1265	STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name()));
1266}
1267
1268
1269void
1270BView::MouseUp(BPoint where)
1271{
1272	// Hook function
1273	STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name()));
1274}
1275
1276
1277void
1278BView::MouseMoved(BPoint where, uint32 code, const BMessage* a_message)
1279{
1280	// Hook function
1281	STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name()));
1282}
1283
1284
1285void
1286BView::Pulse()
1287{
1288	// Hook function
1289	STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name()));
1290}
1291
1292
1293void
1294BView::TargetedByScrollView(BScrollView* scroll_view)
1295{
1296	// Hook function
1297	STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name()));
1298}
1299
1300
1301void
1302BView::WindowActivated(bool state)
1303{
1304	// Hook function
1305	STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name()));
1306}
1307
1308
1309//	#pragma mark - Input Functions
1310
1311
1312void
1313BView::BeginRectTracking(BRect startRect, uint32 style)
1314{
1315	if (_CheckOwnerLockAndSwitchCurrent()) {
1316		fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK);
1317		fOwner->fLink->Attach<BRect>(startRect);
1318		fOwner->fLink->Attach<uint32>(style);
1319		fOwner->fLink->Flush();
1320	}
1321}
1322
1323
1324void
1325BView::EndRectTracking()
1326{
1327	if (_CheckOwnerLockAndSwitchCurrent()) {
1328		fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK);
1329		fOwner->fLink->Flush();
1330	}
1331}
1332
1333
1334void
1335BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo)
1336{
1337	if (!message)
1338		return;
1339
1340	_CheckOwnerLock();
1341
1342	// calculate the offset
1343	BPoint offset;
1344	uint32 buttons;
1345	BMessage* current = fOwner->CurrentMessage();
1346	if (!current || current->FindPoint("be:view_where", &offset) != B_OK)
1347		GetMouse(&offset, &buttons, false);
1348	offset -= dragRect.LeftTop();
1349
1350	if (!dragRect.IsValid()) {
1351		DragMessage(message, NULL, B_OP_BLEND, offset, replyTo);
1352		return;
1353	}
1354
1355	// TODO: that's not really what should happen - the app_server should take
1356	// the chance *NOT* to need to drag a whole bitmap around but just a frame.
1357
1358	// create a drag bitmap for the rect
1359	BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32);
1360	if (bitmap == NULL)
1361		return;
1362
1363	uint32* bits = (uint32*)bitmap->Bits();
1364	uint32 bytesPerRow = bitmap->BytesPerRow();
1365	uint32 width = dragRect.IntegerWidth() + 1;
1366	uint32 height = dragRect.IntegerHeight() + 1;
1367	uint32 lastRow = (height - 1) * width;
1368
1369	memset(bits, 0x00, height * bytesPerRow);
1370
1371	// top
1372	for (uint32 i = 0; i < width; i += 2)
1373		bits[i] = 0xff000000;
1374
1375	// bottom
1376	for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2)
1377		bits[lastRow + i] = 0xff000000;
1378
1379	// left
1380	for (uint32 i = 0; i < lastRow; i += width * 2)
1381		bits[i] = 0xff000000;
1382
1383	// right
1384	for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2)
1385		bits[width - 1 + i] = 0xff000000;
1386
1387	DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo);
1388}
1389
1390
1391void
1392BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset,
1393	BHandler* replyTo)
1394{
1395	DragMessage(message, image, B_OP_COPY, offset, replyTo);
1396}
1397
1398
1399void
1400BView::DragMessage(BMessage* message, BBitmap* image,
1401	drawing_mode dragMode, BPoint offset, BHandler* replyTo)
1402{
1403	if (message == NULL)
1404		return;
1405
1406	if (image == NULL) {
1407		// TODO: workaround for drags without a bitmap - should not be necessary if
1408		//	we move the rectangle dragging into the app_server
1409		image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32);
1410		if (image == NULL)
1411			return;
1412	}
1413
1414	if (replyTo == NULL)
1415		replyTo = this;
1416
1417	if (replyTo->Looper() == NULL)
1418		debugger("DragMessage: warning - the Handler needs a looper");
1419
1420	_CheckOwnerLock();
1421
1422	if (!message->HasInt32("buttons")) {
1423		BMessage* msg = fOwner->CurrentMessage();
1424		uint32 buttons;
1425
1426		if (msg == NULL
1427			|| msg->FindInt32("buttons", (int32*)&buttons) != B_OK) {
1428			BPoint point;
1429			GetMouse(&point, &buttons, false);
1430		}
1431
1432		message->AddInt32("buttons", buttons);
1433	}
1434
1435	BMessage::Private privateMessage(message);
1436	privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper()));
1437
1438	int32 bufferSize = message->FlattenedSize();
1439	char* buffer = new(std::nothrow) char[bufferSize];
1440	if (buffer != NULL) {
1441		message->Flatten(buffer, bufferSize);
1442
1443		fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE);
1444		fOwner->fLink->Attach<int32>(image->_ServerToken());
1445		fOwner->fLink->Attach<int32>((int32)dragMode);
1446		fOwner->fLink->Attach<BPoint>(offset);
1447		fOwner->fLink->Attach<int32>(bufferSize);
1448		fOwner->fLink->Attach(buffer, bufferSize);
1449
1450		// we need to wait for the server
1451		// to actually process this message
1452		// before we can delete the bitmap
1453		int32 code;
1454		fOwner->fLink->FlushWithReply(code);
1455
1456		delete [] buffer;
1457	} else {
1458		fprintf(stderr, "BView::DragMessage() - no memory to flatten drag "
1459			"message\n");
1460	}
1461
1462	delete image;
1463}
1464
1465
1466void
1467BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue)
1468{
1469	if (_location == NULL && _buttons == NULL)
1470		return;
1471
1472	_CheckOwnerLockAndSwitchCurrent();
1473
1474	uint32 eventOptions = fEventOptions | fMouseEventOptions;
1475	bool noHistory = eventOptions & B_NO_POINTER_HISTORY;
1476	bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY;
1477
1478	if (checkMessageQueue && !noHistory) {
1479		Window()->UpdateIfNeeded();
1480		BMessageQueue* queue = Window()->MessageQueue();
1481		queue->Lock();
1482
1483		// Look out for mouse update messages
1484
1485		BMessage* message;
1486		for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) {
1487			switch (message->what) {
1488				case B_MOUSE_MOVED:
1489				case B_MOUSE_UP:
1490				case B_MOUSE_DOWN:
1491					bool deleteMessage;
1492					if (!Window()->_StealMouseMessage(message, deleteMessage))
1493						continue;
1494
1495					if (!fullHistory && message->what == B_MOUSE_MOVED) {
1496						// Check if the message is too old. Some applications
1497						// check the message queue in such a way that mouse
1498						// messages *must* pile up. This check makes them work
1499						// as intended, although these applications could simply
1500						// use the version of BView::GetMouse() that does not
1501						// check the history. Also note that it isn't a problem
1502						// to delete the message in case there is not a newer
1503						// one. If we don't find a message in the queue, we will
1504						// just fall back to asking the app_sever directly. So
1505						// the imposed delay will not be a problem on slower
1506						// computers. This check also prevents another problem,
1507						// when the message that we use is *not* removed from
1508						// the queue. Subsequent calls to GetMouse() would find
1509						// this message over and over!
1510						bigtime_t eventTime;
1511						if (message->FindInt64("when", &eventTime) == B_OK
1512							&& system_time() - eventTime > 10000) {
1513							// just discard the message
1514							if (deleteMessage)
1515								delete message;
1516							continue;
1517						}
1518					}
1519					message->FindPoint("screen_where", _location);
1520					message->FindInt32("buttons", (int32*)_buttons);
1521					queue->Unlock();
1522						// we need to hold the queue lock until here, because
1523						// the message might still be used for something else
1524
1525					if (_location != NULL)
1526						ConvertFromScreen(_location);
1527
1528					if (deleteMessage)
1529						delete message;
1530
1531					return;
1532			}
1533		}
1534		queue->Unlock();
1535	}
1536
1537	// If no mouse update message has been found in the message queue,
1538	// we get the current mouse location and buttons from the app_server
1539
1540	fOwner->fLink->StartMessage(AS_GET_MOUSE);
1541
1542	int32 code;
1543	if (fOwner->fLink->FlushWithReply(code) == B_OK
1544		&& code == B_OK) {
1545		BPoint location;
1546		uint32 buttons;
1547		fOwner->fLink->Read<BPoint>(&location);
1548		fOwner->fLink->Read<uint32>(&buttons);
1549			// TODO: ServerWindow replies with an int32 here
1550
1551		ConvertFromScreen(&location);
1552			// TODO: in beos R5, location is already converted to the view
1553			// local coordinate system, so if an app checks the window message
1554			// queue by itself, it might not find what it expects.
1555			// NOTE: the fact that we have mouse coords in screen space in our
1556			// queue avoids the problem that messages already in the queue will
1557			// be outdated as soon as a window or even the view moves. The
1558			// second situation being quite common actually, also with regards
1559			// to scrolling. An app reading these messages would have to know
1560			// the locations of the window and view for each message...
1561			// otherwise it is potentially broken anyways.
1562		if (_location != NULL)
1563			*_location = location;
1564		if (_buttons != NULL)
1565			*_buttons = buttons;
1566	} else {
1567		if (_location != NULL)
1568			_location->Set(0, 0);
1569		if (_buttons != NULL)
1570			*_buttons = 0;
1571	}
1572}
1573
1574
1575void
1576BView::MakeFocus(bool focusState)
1577{
1578	if (fOwner) {
1579		// TODO: If this view has focus and focusState==false,
1580		// will there really be no other view with focus? No
1581		// cycling to the next one?
1582		BView* focus = fOwner->CurrentFocus();
1583		if (focusState) {
1584			// Unfocus a previous focus view
1585			if (focus && focus != this)
1586				focus->MakeFocus(false);
1587			// if we want to make this view the current focus view
1588			fOwner->_SetFocus(this, true);
1589		} else {
1590			// we want to unfocus this view, but only if it actually has focus
1591			if (focus == this) {
1592				fOwner->_SetFocus(NULL, true);
1593			}
1594		}
1595	}
1596}
1597
1598
1599BScrollBar*
1600BView::ScrollBar(orientation posture) const
1601{
1602	switch (posture) {
1603		case B_VERTICAL:
1604			return fVerScroller;
1605
1606		case B_HORIZONTAL:
1607			return fHorScroller;
1608
1609		default:
1610			return NULL;
1611	}
1612}
1613
1614
1615void
1616BView::ScrollBy(float deltaX, float deltaY)
1617{
1618	ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY));
1619}
1620
1621
1622void
1623BView::ScrollTo(BPoint where)
1624{
1625	// scrolling by fractional values is not supported
1626	where.x = roundf(where.x);
1627	where.y = roundf(where.y);
1628
1629	// no reason to process this further if no scroll is intended.
1630	if (where.x == fBounds.left && where.y == fBounds.top)
1631		return;
1632
1633	// make sure scrolling is within valid bounds
1634	if (fHorScroller) {
1635		float min, max;
1636		fHorScroller->GetRange(&min, &max);
1637
1638		if (where.x < min)
1639			where.x = min;
1640		else if (where.x > max)
1641			where.x = max;
1642	}
1643	if (fVerScroller) {
1644		float min, max;
1645		fVerScroller->GetRange(&min, &max);
1646
1647		if (where.y < min)
1648			where.y = min;
1649		else if (where.y > max)
1650			where.y = max;
1651	}
1652
1653	_CheckLockAndSwitchCurrent();
1654
1655	float xDiff = where.x - fBounds.left;
1656	float yDiff = where.y - fBounds.top;
1657
1658	// if we're attached to a window tell app_server about this change
1659	if (fOwner) {
1660		fOwner->fLink->StartMessage(AS_VIEW_SCROLL);
1661		fOwner->fLink->Attach<float>(xDiff);
1662		fOwner->fLink->Attach<float>(yDiff);
1663
1664		fOwner->fLink->Flush();
1665
1666//		fState->valid_flags &= ~B_VIEW_FRAME_BIT;
1667	}
1668
1669	// we modify our bounds rectangle by deltaX/deltaY coord units hor/ver.
1670	fBounds.OffsetTo(where.x, where.y);
1671
1672	// then set the new values of the scrollbars
1673	if (fHorScroller && xDiff != 0.0)
1674		fHorScroller->SetValue(fBounds.left);
1675	if (fVerScroller && yDiff != 0.0)
1676		fVerScroller->SetValue(fBounds.top);
1677
1678}
1679
1680
1681status_t
1682BView::SetEventMask(uint32 mask, uint32 options)
1683{
1684	if (fEventMask == mask && fEventOptions == options)
1685		return B_OK;
1686
1687	// don't change the mask if it's zero and we've got options
1688	if (mask != 0 || options == 0)
1689		fEventMask = mask | (fEventMask & 0xffff0000);
1690	fEventOptions = options;
1691
1692	fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT;
1693
1694	if (fOwner) {
1695		_CheckLockAndSwitchCurrent();
1696
1697		fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK);
1698		fOwner->fLink->Attach<uint32>(mask);
1699		fOwner->fLink->Attach<uint32>(options);
1700		fOwner->fLink->Flush();
1701	}
1702
1703	return B_OK;
1704}
1705
1706
1707uint32
1708BView::EventMask()
1709{
1710	return fEventMask;
1711}
1712
1713
1714status_t
1715BView::SetMouseEventMask(uint32 mask, uint32 options)
1716{
1717	// Just don't do anything if the view is not yet attached
1718	// or we were called outside of BView::MouseDown()
1719	if (fOwner != NULL
1720		&& fOwner->CurrentMessage() != NULL
1721		&& fOwner->CurrentMessage()->what == B_MOUSE_DOWN) {
1722		_CheckLockAndSwitchCurrent();
1723		fMouseEventOptions = options;
1724
1725		fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK);
1726		fOwner->fLink->Attach<uint32>(mask);
1727		fOwner->fLink->Attach<uint32>(options);
1728		fOwner->fLink->Flush();
1729		return B_OK;
1730	}
1731
1732	return B_ERROR;
1733}
1734
1735
1736//	#pragma mark - Graphic State Functions
1737
1738
1739void
1740BView::PushState()
1741{
1742	_CheckOwnerLockAndSwitchCurrent();
1743
1744	fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
1745
1746	// initialize origin and scale
1747	fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT;
1748	fState->scale = 1.0f;
1749	fState->origin.Set(0, 0);
1750}
1751
1752
1753void
1754BView::PopState()
1755{
1756	_CheckOwnerLockAndSwitchCurrent();
1757
1758	fOwner->fLink->StartMessage(AS_VIEW_POP_STATE);
1759	_FlushIfNotInTransaction();
1760
1761	// invalidate all flags (except those that are not part of pop/push)
1762	fState->valid_flags = B_VIEW_VIEW_COLOR_BIT;
1763}
1764
1765
1766void
1767BView::SetOrigin(BPoint pt)
1768{
1769	SetOrigin(pt.x, pt.y);
1770}
1771
1772
1773void
1774BView::SetOrigin(float x, float y)
1775{
1776	if (fState->IsValid(B_VIEW_ORIGIN_BIT)
1777		&& x == fState->origin.x && y == fState->origin.y)
1778		return;
1779
1780	fState->origin.x = x;
1781	fState->origin.y = y;
1782
1783	if (_CheckOwnerLockAndSwitchCurrent()) {
1784		fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN);
1785		fOwner->fLink->Attach<float>(x);
1786		fOwner->fLink->Attach<float>(y);
1787
1788		fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1789	}
1790
1791	// our local coord system origin has changed, so when archiving we'll add
1792	// this too
1793	fState->archiving_flags |= B_VIEW_ORIGIN_BIT;
1794}
1795
1796
1797BPoint
1798BView::Origin() const
1799{
1800	if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) {
1801		// we don't keep graphics state information, therefor
1802		// we need to ask the server for the origin after PopState()
1803		_CheckOwnerLockAndSwitchCurrent();
1804
1805		fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN);
1806
1807		int32 code;
1808		if (fOwner->fLink->FlushWithReply(code) == B_OK
1809			&& code == B_OK) {
1810			fOwner->fLink->Read<BPoint>(&fState->origin);
1811
1812			fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1813		}
1814	}
1815
1816	return fState->origin;
1817}
1818
1819
1820void
1821BView::SetScale(float scale) const
1822{
1823	if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale)
1824		return;
1825
1826	if (fOwner) {
1827		_CheckLockAndSwitchCurrent();
1828
1829		fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE);
1830		fOwner->fLink->Attach<float>(scale);
1831
1832		fState->valid_flags |= B_VIEW_SCALE_BIT;
1833	}
1834
1835	fState->scale = scale;
1836	fState->archiving_flags |= B_VIEW_SCALE_BIT;
1837}
1838
1839
1840float
1841BView::Scale() const
1842{
1843	if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) {
1844		_CheckLockAndSwitchCurrent();
1845
1846		fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE);
1847
1848 		int32 code;
1849		if (fOwner->fLink->FlushWithReply(code) == B_OK
1850			&& code == B_OK)
1851			fOwner->fLink->Read<float>(&fState->scale);
1852
1853		fState->valid_flags |= B_VIEW_SCALE_BIT;
1854	}
1855
1856	return fState->scale;
1857}
1858
1859
1860void
1861BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit)
1862{
1863	if (fState->IsValid(B_VIEW_LINE_MODES_BIT)
1864		&& lineCap == fState->line_cap && lineJoin == fState->line_join
1865		&& miterLimit == fState->miter_limit)
1866		return;
1867
1868	if (fOwner) {
1869		_CheckLockAndSwitchCurrent();
1870
1871		ViewSetLineModeInfo info;
1872		info.lineJoin = lineJoin;
1873		info.lineCap = lineCap;
1874		info.miterLimit = miterLimit;
1875
1876		fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE);
1877		fOwner->fLink->Attach<ViewSetLineModeInfo>(info);
1878
1879		fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
1880	}
1881
1882	fState->line_cap = lineCap;
1883	fState->line_join = lineJoin;
1884	fState->miter_limit = miterLimit;
1885
1886	fState->archiving_flags |= B_VIEW_LINE_MODES_BIT;
1887}
1888
1889
1890join_mode
1891BView::LineJoinMode() const
1892{
1893	// This will update the current state, if necessary
1894	if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
1895		LineMiterLimit();
1896
1897	return fState->line_join;
1898}
1899
1900
1901cap_mode
1902BView::LineCapMode() const
1903{
1904	// This will update the current state, if necessary
1905	if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
1906		LineMiterLimit();
1907
1908	return fState->line_cap;
1909}
1910
1911
1912float
1913BView::LineMiterLimit() const
1914{
1915	if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) {
1916		_CheckLockAndSwitchCurrent();
1917
1918		fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE);
1919
1920		int32 code;
1921		if (fOwner->fLink->FlushWithReply(code) == B_OK
1922			&& code == B_OK) {
1923
1924			ViewSetLineModeInfo info;
1925			fOwner->fLink->Read<ViewSetLineModeInfo>(&info);
1926
1927			fState->line_cap = info.lineCap;
1928			fState->line_join = info.lineJoin;
1929			fState->miter_limit = info.miterLimit;
1930		}
1931
1932		fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
1933	}
1934
1935	return fState->miter_limit;
1936}
1937
1938
1939void
1940BView::SetDrawingMode(drawing_mode mode)
1941{
1942	if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT)
1943		&& mode == fState->drawing_mode)
1944		return;
1945
1946	if (fOwner) {
1947		_CheckLockAndSwitchCurrent();
1948
1949		fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE);
1950		fOwner->fLink->Attach<int8>((int8)mode);
1951
1952		fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
1953	}
1954
1955	fState->drawing_mode = mode;
1956	fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT;
1957}
1958
1959
1960drawing_mode
1961BView::DrawingMode() const
1962{
1963	if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) {
1964		_CheckLockAndSwitchCurrent();
1965
1966		fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE);
1967
1968		int32 code;
1969		if (fOwner->fLink->FlushWithReply(code) == B_OK
1970			&& code == B_OK) {
1971			int8 drawingMode;
1972			fOwner->fLink->Read<int8>(&drawingMode);
1973
1974			fState->drawing_mode = (drawing_mode)drawingMode;
1975			fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
1976		}
1977	}
1978
1979	return fState->drawing_mode;
1980}
1981
1982
1983void
1984BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction)
1985{
1986	if (fState->IsValid(B_VIEW_BLENDING_BIT)
1987		&& sourceAlpha == fState->alpha_source_mode
1988		&& alphaFunction == fState->alpha_function_mode)
1989		return;
1990
1991	if (fOwner) {
1992		_CheckLockAndSwitchCurrent();
1993
1994		ViewBlendingModeInfo info;
1995		info.sourceAlpha = sourceAlpha;
1996		info.alphaFunction = alphaFunction;
1997
1998		fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE);
1999		fOwner->fLink->Attach<ViewBlendingModeInfo>(info);
2000
2001		fState->valid_flags |= B_VIEW_BLENDING_BIT;
2002	}
2003
2004	fState->alpha_source_mode = sourceAlpha;
2005	fState->alpha_function_mode = alphaFunction;
2006
2007	fState->archiving_flags |= B_VIEW_BLENDING_BIT;
2008}
2009
2010
2011void
2012BView::GetBlendingMode(source_alpha* _sourceAlpha,
2013	alpha_function* _alphaFunction) const
2014{
2015	if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) {
2016		_CheckLockAndSwitchCurrent();
2017
2018		fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE);
2019
2020		int32 code;
2021 		if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2022 			ViewBlendingModeInfo info;
2023			fOwner->fLink->Read<ViewBlendingModeInfo>(&info);
2024
2025			fState->alpha_source_mode = info.sourceAlpha;
2026			fState->alpha_function_mode = info.alphaFunction;
2027
2028			fState->valid_flags |= B_VIEW_BLENDING_BIT;
2029		}
2030	}
2031
2032	if (_sourceAlpha)
2033		*_sourceAlpha = fState->alpha_source_mode;
2034
2035	if (_alphaFunction)
2036		*_alphaFunction = fState->alpha_function_mode;
2037}
2038
2039
2040void
2041BView::MovePenTo(BPoint point)
2042{
2043	MovePenTo(point.x, point.y);
2044}
2045
2046
2047void
2048BView::MovePenTo(float x, float y)
2049{
2050	if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT)
2051		&& x == fState->pen_location.x && y == fState->pen_location.y)
2052		return;
2053
2054	if (fOwner) {
2055		_CheckLockAndSwitchCurrent();
2056
2057		fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC);
2058		fOwner->fLink->Attach<BPoint>(BPoint(x, y));
2059
2060		fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2061	}
2062
2063	fState->pen_location.x = x;
2064	fState->pen_location.y = y;
2065
2066	fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT;
2067}
2068
2069
2070void
2071BView::MovePenBy(float x, float y)
2072{
2073	// this will update the pen location if necessary
2074	if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT))
2075		PenLocation();
2076
2077	MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y);
2078}
2079
2080
2081BPoint
2082BView::PenLocation() const
2083{
2084	if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) {
2085		_CheckLockAndSwitchCurrent();
2086
2087		fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC);
2088
2089		int32 code;
2090		if (fOwner->fLink->FlushWithReply(code) == B_OK
2091			&& code == B_OK) {
2092			fOwner->fLink->Read<BPoint>(&fState->pen_location);
2093
2094			fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2095		}
2096	}
2097
2098	return fState->pen_location;
2099}
2100
2101
2102void
2103BView::SetPenSize(float size)
2104{
2105	if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size)
2106		return;
2107
2108	if (fOwner) {
2109		_CheckLockAndSwitchCurrent();
2110
2111		fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE);
2112		fOwner->fLink->Attach<float>(size);
2113
2114		fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2115	}
2116
2117	fState->pen_size = size;
2118	fState->archiving_flags	|= B_VIEW_PEN_SIZE_BIT;
2119}
2120
2121
2122float
2123BView::PenSize() const
2124{
2125	if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) {
2126		_CheckLockAndSwitchCurrent();
2127
2128		fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE);
2129
2130		int32 code;
2131		if (fOwner->fLink->FlushWithReply(code) == B_OK
2132			&& code == B_OK) {
2133			fOwner->fLink->Read<float>(&fState->pen_size);
2134
2135			fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2136		}
2137	}
2138
2139	return fState->pen_size;
2140}
2141
2142
2143void
2144BView::SetHighColor(rgb_color color)
2145{
2146	// are we up-to-date already?
2147	if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT)
2148		&& fState->high_color == color)
2149		return;
2150
2151	if (fOwner) {
2152		_CheckLockAndSwitchCurrent();
2153
2154		fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR);
2155		fOwner->fLink->Attach<rgb_color>(color);
2156
2157		fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2158	}
2159
2160	fState->high_color = color;
2161
2162	fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT;
2163}
2164
2165
2166rgb_color
2167BView::HighColor() const
2168{
2169	if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) {
2170		_CheckLockAndSwitchCurrent();
2171
2172		fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR);
2173
2174		int32 code;
2175		if (fOwner->fLink->FlushWithReply(code) == B_OK
2176			&& code == B_OK) {
2177			fOwner->fLink->Read<rgb_color>(&fState->high_color);
2178
2179			fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2180		}
2181	}
2182
2183	return fState->high_color;
2184}
2185
2186
2187void
2188BView::SetLowColor(rgb_color color)
2189{
2190	if (fState->IsValid(B_VIEW_LOW_COLOR_BIT)
2191		&& fState->low_color == color)
2192		return;
2193
2194	if (fOwner) {
2195		_CheckLockAndSwitchCurrent();
2196
2197		fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR);
2198		fOwner->fLink->Attach<rgb_color>(color);
2199
2200		fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2201	}
2202
2203	fState->low_color = color;
2204
2205	fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT;
2206}
2207
2208
2209rgb_color
2210BView::LowColor() const
2211{
2212	if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) {
2213		_CheckLockAndSwitchCurrent();
2214
2215		fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR);
2216
2217		int32 code;
2218		if (fOwner->fLink->FlushWithReply(code) == B_OK
2219			&& code == B_OK) {
2220			fOwner->fLink->Read<rgb_color>(&fState->low_color);
2221
2222			fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2223		}
2224	}
2225
2226	return fState->low_color;
2227}
2228
2229
2230void
2231BView::SetViewColor(rgb_color color)
2232{
2233	if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color)
2234		return;
2235
2236	if (fOwner) {
2237		_CheckLockAndSwitchCurrent();
2238
2239		fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR);
2240		fOwner->fLink->Attach<rgb_color>(color);
2241		fOwner->fLink->Flush();
2242
2243		fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2244	}
2245
2246	fState->view_color = color;
2247
2248	fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT;
2249}
2250
2251
2252rgb_color
2253BView::ViewColor() const
2254{
2255	if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) {
2256		_CheckLockAndSwitchCurrent();
2257
2258		fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR);
2259
2260		int32 code;
2261		if (fOwner->fLink->FlushWithReply(code) == B_OK
2262			&& code == B_OK) {
2263			fOwner->fLink->Read<rgb_color>(&fState->view_color);
2264
2265			fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2266		}
2267	}
2268
2269	return fState->view_color;
2270}
2271
2272
2273void
2274BView::ForceFontAliasing(bool enable)
2275{
2276	if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT)
2277		&& enable == fState->font_aliasing)
2278		return;
2279
2280	if (fOwner) {
2281		_CheckLockAndSwitchCurrent();
2282
2283		fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING);
2284		fOwner->fLink->Attach<bool>(enable);
2285
2286		fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT;
2287	}
2288
2289	fState->font_aliasing = enable;
2290	fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT;
2291}
2292
2293
2294void
2295BView::SetFont(const BFont* font, uint32 mask)
2296{
2297	if (!font || mask == 0)
2298		return;
2299
2300	if (mask == B_FONT_ALL) {
2301		fState->font = *font;
2302	} else {
2303		// TODO: move this into a BFont method
2304		if (mask & B_FONT_FAMILY_AND_STYLE)
2305			fState->font.SetFamilyAndStyle(font->FamilyAndStyle());
2306
2307		if (mask & B_FONT_SIZE)
2308			fState->font.SetSize(font->Size());
2309
2310		if (mask & B_FONT_SHEAR)
2311			fState->font.SetShear(font->Shear());
2312
2313		if (mask & B_FONT_ROTATION)
2314			fState->font.SetRotation(font->Rotation());
2315
2316		if (mask & B_FONT_FALSE_BOLD_WIDTH)
2317			fState->font.SetFalseBoldWidth(font->FalseBoldWidth());
2318
2319		if (mask & B_FONT_SPACING)
2320			fState->font.SetSpacing(font->Spacing());
2321
2322		if (mask & B_FONT_ENCODING)
2323			fState->font.SetEncoding(font->Encoding());
2324
2325		if (mask & B_FONT_FACE)
2326			fState->font.SetFace(font->Face());
2327
2328		if (mask & B_FONT_FLAGS)
2329			fState->font.SetFlags(font->Flags());
2330	}
2331
2332	fState->font_flags |= mask;
2333
2334	if (fOwner) {
2335		_CheckLockAndSwitchCurrent();
2336
2337		fState->UpdateServerFontState(*fOwner->fLink);
2338		fState->valid_flags |= B_VIEW_FONT_BIT;
2339	}
2340
2341	fState->archiving_flags |= B_VIEW_FONT_BIT;
2342	// TODO: InvalidateLayout() here for convenience?
2343}
2344
2345
2346void
2347BView::GetFont(BFont* font) const
2348{
2349	if (!fState->IsValid(B_VIEW_FONT_BIT)) {
2350		// we don't keep graphics state information, therefor
2351		// we need to ask the server for the origin after PopState()
2352		_CheckOwnerLockAndSwitchCurrent();
2353
2354		// TODO: add a font getter!
2355		fState->UpdateFrom(*fOwner->fLink);
2356	}
2357
2358	*font = fState->font;
2359}
2360
2361
2362void
2363BView::GetFontHeight(font_height* height) const
2364{
2365	fState->font.GetHeight(height);
2366}
2367
2368
2369void
2370BView::SetFontSize(float size)
2371{
2372	BFont font;
2373	font.SetSize(size);
2374
2375	SetFont(&font, B_FONT_SIZE);
2376}
2377
2378
2379float
2380BView::StringWidth(const char* string) const
2381{
2382	return fState->font.StringWidth(string);
2383}
2384
2385
2386float
2387BView::StringWidth(const char* string, int32 length) const
2388{
2389	return fState->font.StringWidth(string, length);
2390}
2391
2392
2393void
2394BView::GetStringWidths(char* stringArray[], int32 lengthArray[],
2395	int32 numStrings, float widthArray[]) const
2396{
2397	fState->font.GetStringWidths(const_cast<const char**>(stringArray),
2398		const_cast<const int32*>(lengthArray), numStrings, widthArray);
2399}
2400
2401
2402void
2403BView::TruncateString(BString* string, uint32 mode, float width) const
2404{
2405	fState->font.TruncateString(string, mode, width);
2406}
2407
2408
2409void
2410BView::ClipToPicture(BPicture* picture, BPoint where, bool sync)
2411{
2412	_ClipToPicture(picture, where, false, sync);
2413}
2414
2415
2416void
2417BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync)
2418{
2419	_ClipToPicture(picture, where, true, sync);
2420}
2421
2422
2423void
2424BView::GetClippingRegion(BRegion* region) const
2425{
2426	if (!region)
2427		return;
2428
2429	// NOTE: the client has no idea when the clipping in the server
2430	// changed, so it is always read from the server
2431	region->MakeEmpty();
2432
2433
2434	if (fOwner) {
2435		if (fIsPrinting && _CheckOwnerLock()) {
2436			region->Set(fState->print_rect);
2437			return;
2438		}
2439
2440		_CheckLockAndSwitchCurrent();
2441		fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION);
2442
2443 		int32 code;
2444 		if (fOwner->fLink->FlushWithReply(code) == B_OK
2445 			&& code == B_OK) {
2446			fOwner->fLink->ReadRegion(region);
2447			fState->valid_flags |= B_VIEW_CLIP_REGION_BIT;
2448		}
2449	}
2450}
2451
2452
2453void
2454BView::ConstrainClippingRegion(BRegion* region)
2455{
2456	if (_CheckOwnerLockAndSwitchCurrent()) {
2457		fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION);
2458
2459		if (region) {
2460			int32 count = region->CountRects();
2461			fOwner->fLink->Attach<int32>(count);
2462			if (count > 0)
2463				fOwner->fLink->AttachRegion(*region);
2464		} else {
2465			fOwner->fLink->Attach<int32>(-1);
2466			// '-1' means that in the app_server, there won't be any 'local'
2467			// clipping region (it will be NULL)
2468		}
2469
2470		_FlushIfNotInTransaction();
2471
2472		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
2473		fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
2474	}
2475}
2476
2477
2478//	#pragma mark - Drawing Functions
2479
2480
2481void
2482BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
2483	uint32 options)
2484{
2485	if (bitmap == NULL || fOwner == NULL
2486		|| !bitmapRect.IsValid() || !viewRect.IsValid())
2487		return;
2488
2489	_CheckLockAndSwitchCurrent();
2490
2491	ViewDrawBitmapInfo info;
2492	info.bitmapToken = bitmap->_ServerToken();
2493	info.options = options;
2494	info.viewRect = viewRect;
2495	info.bitmapRect = bitmapRect;
2496
2497	fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
2498	fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
2499
2500	_FlushIfNotInTransaction();
2501}
2502
2503
2504void
2505BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
2506{
2507	DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
2508}
2509
2510
2511void
2512BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect)
2513{
2514	if (bitmap && fOwner) {
2515		DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN),
2516			viewRect, 0);
2517	}
2518}
2519
2520
2521void
2522BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where)
2523{
2524	if (bitmap == NULL || fOwner == NULL)
2525		return;
2526
2527	_CheckLockAndSwitchCurrent();
2528
2529	ViewDrawBitmapInfo info;
2530	info.bitmapToken = bitmap->_ServerToken();
2531	info.options = 0;
2532	info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN);
2533	info.viewRect = info.bitmapRect.OffsetToCopy(where);
2534
2535	fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
2536	fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
2537
2538	_FlushIfNotInTransaction();
2539}
2540
2541
2542void
2543BView::DrawBitmapAsync(const BBitmap* bitmap)
2544{
2545	DrawBitmapAsync(bitmap, PenLocation());
2546}
2547
2548
2549void
2550BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
2551	uint32 options)
2552{
2553	if (fOwner) {
2554		DrawBitmapAsync(bitmap, bitmapRect, viewRect, options);
2555		Sync();
2556	}
2557}
2558
2559
2560void
2561BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
2562{
2563	if (fOwner) {
2564		DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
2565		Sync();
2566	}
2567}
2568
2569
2570void
2571BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect)
2572{
2573	if (bitmap && fOwner) {
2574		DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect,
2575			0);
2576	}
2577}
2578
2579
2580void
2581BView::DrawBitmap(const BBitmap* bitmap, BPoint where)
2582{
2583	if (fOwner) {
2584		DrawBitmapAsync(bitmap, where);
2585		Sync();
2586	}
2587}
2588
2589
2590void
2591BView::DrawBitmap(const BBitmap* bitmap)
2592{
2593	DrawBitmap(bitmap, PenLocation());
2594}
2595
2596
2597void
2598BView::DrawChar(char c)
2599{
2600	DrawString(&c, 1, PenLocation());
2601}
2602
2603
2604void
2605BView::DrawChar(char c, BPoint location)
2606{
2607	DrawString(&c, 1, location);
2608}
2609
2610
2611void
2612BView::DrawString(const char* string, escapement_delta* delta)
2613{
2614	if (string == NULL)
2615		return;
2616
2617	DrawString(string, strlen(string), PenLocation(), delta);
2618}
2619
2620
2621void
2622BView::DrawString(const char* string, BPoint location, escapement_delta* delta)
2623{
2624	if (string == NULL)
2625		return;
2626
2627	DrawString(string, strlen(string), location, delta);
2628}
2629
2630
2631void
2632BView::DrawString(const char* string, int32 length, escapement_delta* delta)
2633{
2634	DrawString(string, length, PenLocation(), delta);
2635}
2636
2637
2638void
2639BView::DrawString(const char* string, int32 length, BPoint location,
2640	escapement_delta* delta)
2641{
2642	if (fOwner == NULL || string == NULL || length < 1)
2643		return;
2644
2645	_CheckLockAndSwitchCurrent();
2646
2647	ViewDrawStringInfo info;
2648	info.stringLength = length;
2649	info.location = location;
2650	if (delta != NULL)
2651		info.delta = *delta;
2652
2653	// quite often delta will be NULL
2654	if (delta)
2655		fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA);
2656	else
2657		fOwner->fLink->StartMessage(AS_DRAW_STRING);
2658
2659	fOwner->fLink->Attach<ViewDrawStringInfo>(info);
2660	fOwner->fLink->Attach(string, length);
2661
2662	_FlushIfNotInTransaction();
2663
2664	// this modifies our pen location, so we invalidate the flag.
2665	fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
2666}
2667
2668
2669void
2670BView::DrawString(const char* string, const BPoint* locations,
2671	int32 locationCount)
2672{
2673	if (string == NULL)
2674		return;
2675
2676	DrawString(string, strlen(string), locations, locationCount);
2677}
2678
2679
2680void
2681BView::DrawString(const char* string, int32 length, const BPoint* locations,
2682	int32 locationCount)
2683{
2684	if (fOwner == NULL || string == NULL || length < 1 || locations == NULL)
2685		return;
2686
2687	_CheckLockAndSwitchCurrent();
2688
2689	fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS);
2690
2691	fOwner->fLink->Attach<int32>(length);
2692	fOwner->fLink->Attach<int32>(locationCount);
2693	fOwner->fLink->Attach(string, length);
2694	fOwner->fLink->Attach(locations, locationCount * sizeof(BPoint));
2695
2696	_FlushIfNotInTransaction();
2697
2698	// this modifies our pen location, so we invalidate the flag.
2699	fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
2700}
2701
2702
2703void
2704BView::StrokeEllipse(BPoint center, float xRadius, float yRadius,
2705	::pattern pattern)
2706{
2707	StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius,
2708		center.x + xRadius, center.y + yRadius), pattern);
2709}
2710
2711
2712void
2713BView::StrokeEllipse(BRect rect, ::pattern pattern)
2714{
2715	if (fOwner == NULL)
2716		return;
2717
2718	_CheckLockAndSwitchCurrent();
2719	_UpdatePattern(pattern);
2720
2721	fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE);
2722	fOwner->fLink->Attach<BRect>(rect);
2723
2724	_FlushIfNotInTransaction();
2725}
2726
2727
2728void
2729BView::FillEllipse(BPoint center, float xRadius, float yRadius,
2730	::pattern pattern)
2731{
2732	FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
2733		center.x + xRadius, center.y + yRadius), pattern);
2734}
2735
2736
2737void
2738BView::FillEllipse(BPoint center, float xRadius, float yRadius,
2739	const BGradient& gradient)
2740{
2741	FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
2742					  center.x + xRadius, center.y + yRadius), gradient);
2743}
2744
2745
2746void
2747BView::FillEllipse(BRect rect, ::pattern pattern)
2748{
2749	if (fOwner == NULL)
2750		return;
2751
2752	_CheckLockAndSwitchCurrent();
2753	_UpdatePattern(pattern);
2754
2755	fOwner->fLink->StartMessage(AS_FILL_ELLIPSE);
2756	fOwner->fLink->Attach<BRect>(rect);
2757
2758	_FlushIfNotInTransaction();
2759}
2760
2761
2762void
2763BView::FillEllipse(BRect rect, const BGradient& gradient)
2764{
2765	if (fOwner == NULL)
2766		return;
2767
2768	_CheckLockAndSwitchCurrent();
2769
2770	fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT);
2771	fOwner->fLink->Attach<BRect>(rect);
2772	fOwner->fLink->AttachGradient(gradient);
2773
2774	_FlushIfNotInTransaction();
2775}
2776
2777
2778void
2779BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle,
2780	float arcAngle, ::pattern pattern)
2781{
2782	StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2783		center.y + yRadius), startAngle, arcAngle, pattern);
2784}
2785
2786
2787void
2788BView::StrokeArc(BRect rect, float startAngle, float arcAngle,
2789	::pattern pattern)
2790{
2791	if (fOwner == NULL)
2792		return;
2793
2794	_CheckLockAndSwitchCurrent();
2795	_UpdatePattern(pattern);
2796
2797	fOwner->fLink->StartMessage(AS_STROKE_ARC);
2798	fOwner->fLink->Attach<BRect>(rect);
2799	fOwner->fLink->Attach<float>(startAngle);
2800	fOwner->fLink->Attach<float>(arcAngle);
2801
2802	_FlushIfNotInTransaction();
2803}
2804
2805
2806void
2807BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
2808	float arcAngle, ::pattern pattern)
2809{
2810	FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2811		center.y + yRadius), startAngle, arcAngle, pattern);
2812}
2813
2814
2815void
2816BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
2817	float arcAngle, const BGradient& gradient)
2818{
2819	FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2820		center.y + yRadius), startAngle, arcAngle, gradient);
2821}
2822
2823
2824void
2825BView::FillArc(BRect rect, float startAngle, float arcAngle,
2826	::pattern pattern)
2827{
2828	if (fOwner == NULL)
2829		return;
2830
2831	_CheckLockAndSwitchCurrent();
2832	_UpdatePattern(pattern);
2833
2834	fOwner->fLink->StartMessage(AS_FILL_ARC);
2835	fOwner->fLink->Attach<BRect>(rect);
2836	fOwner->fLink->Attach<float>(startAngle);
2837	fOwner->fLink->Attach<float>(arcAngle);
2838
2839	_FlushIfNotInTransaction();
2840}
2841
2842
2843void
2844BView::FillArc(BRect rect, float startAngle, float arcAngle,
2845	const BGradient& gradient)
2846{
2847	if (fOwner == NULL)
2848		return;
2849
2850	_CheckLockAndSwitchCurrent();
2851
2852	fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT);
2853	fOwner->fLink->Attach<BRect>(rect);
2854	fOwner->fLink->Attach<float>(startAngle);
2855	fOwner->fLink->Attach<float>(arcAngle);
2856	fOwner->fLink->AttachGradient(gradient);
2857
2858	_FlushIfNotInTransaction();
2859}
2860
2861
2862void
2863BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern)
2864{
2865	if (fOwner == NULL)
2866		return;
2867
2868	_CheckLockAndSwitchCurrent();
2869	_UpdatePattern(pattern);
2870
2871	fOwner->fLink->StartMessage(AS_STROKE_BEZIER);
2872	fOwner->fLink->Attach<BPoint>(controlPoints[0]);
2873	fOwner->fLink->Attach<BPoint>(controlPoints[1]);
2874	fOwner->fLink->Attach<BPoint>(controlPoints[2]);
2875	fOwner->fLink->Attach<BPoint>(controlPoints[3]);
2876
2877	_FlushIfNotInTransaction();
2878}
2879
2880
2881void
2882BView::FillBezier(BPoint* controlPoints, ::pattern pattern)
2883{
2884	if (fOwner == NULL)
2885		return;
2886
2887	_CheckLockAndSwitchCurrent();
2888	_UpdatePattern(pattern);
2889
2890	fOwner->fLink->StartMessage(AS_FILL_BEZIER);
2891	fOwner->fLink->Attach<BPoint>(controlPoints[0]);
2892	fOwner->fLink->Attach<BPoint>(controlPoints[1]);
2893	fOwner->fLink->Attach<BPoint>(controlPoints[2]);
2894	fOwner->fLink->Attach<BPoint>(controlPoints[3]);
2895
2896	_FlushIfNotInTransaction();
2897}
2898
2899
2900void
2901BView::FillBezier(BPoint* controlPoints, const BGradient& gradient)
2902{
2903	if (fOwner == NULL)
2904		return;
2905
2906	_CheckLockAndSwitchCurrent();
2907
2908	fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT);
2909	fOwner->fLink->Attach<BPoint>(controlPoints[0]);
2910	fOwner->fLink->Attach<BPoint>(controlPoints[1]);
2911	fOwner->fLink->Attach<BPoint>(controlPoints[2]);
2912	fOwner->fLink->Attach<BPoint>(controlPoints[3]);
2913	fOwner->fLink->AttachGradient(gradient);
2914
2915	_FlushIfNotInTransaction();
2916}
2917
2918
2919void
2920BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern)
2921{
2922	if (!polygon)
2923		return;
2924
2925	StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed,
2926		pattern);
2927}
2928
2929
2930void
2931BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed,
2932	::pattern pattern)
2933{
2934	BPolygon polygon(pointArray, numPoints);
2935
2936	StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed,
2937		pattern);
2938}
2939
2940
2941void
2942BView::StrokePolygon(const BPoint* ptArray, int32 numPoints, BRect bounds,
2943	bool closed, ::pattern pattern)
2944{
2945	if (!ptArray
2946		|| numPoints <= 1
2947		|| fOwner == NULL)
2948		return;
2949
2950	_CheckLockAndSwitchCurrent();
2951	_UpdatePattern(pattern);
2952
2953	BPolygon polygon(ptArray, numPoints);
2954	polygon.MapTo(polygon.Frame(), bounds);
2955
2956	if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON,
2957			polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool)
2958				+ sizeof(int32)) == B_OK) {
2959		fOwner->fLink->Attach<BRect>(polygon.Frame());
2960		fOwner->fLink->Attach<bool>(closed);
2961		fOwner->fLink->Attach<int32>(polygon.fCount);
2962		fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint));
2963
2964		_FlushIfNotInTransaction();
2965	} else {
2966		fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
2967	}
2968}
2969
2970
2971void
2972BView::FillPolygon(const BPolygon* polygon, ::pattern pattern)
2973{
2974	if (polygon == NULL
2975		|| polygon->fCount <= 2
2976		|| fOwner == NULL)
2977		return;
2978
2979	_CheckLockAndSwitchCurrent();
2980	_UpdatePattern(pattern);
2981
2982	if (fOwner->fLink->StartMessage(AS_FILL_POLYGON,
2983			polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
2984				== B_OK) {
2985		fOwner->fLink->Attach<BRect>(polygon->Frame());
2986		fOwner->fLink->Attach<int32>(polygon->fCount);
2987		fOwner->fLink->Attach(polygon->fPoints,
2988			polygon->fCount * sizeof(BPoint));
2989
2990		_FlushIfNotInTransaction();
2991	} else {
2992		fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
2993	}
2994}
2995
2996
2997void
2998BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient)
2999{
3000	if (polygon == NULL
3001		|| polygon->fCount <= 2
3002		|| fOwner == NULL)
3003		return;
3004
3005	_CheckLockAndSwitchCurrent();
3006
3007	if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT,
3008			polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3009				== B_OK) {
3010		fOwner->fLink->Attach<BRect>(polygon->Frame());
3011		fOwner->fLink->Attach<int32>(polygon->fCount);
3012		fOwner->fLink->Attach(polygon->fPoints,
3013			polygon->fCount * sizeof(BPoint));
3014		fOwner->fLink->AttachGradient(gradient);
3015
3016		_FlushIfNotInTransaction();
3017	} else {
3018		fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3019	}
3020}
3021
3022
3023void
3024BView::FillPolygon(const BPoint* ptArray, int32 numPts, ::pattern pattern)
3025{
3026	if (!ptArray)
3027		return;
3028
3029	BPolygon polygon(ptArray, numPts);
3030	FillPolygon(&polygon, pattern);
3031}
3032
3033
3034void
3035BView::FillPolygon(const BPoint* ptArray, int32 numPts,
3036	const BGradient& gradient)
3037{
3038	if (!ptArray)
3039		return;
3040
3041	BPolygon polygon(ptArray, numPts);
3042	FillPolygon(&polygon, gradient);
3043}
3044
3045
3046void
3047BView::FillPolygon(const BPoint* ptArray, int32 numPts, BRect bounds,
3048	pattern p)
3049{
3050	if (!ptArray)
3051		return;
3052
3053	BPolygon polygon(ptArray, numPts);
3054
3055	polygon.MapTo(polygon.Frame(), bounds);
3056	FillPolygon(&polygon, p);
3057}
3058
3059
3060void
3061BView::FillPolygon(const BPoint* ptArray, int32 numPts, BRect bounds,
3062	const BGradient& gradient)
3063{
3064	if (!ptArray)
3065		return;
3066
3067	BPolygon polygon(ptArray, numPts);
3068
3069	polygon.MapTo(polygon.Frame(), bounds);
3070	FillPolygon(&polygon, gradient);
3071}
3072
3073
3074void
3075BView::StrokeRect(BRect rect, ::pattern pattern)
3076{
3077	if (fOwner == NULL)
3078		return;
3079
3080	_CheckLockAndSwitchCurrent();
3081	_UpdatePattern(pattern);
3082
3083	fOwner->fLink->StartMessage(AS_STROKE_RECT);
3084	fOwner->fLink->Attach<BRect>(rect);
3085
3086	_FlushIfNotInTransaction();
3087}
3088
3089
3090void
3091BView::FillRect(BRect rect, ::pattern pattern)
3092{
3093	if (fOwner == NULL)
3094		return;
3095
3096	// NOTE: ensuring compatibility with R5,
3097	// invalid rects are not filled, they are stroked though!
3098	if (!rect.IsValid())
3099		return;
3100
3101	_CheckLockAndSwitchCurrent();
3102	_UpdatePattern(pattern);
3103
3104	fOwner->fLink->StartMessage(AS_FILL_RECT);
3105	fOwner->fLink->Attach<BRect>(rect);
3106
3107	_FlushIfNotInTransaction();
3108}
3109
3110
3111void
3112BView::FillRect(BRect rect, const BGradient& gradient)
3113{
3114	if (fOwner == NULL)
3115		return;
3116
3117	// NOTE: ensuring compatibility with R5,
3118	// invalid rects are not filled, they are stroked though!
3119	if (!rect.IsValid())
3120		return;
3121
3122	_CheckLockAndSwitchCurrent();
3123
3124	fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT);
3125	fOwner->fLink->Attach<BRect>(rect);
3126	fOwner->fLink->AttachGradient(gradient);
3127
3128	_FlushIfNotInTransaction();
3129}
3130
3131
3132void
3133BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius,
3134	::pattern pattern)
3135{
3136	if (fOwner == NULL)
3137		return;
3138
3139	_CheckLockAndSwitchCurrent();
3140	_UpdatePattern(pattern);
3141
3142	fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT);
3143	fOwner->fLink->Attach<BRect>(rect);
3144	fOwner->fLink->Attach<float>(xRadius);
3145	fOwner->fLink->Attach<float>(yRadius);
3146
3147	_FlushIfNotInTransaction();
3148}
3149
3150
3151void
3152BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3153	::pattern pattern)
3154{
3155	if (fOwner == NULL)
3156		return;
3157
3158	_CheckLockAndSwitchCurrent();
3159
3160	_UpdatePattern(pattern);
3161
3162	fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT);
3163	fOwner->fLink->Attach<BRect>(rect);
3164	fOwner->fLink->Attach<float>(xRadius);
3165	fOwner->fLink->Attach<float>(yRadius);
3166
3167	_FlushIfNotInTransaction();
3168}
3169
3170
3171void
3172BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3173	const BGradient& gradient)
3174{
3175	if (fOwner == NULL)
3176		return;
3177
3178	_CheckLockAndSwitchCurrent();
3179
3180	fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT);
3181	fOwner->fLink->Attach<BRect>(rect);
3182	fOwner->fLink->Attach<float>(xRadius);
3183	fOwner->fLink->Attach<float>(yRadius);
3184	fOwner->fLink->AttachGradient(gradient);
3185
3186	_FlushIfNotInTransaction();
3187}
3188
3189
3190void
3191BView::FillRegion(BRegion* region, ::pattern pattern)
3192{
3193	if (region == NULL || fOwner == NULL)
3194		return;
3195
3196	_CheckLockAndSwitchCurrent();
3197
3198	_UpdatePattern(pattern);
3199
3200	fOwner->fLink->StartMessage(AS_FILL_REGION);
3201	fOwner->fLink->AttachRegion(*region);
3202
3203	_FlushIfNotInTransaction();
3204}
3205
3206
3207void
3208BView::FillRegion(BRegion* region, const BGradient& gradient)
3209{
3210	if (region == NULL || fOwner == NULL)
3211		return;
3212
3213	_CheckLockAndSwitchCurrent();
3214
3215	fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT);
3216	fOwner->fLink->AttachRegion(*region);
3217	fOwner->fLink->AttachGradient(gradient);
3218
3219	_FlushIfNotInTransaction();
3220}
3221
3222
3223void
3224BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds,
3225	::pattern pattern)
3226{
3227	if (fOwner == NULL)
3228		return;
3229
3230	_CheckLockAndSwitchCurrent();
3231
3232	_UpdatePattern(pattern);
3233
3234	fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE);
3235	fOwner->fLink->Attach<BPoint>(pt1);
3236	fOwner->fLink->Attach<BPoint>(pt2);
3237	fOwner->fLink->Attach<BPoint>(pt3);
3238	fOwner->fLink->Attach<BRect>(bounds);
3239
3240	_FlushIfNotInTransaction();
3241}
3242
3243
3244void
3245BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p)
3246{
3247	if (fOwner) {
3248		// we construct the smallest rectangle that contains the 3 points
3249		// for the 1st point
3250		BRect bounds(pt1, pt1);
3251
3252		// for the 2nd point
3253		if (pt2.x < bounds.left)
3254			bounds.left = pt2.x;
3255
3256		if (pt2.y < bounds.top)
3257			bounds.top = pt2.y;
3258
3259		if (pt2.x > bounds.right)
3260			bounds.right = pt2.x;
3261
3262		if (pt2.y > bounds.bottom)
3263			bounds.bottom = pt2.y;
3264
3265		// for the 3rd point
3266		if (pt3.x < bounds.left)
3267			bounds.left = pt3.x;
3268
3269		if (pt3.y < bounds.top)
3270			bounds.top = pt3.y;
3271
3272		if (pt3.x > bounds.right)
3273			bounds.right = pt3.x;
3274
3275		if (pt3.y > bounds.bottom)
3276			bounds.bottom = pt3.y;
3277
3278		StrokeTriangle(pt1, pt2, pt3, bounds, p);
3279	}
3280}
3281
3282
3283void
3284BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p)
3285{
3286	if (fOwner) {
3287		// we construct the smallest rectangle that contains the 3 points
3288		// for the 1st point
3289		BRect bounds(pt1, pt1);
3290
3291		// for the 2nd point
3292		if (pt2.x < bounds.left)
3293			bounds.left = pt2.x;
3294
3295		if (pt2.y < bounds.top)
3296			bounds.top = pt2.y;
3297
3298		if (pt2.x > bounds.right)
3299			bounds.right = pt2.x;
3300
3301		if (pt2.y > bounds.bottom)
3302			bounds.bottom = pt2.y;
3303
3304		// for the 3rd point
3305		if (pt3.x < bounds.left)
3306			bounds.left = pt3.x;
3307
3308		if (pt3.y < bounds.top)
3309			bounds.top = pt3.y;
3310
3311		if (pt3.x > bounds.right)
3312			bounds.right = pt3.x;
3313
3314		if (pt3.y > bounds.bottom)
3315			bounds.bottom = pt3.y;
3316
3317		FillTriangle(pt1, pt2, pt3, bounds, p);
3318	}
3319}
3320
3321
3322void
3323BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
3324	const BGradient& gradient)
3325{
3326	if (fOwner) {
3327		// we construct the smallest rectangle that contains the 3 points
3328		// for the 1st point
3329		BRect bounds(pt1, pt1);
3330
3331		// for the 2nd point
3332		if (pt2.x < bounds.left)
3333			bounds.left = pt2.x;
3334
3335		if (pt2.y < bounds.top)
3336			bounds.top = pt2.y;
3337
3338		if (pt2.x > bounds.right)
3339			bounds.right = pt2.x;
3340
3341		if (pt2.y > bounds.bottom)
3342			bounds.bottom = pt2.y;
3343
3344		// for the 3rd point
3345		if (pt3.x < bounds.left)
3346			bounds.left = pt3.x;
3347
3348		if (pt3.y < bounds.top)
3349			bounds.top = pt3.y;
3350
3351		if (pt3.x > bounds.right)
3352			bounds.right = pt3.x;
3353
3354		if (pt3.y > bounds.bottom)
3355			bounds.bottom = pt3.y;
3356
3357		FillTriangle(pt1, pt2, pt3, bounds, gradient);
3358	}
3359}
3360
3361
3362void
3363BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
3364	BRect bounds, ::pattern pattern)
3365{
3366	if (fOwner == NULL)
3367		return;
3368
3369	_CheckLockAndSwitchCurrent();
3370	_UpdatePattern(pattern);
3371
3372	fOwner->fLink->StartMessage(AS_FILL_TRIANGLE);
3373	fOwner->fLink->Attach<BPoint>(pt1);
3374	fOwner->fLink->Attach<BPoint>(pt2);
3375	fOwner->fLink->Attach<BPoint>(pt3);
3376	fOwner->fLink->Attach<BRect>(bounds);
3377
3378	_FlushIfNotInTransaction();
3379}
3380
3381
3382void
3383BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
3384	BRect bounds, const BGradient& gradient)
3385{
3386	if (fOwner == NULL)
3387		return;
3388
3389	_CheckLockAndSwitchCurrent();
3390	fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT);
3391	fOwner->fLink->Attach<BPoint>(pt1);
3392	fOwner->fLink->Attach<BPoint>(pt2);
3393	fOwner->fLink->Attach<BPoint>(pt3);
3394	fOwner->fLink->Attach<BRect>(bounds);
3395	fOwner->fLink->AttachGradient(gradient);
3396
3397	_FlushIfNotInTransaction();
3398}
3399
3400
3401void
3402BView::StrokeLine(BPoint toPt, pattern p)
3403{
3404	StrokeLine(PenLocation(), toPt, p);
3405}
3406
3407
3408void
3409BView::StrokeLine(BPoint pt0, BPoint pt1, ::pattern pattern)
3410{
3411	if (fOwner == NULL)
3412		return;
3413
3414	_CheckLockAndSwitchCurrent();
3415	_UpdatePattern(pattern);
3416
3417	ViewStrokeLineInfo info;
3418	info.startPoint = pt0;
3419	info.endPoint = pt1;
3420
3421	fOwner->fLink->StartMessage(AS_STROKE_LINE);
3422	fOwner->fLink->Attach<ViewStrokeLineInfo>(info);
3423
3424	_FlushIfNotInTransaction();
3425
3426	// this modifies our pen location, so we invalidate the flag.
3427	fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3428}
3429
3430
3431void
3432BView::StrokeShape(BShape* shape, ::pattern pattern)
3433{
3434	if (shape == NULL || fOwner == NULL)
3435		return;
3436
3437	shape_data* sd = (shape_data*)shape->fPrivateData;
3438	if (sd->opCount == 0 || sd->ptCount == 0)
3439		return;
3440
3441	_CheckLockAndSwitchCurrent();
3442	_UpdatePattern(pattern);
3443
3444	fOwner->fLink->StartMessage(AS_STROKE_SHAPE);
3445	fOwner->fLink->Attach<BRect>(shape->Bounds());
3446	fOwner->fLink->Attach<int32>(sd->opCount);
3447	fOwner->fLink->Attach<int32>(sd->ptCount);
3448	fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
3449	fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3450
3451	_FlushIfNotInTransaction();
3452}
3453
3454
3455void
3456BView::FillShape(BShape* shape, ::pattern pattern)
3457{
3458	if (shape == NULL || fOwner == NULL)
3459		return;
3460
3461	shape_data* sd = (shape_data*)(shape->fPrivateData);
3462	if (sd->opCount == 0 || sd->ptCount == 0)
3463		return;
3464
3465	_CheckLockAndSwitchCurrent();
3466	_UpdatePattern(pattern);
3467
3468	fOwner->fLink->StartMessage(AS_FILL_SHAPE);
3469	fOwner->fLink->Attach<BRect>(shape->Bounds());
3470	fOwner->fLink->Attach<int32>(sd->opCount);
3471	fOwner->fLink->Attach<int32>(sd->ptCount);
3472	fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3473	fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3474
3475	_FlushIfNotInTransaction();
3476}
3477
3478
3479void
3480BView::FillShape(BShape* shape, const BGradient& gradient)
3481{
3482	if (shape == NULL || fOwner == NULL)
3483		return;
3484
3485	shape_data* sd = (shape_data*)(shape->fPrivateData);
3486	if (sd->opCount == 0 || sd->ptCount == 0)
3487		return;
3488
3489	_CheckLockAndSwitchCurrent();
3490
3491	fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT);
3492	fOwner->fLink->Attach<BRect>(shape->Bounds());
3493	fOwner->fLink->Attach<int32>(sd->opCount);
3494	fOwner->fLink->Attach<int32>(sd->ptCount);
3495	fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3496	fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3497	fOwner->fLink->AttachGradient(gradient);
3498
3499	_FlushIfNotInTransaction();
3500}
3501
3502
3503void
3504BView::BeginLineArray(int32 count)
3505{
3506	if (fOwner == NULL)
3507		return;
3508
3509	if (count <= 0)
3510		debugger("Calling BeginLineArray with a count <= 0");
3511
3512	_CheckLock();
3513
3514	if (fCommArray) {
3515		debugger("Can't nest BeginLineArray calls");
3516			// not fatal, but it helps during
3517			// development of your app and is in
3518			// line with R5...
3519		delete[] fCommArray->array;
3520		delete fCommArray;
3521	}
3522
3523	// TODO: since this method cannot return failure, and further AddLine()
3524	//	calls with a NULL fCommArray would drop into the debugger anyway,
3525	//	we allow the possible std::bad_alloc exceptions here...
3526	fCommArray = new _array_data_;
3527	fCommArray->maxCount = count;
3528	fCommArray->count = 0;
3529	fCommArray->array = new ViewLineArrayInfo[count];
3530}
3531
3532
3533void
3534BView::AddLine(BPoint pt0, BPoint pt1, rgb_color col)
3535{
3536	if (fOwner == NULL)
3537		return;
3538
3539	if (!fCommArray)
3540		debugger("BeginLineArray must be called before using AddLine");
3541
3542	_CheckLock();
3543
3544	const uint32 &arrayCount = fCommArray->count;
3545	if (arrayCount < fCommArray->maxCount) {
3546		fCommArray->array[arrayCount].startPoint = pt0;
3547		fCommArray->array[arrayCount].endPoint = pt1;
3548		fCommArray->array[arrayCount].color = col;
3549
3550		fCommArray->count++;
3551	}
3552}
3553
3554
3555void
3556BView::EndLineArray()
3557{
3558	if (fOwner == NULL)
3559		return;
3560
3561	if (fCommArray == NULL)
3562		debugger("Can't call EndLineArray before BeginLineArray");
3563
3564	_CheckLockAndSwitchCurrent();
3565
3566	fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY);
3567	fOwner->fLink->Attach<int32>(fCommArray->count);
3568	fOwner->fLink->Attach(fCommArray->array,
3569		fCommArray->count * sizeof(ViewLineArrayInfo));
3570
3571	_FlushIfNotInTransaction();
3572
3573	_RemoveCommArray();
3574}
3575
3576
3577void
3578BView::SetDiskMode(char* filename, long offset)
3579{
3580	// TODO: implement
3581	// One BeBook version has this to say about SetDiskMode():
3582	//
3583	// "Begins recording a picture to the file with the given filename
3584	// at the given offset. Subsequent drawing commands sent to the view
3585	// will be written to the file until EndPicture() is called. The
3586	// stored commands may be played from the file with DrawPicture()."
3587}
3588
3589
3590void
3591BView::BeginPicture(BPicture* picture)
3592{
3593	if (_CheckOwnerLockAndSwitchCurrent()
3594		&& picture && picture->fUsurped == NULL) {
3595		picture->Usurp(fCurrentPicture);
3596		fCurrentPicture = picture;
3597
3598		fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE);
3599	}
3600}
3601
3602
3603void
3604BView::AppendToPicture(BPicture* picture)
3605{
3606	_CheckLockAndSwitchCurrent();
3607
3608	if (picture && picture->fUsurped == NULL) {
3609		int32 token = picture->Token();
3610
3611		if (token == -1) {
3612			BeginPicture(picture);
3613		} else {
3614			picture->SetToken(-1);
3615			picture->Usurp(fCurrentPicture);
3616			fCurrentPicture = picture;
3617			fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE);
3618			fOwner->fLink->Attach<int32>(token);
3619		}
3620	}
3621}
3622
3623
3624BPicture*
3625BView::EndPicture()
3626{
3627	if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) {
3628		int32 token;
3629
3630		fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE);
3631
3632		int32 code;
3633		if (fOwner->fLink->FlushWithReply(code) == B_OK
3634			&& code == B_OK
3635			&& fOwner->fLink->Read<int32>(&token) == B_OK) {
3636			BPicture* picture = fCurrentPicture;
3637			fCurrentPicture = picture->StepDown();
3638			picture->SetToken(token);
3639
3640			// TODO do this more efficient e.g. use a shared area and let the
3641			// client write into it
3642			picture->_Download();
3643			return picture;
3644		}
3645	}
3646
3647	return NULL;
3648}
3649
3650
3651void
3652BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
3653	uint32 followFlags, uint32 options)
3654{
3655	_SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options);
3656}
3657
3658
3659void
3660BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options)
3661{
3662	BRect rect;
3663 	if (bitmap)
3664		rect = bitmap->Bounds();
3665
3666 	rect.OffsetTo(B_ORIGIN);
3667
3668	_SetViewBitmap(bitmap, rect, rect, followFlags, options);
3669}
3670
3671
3672void
3673BView::ClearViewBitmap()
3674{
3675	_SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3676}
3677
3678
3679status_t
3680BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect,
3681	rgb_color* colorKey, uint32 followFlags, uint32 options)
3682{
3683	if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0)
3684		return B_BAD_VALUE;
3685
3686	status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags,
3687		options | AS_REQUEST_COLOR_KEY);
3688	if (status == B_OK) {
3689		// read the color that will be treated as transparent
3690		fOwner->fLink->Read<rgb_color>(colorKey);
3691	}
3692
3693	return status;
3694}
3695
3696
3697status_t
3698BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey,
3699	uint32 followFlags, uint32 options)
3700{
3701	if (overlay == NULL)
3702		return B_BAD_VALUE;
3703
3704	BRect rect = overlay->Bounds();
3705 	rect.OffsetTo(B_ORIGIN);
3706
3707	return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options);
3708}
3709
3710
3711void
3712BView::ClearViewOverlay()
3713{
3714	_SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3715}
3716
3717
3718void
3719BView::CopyBits(BRect src, BRect dst)
3720{
3721	if (fOwner == NULL)
3722		return;
3723
3724	if (!src.IsValid() || !dst.IsValid())
3725		return;
3726
3727	_CheckLockAndSwitchCurrent();
3728
3729	fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS);
3730	fOwner->fLink->Attach<BRect>(src);
3731	fOwner->fLink->Attach<BRect>(dst);
3732
3733	_FlushIfNotInTransaction();
3734}
3735
3736
3737void
3738BView::DrawPicture(const BPicture* picture)
3739{
3740	if (picture == NULL)
3741		return;
3742
3743	DrawPictureAsync(picture, PenLocation());
3744	Sync();
3745}
3746
3747
3748void
3749BView::DrawPicture(const BPicture* picture, BPoint where)
3750{
3751	if (picture == NULL)
3752		return;
3753
3754	DrawPictureAsync(picture, where);
3755	Sync();
3756}
3757
3758
3759void
3760BView::DrawPicture(const char* filename, long offset, BPoint where)
3761{
3762	if (!filename)
3763		return;
3764
3765	DrawPictureAsync(filename, offset, where);
3766	Sync();
3767}
3768
3769
3770void
3771BView::DrawPictureAsync(const BPicture* picture)
3772{
3773	if (picture == NULL)
3774		return;
3775
3776	DrawPictureAsync(picture, PenLocation());
3777}
3778
3779
3780void
3781BView::DrawPictureAsync(const BPicture* picture, BPoint where)
3782{
3783	if (picture == NULL)
3784		return;
3785
3786	if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) {
3787		fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE);
3788		fOwner->fLink->Attach<int32>(picture->Token());
3789		fOwner->fLink->Attach<BPoint>(where);
3790
3791		_FlushIfNotInTransaction();
3792	}
3793}
3794
3795
3796void
3797BView::DrawPictureAsync(const char* filename, long offset, BPoint where)
3798{
3799	if (!filename)
3800		return;
3801
3802	// TODO: Test
3803	BFile file(filename, B_READ_ONLY);
3804	if (file.InitCheck() < B_OK)
3805		return;
3806
3807	file.Seek(offset, SEEK_SET);
3808
3809	BPicture picture;
3810	if (picture.Unflatten(&file) < B_OK)
3811		return;
3812
3813	DrawPictureAsync(&picture, where);
3814}
3815
3816
3817void
3818BView::Invalidate(BRect invalRect)
3819{
3820	if (fOwner == NULL)
3821		return;
3822
3823	// NOTE: This rounding of the invalid rect is to stay compatible with BeOS.
3824	// On the server side, the invalid rect will be converted to a BRegion,
3825	// which rounds in a different manner, so that it really includes the
3826	// fractional coordinates of a BRect (ie ceilf(rect.right) &
3827	// ceilf(rect.bottom)), which is also what BeOS does. So we have to do the
3828	// different rounding here to stay compatible in both ways.
3829	invalRect.left = (int)invalRect.left;
3830	invalRect.top = (int)invalRect.top;
3831	invalRect.right = (int)invalRect.right;
3832	invalRect.bottom = (int)invalRect.bottom;
3833	if (!invalRect.IsValid())
3834		return;
3835
3836	_CheckLockAndSwitchCurrent();
3837
3838	fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT);
3839	fOwner->fLink->Attach<BRect>(invalRect);
3840
3841// TODO: determine why this check isn't working correctly.
3842#if 0
3843	if (!fOwner->fUpdateRequested) {
3844		fOwner->fLink->Flush();
3845		fOwner->fUpdateRequested = true;
3846	}
3847#else
3848	fOwner->fLink->Flush();
3849#endif
3850}
3851
3852
3853void
3854BView::Invalidate(const BRegion* region)
3855{
3856	if (region == NULL || fOwner == NULL)
3857		return;
3858
3859	_CheckLockAndSwitchCurrent();
3860
3861	fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION);
3862	fOwner->fLink->AttachRegion(*region);
3863
3864// TODO: See above.
3865#if 0
3866	if (!fOwner->fUpdateRequested) {
3867		fOwner->fLink->Flush();
3868		fOwner->fUpdateRequested = true;
3869	}
3870#else
3871	fOwner->fLink->Flush();
3872#endif
3873}
3874
3875
3876void
3877BView::Invalidate()
3878{
3879	Invalidate(Bounds());
3880}
3881
3882
3883void
3884BView::InvertRect(BRect rect)
3885{
3886	if (fOwner) {
3887		_CheckLockAndSwitchCurrent();
3888
3889		fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT);
3890		fOwner->fLink->Attach<BRect>(rect);
3891
3892		_FlushIfNotInTransaction();
3893	}
3894}
3895
3896
3897//	#pragma mark - View Hierarchy Functions
3898
3899
3900void
3901BView::AddChild(BView* child, BView* before)
3902{
3903	STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n",
3904 		this->Name(),
3905 		child != NULL && child->Name() ? child->Name() : "NULL",
3906 		before != NULL && before->Name() ? before->Name() : "NULL"));
3907
3908	if (!_AddChild(child, before))
3909		return;
3910
3911	if (fLayoutData->fLayout)
3912		fLayoutData->fLayout->AddView(child);
3913}
3914
3915
3916bool
3917BView::AddChild(BLayoutItem* child)
3918{
3919	if (!fLayoutData->fLayout)
3920		return false;
3921	return fLayoutData->fLayout->AddItem(child);
3922}
3923
3924
3925bool
3926BView::_AddChild(BView* child, BView* before)
3927{
3928	if (!child)
3929		return false;
3930
3931	if (child->fParent != NULL) {
3932		debugger("AddChild failed - the view already has a parent.");
3933		return false;
3934	}
3935
3936	bool lockedOwner = false;
3937	if (fOwner && !fOwner->IsLocked()) {
3938		fOwner->Lock();
3939		lockedOwner = true;
3940	}
3941
3942	if (!_AddChildToList(child, before)) {
3943		debugger("AddChild failed!");
3944		if (lockedOwner)
3945			fOwner->Unlock();
3946		return false;
3947	}
3948
3949	if (fOwner) {
3950		_CheckLockAndSwitchCurrent();
3951
3952		child->_SetOwner(fOwner);
3953		child->_CreateSelf();
3954		child->_Attach();
3955
3956		if (lockedOwner)
3957			fOwner->Unlock();
3958	}
3959
3960	InvalidateLayout();
3961
3962	return true;
3963}
3964
3965
3966bool
3967BView::RemoveChild(BView* child)
3968{
3969	STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
3970
3971	if (!child)
3972		return false;
3973
3974	if (child->fParent != this)
3975		return false;
3976
3977	return child->RemoveSelf();
3978}
3979
3980int32
3981BView::CountChildren() const
3982{
3983	_CheckLock();
3984
3985	uint32 count = 0;
3986	BView* child = fFirstChild;
3987
3988	while (child != NULL) {
3989		count++;
3990		child = child->fNextSibling;
3991	}
3992
3993	return count;
3994}
3995
3996
3997BView*
3998BView::ChildAt(int32 index) const
3999{
4000	_CheckLock();
4001
4002	BView* child = fFirstChild;
4003	while (child != NULL && index-- > 0) {
4004		child = child->fNextSibling;
4005	}
4006
4007	return child;
4008}
4009
4010
4011BView*
4012BView::NextSibling() const
4013{
4014	return fNextSibling;
4015}
4016
4017
4018BView*
4019BView::PreviousSibling() const
4020{
4021	return fPreviousSibling;
4022}
4023
4024
4025bool
4026BView::RemoveSelf()
4027{
4028	if (fParent && fParent->fLayoutData->fLayout) {
4029		int32 itemsRemaining = fLayoutData->fLayoutItems.CountItems();
4030		while (itemsRemaining-- > 0) {
4031			BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(0);
4032				// always remove item at index 0, since items are shuffled
4033				// downwards by BObjectList
4034			item->Layout()->RemoveItem(item);
4035				// removes item from fLayoutItems list
4036			delete item;
4037		}
4038	}
4039
4040	return _RemoveSelf();
4041}
4042
4043
4044bool
4045BView::_RemoveSelf()
4046{
4047	STRACE(("BView(%s)::_RemoveSelf()\n", Name()));
4048
4049	// Remove this child from its parent
4050
4051	BWindow* owner = fOwner;
4052	_CheckLock();
4053
4054	if (owner != NULL) {
4055		_UpdateStateForRemove();
4056		_Detach();
4057	}
4058
4059	BView* parent = fParent;
4060	if (!parent || !parent->_RemoveChildFromList(this))
4061		return false;
4062
4063	if (owner != NULL && !fTopLevelView) {
4064		// the top level view is deleted by the app_server automatically
4065		owner->fLink->StartMessage(AS_VIEW_DELETE);
4066		owner->fLink->Attach<int32>(_get_object_token_(this));
4067	}
4068
4069	parent->InvalidateLayout();
4070
4071	STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name()));
4072
4073	return true;
4074}
4075
4076
4077BView*
4078BView::Parent() const
4079{
4080	if (fParent && fParent->fTopLevelView)
4081		return NULL;
4082
4083	return fParent;
4084}
4085
4086
4087BView*
4088BView::FindView(const char* name) const
4089{
4090	if (name == NULL)
4091		return NULL;
4092
4093	if (Name() != NULL && !strcmp(Name(), name))
4094		return const_cast<BView*>(this);
4095
4096	BView* child = fFirstChild;
4097	while (child != NULL) {
4098		BView* view = child->FindView(name);
4099		if (view != NULL)
4100			return view;
4101
4102		child = child->fNextSibling;
4103	}
4104
4105	return NULL;
4106}
4107
4108
4109void
4110BView::MoveBy(float deltaX, float deltaY)
4111{
4112	MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY));
4113}
4114
4115
4116void
4117BView::MoveTo(BPoint where)
4118{
4119	MoveTo(where.x, where.y);
4120}
4121
4122
4123void
4124BView::MoveTo(float x, float y)
4125{
4126	if (x == fParentOffset.x && y == fParentOffset.y)
4127		return;
4128
4129	// BeBook says we should do this. And it makes sense.
4130	x = roundf(x);
4131	y = roundf(y);
4132
4133	if (fOwner) {
4134		_CheckLockAndSwitchCurrent();
4135		fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO);
4136		fOwner->fLink->Attach<float>(x);
4137		fOwner->fLink->Attach<float>(y);
4138
4139//		fState->valid_flags |= B_VIEW_FRAME_BIT;
4140
4141		_FlushIfNotInTransaction();
4142	}
4143
4144	_MoveTo((int32)x, (int32)y);
4145}
4146
4147
4148void
4149BView::ResizeBy(float deltaWidth, float deltaHeight)
4150{
4151	// BeBook says we should do this. And it makes sense.
4152	deltaWidth = roundf(deltaWidth);
4153	deltaHeight = roundf(deltaHeight);
4154
4155	if (deltaWidth == 0 && deltaHeight == 0)
4156		return;
4157
4158	if (fOwner) {
4159		_CheckLockAndSwitchCurrent();
4160		fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO);
4161
4162		fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth);
4163		fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight);
4164
4165//		fState->valid_flags |= B_VIEW_FRAME_BIT;
4166
4167		_FlushIfNotInTransaction();
4168	}
4169
4170	_ResizeBy((int32)deltaWidth, (int32)deltaHeight);
4171}
4172
4173
4174void
4175BView::ResizeTo(float width, float height)
4176{
4177	ResizeBy(width - fBounds.Width(), height - fBounds.Height());
4178}
4179
4180
4181void
4182BView::ResizeTo(BSize size)
4183{
4184	ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height());
4185}
4186
4187
4188//	#pragma mark - Inherited Methods (from BHandler)
4189
4190
4191status_t
4192BView::GetSupportedSuites(BMessage* data)
4193{
4194	if (data == NULL)
4195		return B_BAD_VALUE;
4196
4197	status_t status = data->AddString("suites", "suite/vnd.Be-view");
4198	BPropertyInfo propertyInfo(sViewPropInfo);
4199	if (status == B_OK)
4200		status = data->AddFlat("messages", &propertyInfo);
4201	if (status == B_OK)
4202		return BHandler::GetSupportedSuites(data);
4203	return status;
4204}
4205
4206
4207BHandler*
4208BView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
4209	int32 what,	const char* property)
4210{
4211	if (msg->what == B_WINDOW_MOVE_BY
4212		|| msg->what == B_WINDOW_MOVE_TO)
4213		return this;
4214
4215	BPropertyInfo propertyInfo(sViewPropInfo);
4216	status_t err = B_BAD_SCRIPT_SYNTAX;
4217	BMessage replyMsg(B_REPLY);
4218
4219	switch (propertyInfo.FindMatch(msg, index, specifier, what, property)) {
4220		case 0:
4221		case 1:
4222		case 3:
4223			return this;
4224
4225		case 2:
4226			if (fShelf) {
4227				msg->PopSpecifier();
4228				return fShelf;
4229			}
4230
4231			err = B_NAME_NOT_FOUND;
4232			replyMsg.AddString("message", "This window doesn't have a shelf");
4233			break;
4234
4235		case 4:
4236		{
4237			if (!fFirstChild) {
4238				err = B_NAME_NOT_FOUND;
4239				replyMsg.AddString("message", "This window doesn't have "
4240					"children.");
4241				break;
4242			}
4243			BView* child = NULL;
4244			switch (what) {
4245				case B_INDEX_SPECIFIER:
4246				{
4247					int32 index;
4248					err = specifier->FindInt32("index", &index);
4249					if (err == B_OK)
4250						child = ChildAt(index);
4251					break;
4252				}
4253				case B_REVERSE_INDEX_SPECIFIER:
4254				{
4255					int32 rindex;
4256					err = specifier->FindInt32("index", &rindex);
4257					if (err == B_OK)
4258						child = ChildAt(CountChildren() - rindex);
4259					break;
4260				}
4261				case B_NAME_SPECIFIER:
4262				{
4263					const char* name;
4264					err = specifier->FindString("name", &name);
4265					if (err == B_OK)
4266						child = FindView(name);
4267					break;
4268				}
4269			}
4270
4271			if (child != NULL) {
4272				msg->PopSpecifier();
4273				return child;
4274			}
4275
4276			if (err == B_OK)
4277				err = B_BAD_INDEX;
4278
4279			replyMsg.AddString("message",
4280				"Cannot find view at/with specified index/name.");
4281			break;
4282		}
4283
4284		default:
4285			return BHandler::ResolveSpecifier(msg, index, specifier, what,
4286				property);
4287	}
4288
4289	if (err < B_OK) {
4290		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4291
4292		if (err == B_BAD_SCRIPT_SYNTAX)
4293			replyMsg.AddString("message", "Didn't understand the specifier(s)");
4294		else
4295			replyMsg.AddString("message", strerror(err));
4296	}
4297
4298	replyMsg.AddInt32("error", err);
4299	msg->SendReply(&replyMsg);
4300	return NULL;
4301}
4302
4303
4304void
4305BView::MessageReceived(BMessage* msg)
4306{
4307	if (!msg->HasSpecifiers()) {
4308		switch (msg->what) {
4309			case B_VIEW_RESIZED:
4310				// By the time the message arrives, the bounds may have
4311				// changed already, that's why we don't use the values
4312				// in the message itself.
4313				FrameResized(fBounds.Width(), fBounds.Height());
4314				break;
4315
4316			case B_VIEW_MOVED:
4317				FrameMoved(fParentOffset);
4318				break;
4319
4320			case B_MOUSE_IDLE:
4321			{
4322				BPoint where;
4323				if (msg->FindPoint("be:view_where", &where) != B_OK)
4324					break;
4325
4326				BToolTip* tip;
4327				if (GetToolTipAt(where, &tip))
4328					ShowToolTip(tip);
4329				else
4330					BHandler::MessageReceived(msg);
4331				break;
4332			}
4333
4334			case B_MOUSE_WHEEL_CHANGED:
4335			{
4336				BScrollBar* horizontal = ScrollBar(B_HORIZONTAL);
4337				BScrollBar* vertical = ScrollBar(B_VERTICAL);
4338				if (horizontal == NULL && vertical == NULL) {
4339					// Pass the message to the next handler
4340					BHandler::MessageReceived(msg);
4341					break;
4342				}
4343
4344				float deltaX = 0.0f, deltaY = 0.0f;
4345				if (horizontal != NULL)
4346					msg->FindFloat("be:wheel_delta_x", &deltaX);
4347				if (vertical != NULL)
4348					msg->FindFloat("be:wheel_delta_y", &deltaY);
4349
4350				if (deltaX == 0.0f && deltaY == 0.0f)
4351					break;
4352
4353				if (horizontal != NULL) {
4354					ScrollWithMouseWheelDelta(horizontal, deltaX);
4355				}
4356
4357				if (vertical != NULL) {
4358					ScrollWithMouseWheelDelta(vertical, deltaY);
4359				}
4360				break;
4361			}
4362
4363			default:
4364				BHandler::MessageReceived(msg);
4365				break;
4366		}
4367
4368		return;
4369	}
4370
4371	// Scripting message
4372
4373	BMessage replyMsg(B_REPLY);
4374	status_t err = B_BAD_SCRIPT_SYNTAX;
4375	int32 index;
4376	BMessage specifier;
4377	int32 what;
4378	const char* property;
4379
4380	if (msg->GetCurrentSpecifier(&index, &specifier, &what, &property) != B_OK)
4381		return BHandler::MessageReceived(msg);
4382
4383	BPropertyInfo propertyInfo(sViewPropInfo);
4384	switch (propertyInfo.FindMatch(msg, index, &specifier, what, property)) {
4385		case 0:
4386			if (msg->what == B_GET_PROPERTY) {
4387				err = replyMsg.AddRect("result", Frame());
4388			} else if (msg->what == B_SET_PROPERTY) {
4389				BRect newFrame;
4390				err = msg->FindRect("data", &newFrame);
4391				if (err == B_OK) {
4392					MoveTo(newFrame.LeftTop());
4393					ResizeTo(newFrame.Width(), newFrame.Height());
4394				}
4395			}
4396			break;
4397		case 1:
4398			if (msg->what == B_GET_PROPERTY) {
4399				err = replyMsg.AddBool("result", IsHidden());
4400			} else if (msg->what == B_SET_PROPERTY) {
4401				bool newHiddenState;
4402				err = msg->FindBool("data", &newHiddenState);
4403				if (err == B_OK) {
4404					if (newHiddenState == true)
4405						Hide();
4406					else
4407						Show();
4408				}
4409			}
4410			break;
4411		case 3:
4412			err = replyMsg.AddInt32("result", CountChildren());
4413			break;
4414		default:
4415			return BHandler::MessageReceived(msg);
4416	}
4417
4418	if (err != B_OK) {
4419		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4420
4421		if (err == B_BAD_SCRIPT_SYNTAX)
4422			replyMsg.AddString("message", "Didn't understand the specifier(s)");
4423		else
4424			replyMsg.AddString("message", strerror(err));
4425
4426		replyMsg.AddInt32("error", err);
4427	}
4428
4429	msg->SendReply(&replyMsg);
4430}
4431
4432
4433status_t
4434BView::Perform(perform_code code, void* _data)
4435{
4436	switch (code) {
4437		case PERFORM_CODE_MIN_SIZE:
4438			((perform_data_min_size*)_data)->return_value
4439				= BView::MinSize();
4440			return B_OK;
4441		case PERFORM_CODE_MAX_SIZE:
4442			((perform_data_max_size*)_data)->return_value
4443				= BView::MaxSize();
4444			return B_OK;
4445		case PERFORM_CODE_PREFERRED_SIZE:
4446			((perform_data_preferred_size*)_data)->return_value
4447				= BView::PreferredSize();
4448			return B_OK;
4449		case PERFORM_CODE_LAYOUT_ALIGNMENT:
4450			((perform_data_layout_alignment*)_data)->return_value
4451				= BView::LayoutAlignment();
4452			return B_OK;
4453		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
4454			((perform_data_has_height_for_width*)_data)->return_value
4455				= BView::HasHeightForWidth();
4456			return B_OK;
4457		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
4458		{
4459			perform_data_get_height_for_width* data
4460				= (perform_data_get_height_for_width*)_data;
4461			BView::GetHeightForWidth(data->width, &data->min, &data->max,
4462				&data->preferred);
4463			return B_OK;
4464		}
4465		case PERFORM_CODE_SET_LAYOUT:
4466		{
4467			perform_data_set_layout* data = (perform_data_set_layout*)_data;
4468			BView::SetLayout(data->layout);
4469			return B_OK;
4470		}
4471		case PERFORM_CODE_LAYOUT_INVALIDATED:
4472		{
4473			perform_data_layout_invalidated* data
4474				= (perform_data_layout_invalidated*)_data;
4475			BView::LayoutInvalidated(data->descendants);
4476			return B_OK;
4477		}
4478		case PERFORM_CODE_DO_LAYOUT:
4479		{
4480			BView::DoLayout();
4481			return B_OK;
4482		}
4483		case PERFORM_CODE_LAYOUT_CHANGED:
4484		{
4485			BView::LayoutChanged();
4486			return B_OK;
4487		}
4488		case PERFORM_CODE_GET_TOOL_TIP_AT:
4489		{
4490			perform_data_get_tool_tip_at* data
4491				= (perform_data_get_tool_tip_at*)_data;
4492			data->return_value
4493				= BView::GetToolTipAt(data->point, data->tool_tip);
4494			return B_OK;
4495		}
4496		case PERFORM_CODE_ALL_UNARCHIVED:
4497		{
4498			perform_data_all_unarchived* data =
4499				(perform_data_all_unarchived*)_data;
4500
4501			data->return_value = BView::AllUnarchived(data->archive);
4502			return B_OK;
4503		}
4504		case PERFORM_CODE_ALL_ARCHIVED:
4505		{
4506			perform_data_all_archived* data =
4507				(perform_data_all_archived*)_data;
4508
4509			data->return_value = BView::AllArchived(data->archive);
4510			return B_OK;
4511		}
4512	}
4513
4514	return BHandler::Perform(code, _data);
4515}
4516
4517
4518// #pragma mark - Layout Functions
4519
4520
4521BSize
4522BView::MinSize()
4523{
4524	// TODO: make sure this works correctly when some methods are overridden
4525	float width, height;
4526	GetPreferredSize(&width, &height);
4527
4528	return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
4529		(fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
4530			: BSize(width, height)));
4531}
4532
4533
4534BSize
4535BView::MaxSize()
4536{
4537	return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
4538		(fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
4539			: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
4540}
4541
4542
4543BSize
4544BView::PreferredSize()
4545{
4546	// TODO: make sure this works correctly when some methods are overridden
4547	float width, height;
4548	GetPreferredSize(&width, &height);
4549
4550	return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
4551		(fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
4552			: BSize(width, height)));
4553}
4554
4555
4556BAlignment
4557BView::LayoutAlignment()
4558{
4559	return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
4560		(fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
4561			: BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
4562}
4563
4564
4565void
4566BView::SetExplicitMinSize(BSize size)
4567{
4568	fLayoutData->fMinSize = size;
4569	InvalidateLayout();
4570}
4571
4572
4573void
4574BView::SetExplicitMaxSize(BSize size)
4575{
4576	fLayoutData->fMaxSize = size;
4577	InvalidateLayout();
4578}
4579
4580
4581void
4582BView::SetExplicitPreferredSize(BSize size)
4583{
4584	fLayoutData->fPreferredSize = size;
4585	InvalidateLayout();
4586}
4587
4588
4589void
4590BView::SetExplicitSize(BSize size)
4591{
4592	fLayoutData->fMinSize = size;
4593	fLayoutData->fMaxSize = size;
4594	fLayoutData->fPreferredSize = size;
4595	InvalidateLayout();
4596}
4597
4598
4599void
4600BView::SetExplicitAlignment(BAlignment alignment)
4601{
4602	fLayoutData->fAlignment = alignment;
4603	InvalidateLayout();
4604}
4605
4606
4607BSize
4608BView::ExplicitMinSize() const
4609{
4610	return fLayoutData->fMinSize;
4611}
4612
4613
4614BSize
4615BView::ExplicitMaxSize() const
4616{
4617	return fLayoutData->fMaxSize;
4618}
4619
4620
4621BSize
4622BView::ExplicitPreferredSize() const
4623{
4624	return fLayoutData->fPreferredSize;
4625}
4626
4627
4628BAlignment
4629BView::ExplicitAlignment() const
4630{
4631	return fLayoutData->fAlignment;
4632}
4633
4634
4635bool
4636BView::HasHeightForWidth()
4637{
4638	return (fLayoutData->fLayout
4639		? fLayoutData->fLayout->HasHeightForWidth() : false);
4640}
4641
4642
4643void
4644BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
4645{
4646	if (fLayoutData->fLayout)
4647		fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
4648}
4649
4650
4651void
4652BView::SetLayout(BLayout* layout)
4653{
4654	if (layout == fLayoutData->fLayout)
4655		return;
4656
4657	if (layout && layout->Layout())
4658		debugger("BView::SetLayout() failed, layout is already in use.");
4659
4660	fFlags |= B_SUPPORTS_LAYOUT;
4661
4662	// unset and delete the old layout
4663	if (fLayoutData->fLayout) {
4664		fLayoutData->fLayout->SetOwner(NULL);
4665		delete fLayoutData->fLayout;
4666	}
4667
4668	fLayoutData->fLayout = layout;
4669
4670	if (fLayoutData->fLayout) {
4671		fLayoutData->fLayout->SetOwner(this);
4672
4673		// add all children
4674		int count = CountChildren();
4675		for (int i = 0; i < count; i++)
4676			fLayoutData->fLayout->AddView(ChildAt(i));
4677	}
4678
4679	InvalidateLayout();
4680}
4681
4682
4683BLayout*
4684BView::GetLayout() const
4685{
4686	return fLayoutData->fLayout;
4687}
4688
4689
4690void
4691BView::InvalidateLayout(bool descendants)
4692{
4693	// printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
4694	//	this, descendants, fLayoutData->fLayoutValid,
4695	//	fLayoutData->fLayoutInProgress);
4696
4697	if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
4698 			|| fLayoutData->fLayoutInvalidationDisabled > 0) {
4699		return;
4700	}
4701
4702	fLayoutData->fLayoutValid = false;
4703	fLayoutData->fMinMaxValid = false;
4704	LayoutInvalidated(descendants);
4705
4706	if (descendants) {
4707		for (BView* child = fFirstChild;
4708			child; child = child->fNextSibling) {
4709			child->InvalidateLayout(descendants);
4710		}
4711	}
4712
4713	if (fLayoutData->fLayout)
4714		fLayoutData->fLayout->InvalidateLayout(descendants);
4715	else
4716		_InvalidateParentLayout();
4717
4718	if (fTopLevelView && fOwner)
4719		fOwner->PostMessage(B_LAYOUT_WINDOW);
4720}
4721
4722
4723void
4724BView::EnableLayoutInvalidation()
4725{
4726	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4727		fLayoutData->fLayoutInvalidationDisabled--;
4728}
4729
4730
4731void
4732BView::DisableLayoutInvalidation()
4733{
4734	fLayoutData->fLayoutInvalidationDisabled++;
4735}
4736
4737
4738bool
4739BView::IsLayoutInvalidationDisabled()
4740{
4741	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4742		return true;
4743	return false;
4744}
4745
4746
4747bool
4748BView::IsLayoutValid() const
4749{
4750	return fLayoutData->fLayoutValid;
4751}
4752
4753
4754/*!	\brief Service call for BView derived classes reenabling
4755	InvalidateLayout() notifications.
4756
4757	BLayout & BView will avoid calling InvalidateLayout on views that have
4758	already been invalidated, but if the view caches internal layout information
4759	which it updates in methods other than DoLayout(), it has to invoke this
4760	method, when it has done so, since otherwise the information might become
4761	obsolete without the layout noticing.
4762*/
4763void
4764BView::ResetLayoutInvalidation()
4765{
4766	fLayoutData->fMinMaxValid = true;
4767}
4768
4769
4770BLayoutContext*
4771BView::LayoutContext() const
4772{
4773	return fLayoutData->fLayoutContext;
4774}
4775
4776
4777void
4778BView::Layout(bool force)
4779{
4780	BLayoutContext context;
4781	_Layout(force, &context);
4782}
4783
4784
4785void
4786BView::Relayout()
4787{
4788	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
4789		fLayoutData->fNeedsRelayout = true;
4790		if (fLayoutData->fLayout)
4791			fLayoutData->fLayout->RequireLayout();
4792
4793		// Layout() is recursive, that is if the parent view is currently laid
4794		// out, we don't call layout() on this view, but wait for the parent's
4795		// Layout() to do that for us.
4796		if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
4797			Layout(false);
4798	}
4799}
4800
4801
4802void
4803BView::LayoutInvalidated(bool descendants)
4804{
4805	// hook method
4806}
4807
4808
4809void
4810BView::DoLayout()
4811{
4812	if (fLayoutData->fLayout)
4813		fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
4814}
4815
4816
4817void
4818BView::SetToolTip(const char* text)
4819{
4820	if (text == NULL || text[0] == '\0') {
4821		SetToolTip((BToolTip*)NULL);
4822		return;
4823	}
4824
4825	if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
4826		tip->SetText(text);
4827	else
4828		SetToolTip(new BTextToolTip(text));
4829}
4830
4831
4832void
4833BView::SetToolTip(BToolTip* tip)
4834{
4835	if (fToolTip == tip)
4836		return;
4837	else if (tip == NULL)
4838		HideToolTip();
4839
4840	if (fToolTip != NULL)
4841		fToolTip->ReleaseReference();
4842
4843	fToolTip = tip;
4844
4845	if (fToolTip != NULL)
4846		fToolTip->AcquireReference();
4847}
4848
4849
4850BToolTip*
4851BView::ToolTip() const
4852{
4853	return fToolTip;
4854}
4855
4856
4857void
4858BView::ShowToolTip(BToolTip* tip)
4859{
4860	if (tip == NULL)
4861		return;
4862
4863	BPoint where;
4864	GetMouse(&where, NULL, false);
4865
4866	BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
4867}
4868
4869
4870void
4871BView::HideToolTip()
4872{
4873	BToolTipManager::Manager()->HideTip();
4874}
4875
4876
4877bool
4878BView::GetToolTipAt(BPoint point, BToolTip** _tip)
4879{
4880	if (fToolTip != NULL) {
4881		*_tip = fToolTip;
4882		return true;
4883	}
4884
4885	*_tip = NULL;
4886	return false;
4887}
4888
4889
4890void
4891BView::LayoutChanged()
4892{
4893	// hook method
4894}
4895
4896
4897void
4898BView::_Layout(bool force, BLayoutContext* context)
4899{
4900//printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
4901//printf("  fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
4902//fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
4903//fLayoutData->fLayoutInProgress);
4904	if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
4905		fLayoutData->fLayoutValid = false;
4906
4907		if (fLayoutData->fLayoutInProgress)
4908			return;
4909
4910		BLayoutContext* oldContext = fLayoutData->fLayoutContext;
4911		fLayoutData->fLayoutContext = context;
4912
4913		fLayoutData->fLayoutInProgress = true;
4914		DoLayout();
4915		fLayoutData->fLayoutInProgress = false;
4916
4917		fLayoutData->fLayoutValid = true;
4918		fLayoutData->fMinMaxValid = true;
4919		fLayoutData->fNeedsRelayout = false;
4920
4921		// layout children
4922		for(BView* child = fFirstChild; child; child = child->fNextSibling) {
4923			if (!child->IsHidden(child))
4924				child->_Layout(force, context);
4925		}
4926
4927		LayoutChanged();
4928
4929		fLayoutData->fLayoutContext = oldContext;
4930
4931		// invalidate the drawn content, if requested
4932		if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
4933			Invalidate();
4934	}
4935}
4936
4937
4938void
4939BView::_LayoutLeft(BLayout* deleted)
4940{
4941	// If our layout is added to another layout (via BLayout::AddItem())
4942	// then we share ownership of our layout. In the event that our layout gets
4943	// deleted by the layout it has been added to, this method is called so
4944	// that we don't double-delete our layout.
4945	if (fLayoutData->fLayout == deleted)
4946		fLayoutData->fLayout = NULL;
4947	InvalidateLayout();
4948}
4949
4950
4951void
4952BView::_InvalidateParentLayout()
4953{
4954	if (!fParent)
4955		return;
4956
4957	BLayout* layout = fLayoutData->fLayout;
4958	BLayout* layoutParent = layout ? layout->Layout() : NULL;
4959	if (layoutParent) {
4960		layoutParent->InvalidateLayout();
4961	} else if (fLayoutData->fLayoutItems.CountItems() > 0) {
4962		int32 count = fLayoutData->fLayoutItems.CountItems();
4963		for (int32 i = 0; i < count; i++) {
4964			fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
4965		}
4966	} else {
4967		fParent->InvalidateLayout();
4968	}
4969}
4970
4971
4972//	#pragma mark - Private Functions
4973
4974
4975void
4976BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
4977	uint32 flags)
4978{
4979	// Info: The name of the view is set by BHandler constructor
4980
4981	STRACE(("BView::_InitData: enter\n"));
4982
4983	// initialize members
4984	if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
4985		printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
4986
4987	// There are applications that swap the resize mask and the flags in the
4988	// BView constructor. This does not cause problems under BeOS as it just
4989	// ors the two fields to one 32bit flag.
4990	// For now we do the same but print the above warning message.
4991	// TODO: this should be removed at some point and the original
4992	// version restored:
4993	// fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
4994	fFlags = resizingMode | flags;
4995
4996	// handle rounding
4997	frame.left = roundf(frame.left);
4998	frame.top = roundf(frame.top);
4999	frame.right = roundf(frame.right);
5000	frame.bottom = roundf(frame.bottom);
5001
5002	fParentOffset.Set(frame.left, frame.top);
5003
5004	fOwner = NULL;
5005	fParent = NULL;
5006	fNextSibling = NULL;
5007	fPreviousSibling = NULL;
5008	fFirstChild = NULL;
5009
5010	fShowLevel = 0;
5011	fTopLevelView = false;
5012
5013	fCurrentPicture = NULL;
5014	fCommArray = NULL;
5015
5016	fVerScroller = NULL;
5017	fHorScroller = NULL;
5018
5019	fIsPrinting = false;
5020	fAttached = false;
5021
5022	// TODO: Since we cannot communicate failure, we don't use std::nothrow here
5023	// TODO: Maybe we could auto-delete those views on AddChild() instead?
5024	fState = new BPrivate::ViewState;
5025
5026	fBounds = frame.OffsetToCopy(B_ORIGIN);
5027	fShelf = NULL;
5028
5029	fEventMask = 0;
5030	fEventOptions = 0;
5031	fMouseEventOptions = 0;
5032
5033	fLayoutData = new LayoutData;
5034
5035	fToolTip = NULL;
5036}
5037
5038
5039void
5040BView::_RemoveCommArray()
5041{
5042	if (fCommArray) {
5043		delete [] fCommArray->array;
5044		delete fCommArray;
5045		fCommArray = NULL;
5046	}
5047}
5048
5049
5050void
5051BView::_SetOwner(BWindow* newOwner)
5052{
5053	if (!newOwner)
5054		_RemoveCommArray();
5055
5056	if (fOwner != newOwner && fOwner) {
5057		if (fOwner->fFocus == this)
5058			MakeFocus(false);
5059
5060		if (fOwner->fLastMouseMovedView == this)
5061			fOwner->fLastMouseMovedView = NULL;
5062
5063		fOwner->RemoveHandler(this);
5064		if (fShelf)
5065			fOwner->RemoveHandler(fShelf);
5066	}
5067
5068	if (newOwner && newOwner != fOwner) {
5069		newOwner->AddHandler(this);
5070		if (fShelf)
5071			newOwner->AddHandler(fShelf);
5072
5073		if (fTopLevelView)
5074			SetNextHandler(newOwner);
5075		else
5076			SetNextHandler(fParent);
5077	}
5078
5079	fOwner = newOwner;
5080
5081	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5082		child->_SetOwner(newOwner);
5083}
5084
5085
5086void
5087BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5088{
5089	if (!picture)
5090		return;
5091
5092#if 1
5093	// TODO: Move the implementation to the server!!!
5094	// This implementation is pretty slow, since just creating an offscreen
5095	// bitmap takes a lot of time. That's the main reason why it should be moved
5096	// to the server.
5097
5098	// Here the idea is to get rid of the padding bytes in the bitmap,
5099	// as padding complicates and slows down the iteration.
5100	// TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned
5101	// to a 4 byte boundary.
5102	BRect bounds(Bounds());
5103	if ((bounds.IntegerWidth() + 1) % 32) {
5104		bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1)
5105			* 32 - 1;
5106	}
5107
5108	// TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work.
5109	BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true);
5110	if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) {
5111		BView* view = new(std::nothrow) BView(bounds, "drawing view",
5112			B_FOLLOW_NONE, 0);
5113		if (view != NULL) {
5114			bitmap->AddChild(view);
5115			view->DrawPicture(picture, where);
5116			view->Sync();
5117		}
5118		bitmap->Unlock();
5119	}
5120
5121	BRegion region;
5122	int32 width = bounds.IntegerWidth() + 1;
5123	int32 height = bounds.IntegerHeight() + 1;
5124	if (bitmap != NULL && bitmap->LockBits() == B_OK) {
5125		uint32 bit = 0;
5126		uint32* bits = (uint32*)bitmap->Bits();
5127		clipping_rect rect;
5128
5129		// TODO: A possible optimization would be adding "spans" instead
5130		// of 1x1 rects. That would probably help with very complex
5131		// BPictures
5132		for (int32 y = 0; y < height; y++) {
5133			for (int32 x = 0; x < width; x++) {
5134				bit = *bits++;
5135				if (bit != 0xFFFFFFFF) {
5136					rect.left = x;
5137					rect.right = rect.left;
5138					rect.top = rect.bottom = y;
5139					region.Include(rect);
5140				}
5141			}
5142		}
5143		bitmap->UnlockBits();
5144	}
5145	delete bitmap;
5146
5147	if (invert) {
5148		BRegion inverseRegion;
5149		inverseRegion.Include(Bounds());
5150		inverseRegion.Exclude(&region);
5151		ConstrainClippingRegion(&inverseRegion);
5152	} else
5153		ConstrainClippingRegion(&region);
5154#else
5155	if (_CheckOwnerLockAndSwitchCurrent()) {
5156		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5157		fOwner->fLink->Attach<int32>(picture->Token());
5158		fOwner->fLink->Attach<BPoint>(where);
5159		fOwner->fLink->Attach<bool>(invert);
5160
5161		// TODO: I think that "sync" means another thing here:
5162		// the bebook, at least, says so.
5163		if (sync)
5164			fOwner->fLink->Flush();
5165
5166		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
5167	}
5168
5169	fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
5170#endif
5171}
5172
5173
5174bool
5175BView::_RemoveChildFromList(BView* child)
5176{
5177	if (child->fParent != this)
5178		return false;
5179
5180	if (fFirstChild == child) {
5181		// it's the first view in the list
5182		fFirstChild = child->fNextSibling;
5183	} else {
5184		// there must be a previous sibling
5185		child->fPreviousSibling->fNextSibling = child->fNextSibling;
5186	}
5187
5188	if (child->fNextSibling)
5189		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
5190
5191	child->fParent = NULL;
5192	child->fNextSibling = NULL;
5193	child->fPreviousSibling = NULL;
5194
5195	return true;
5196}
5197
5198
5199bool
5200BView::_AddChildToList(BView* child, BView* before)
5201{
5202	if (!child)
5203		return false;
5204	if (child->fParent != NULL) {
5205		debugger("View already belongs to someone else");
5206		return false;
5207	}
5208	if (before != NULL && before->fParent != this) {
5209		debugger("Invalid before view");
5210		return false;
5211	}
5212
5213	if (before != NULL) {
5214		// add view before this one
5215		child->fNextSibling = before;
5216		child->fPreviousSibling = before->fPreviousSibling;
5217		if (child->fPreviousSibling != NULL)
5218			child->fPreviousSibling->fNextSibling = child;
5219
5220		before->fPreviousSibling = child;
5221		if (fFirstChild == before)
5222			fFirstChild = child;
5223	} else {
5224		// add view to the end of the list
5225		BView* last = fFirstChild;
5226		while (last != NULL && last->fNextSibling != NULL) {
5227			last = last->fNextSibling;
5228		}
5229
5230		if (last != NULL) {
5231			last->fNextSibling = child;
5232			child->fPreviousSibling = last;
5233		} else {
5234			fFirstChild = child;
5235			child->fPreviousSibling = NULL;
5236		}
5237
5238		child->fNextSibling = NULL;
5239	}
5240
5241	child->fParent = this;
5242	return true;
5243}
5244
5245
5246/*!	\brief Creates the server counterpart of this view.
5247	This is only done for views that are part of the view hierarchy, ie. when
5248	they are attached to a window.
5249	RemoveSelf() deletes the server object again.
5250*/
5251bool
5252BView::_CreateSelf()
5253{
5254	// AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
5255	// current view mechanism via _CheckLockAndSwitchCurrent() - the token
5256	// of the view and its parent are both send to the server.
5257
5258	if (fTopLevelView)
5259		fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
5260	else
5261 		fOwner->fLink->StartMessage(AS_VIEW_CREATE);
5262
5263	fOwner->fLink->Attach<int32>(_get_object_token_(this));
5264	fOwner->fLink->AttachString(Name());
5265	fOwner->fLink->Attach<BRect>(Frame());
5266	fOwner->fLink->Attach<BPoint>(LeftTop());
5267	fOwner->fLink->Attach<uint32>(ResizingMode());
5268	fOwner->fLink->Attach<uint32>(fEventMask);
5269	fOwner->fLink->Attach<uint32>(fEventOptions);
5270	fOwner->fLink->Attach<uint32>(Flags());
5271	fOwner->fLink->Attach<bool>(IsHidden(this));
5272	fOwner->fLink->Attach<rgb_color>(fState->view_color);
5273	if (fTopLevelView)
5274		fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
5275	else
5276		fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
5277	fOwner->fLink->Flush();
5278
5279	_CheckOwnerLockAndSwitchCurrent();
5280	fState->UpdateServerState(*fOwner->fLink);
5281
5282	// we create all its children, too
5283
5284	for (BView* child = fFirstChild; child != NULL;
5285			child = child->fNextSibling) {
5286		child->_CreateSelf();
5287	}
5288
5289	fOwner->fLink->Flush();
5290	return true;
5291}
5292
5293
5294/*!	Sets the new view position.
5295	It doesn't contact the server, though - the only case where this
5296	is called outside of MoveTo() is as reaction of moving a view
5297	in the server (a.k.a. B_WINDOW_RESIZED).
5298	It also calls the BView's FrameMoved() hook.
5299*/
5300void
5301BView::_MoveTo(int32 x, int32 y)
5302{
5303	fParentOffset.Set(x, y);
5304
5305	if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
5306		BMessage moved(B_VIEW_MOVED);
5307		moved.AddInt64("when", system_time());
5308		moved.AddPoint("where", BPoint(x, y));
5309
5310		BMessenger target(this);
5311		target.SendMessage(&moved);
5312	}
5313}
5314
5315
5316/*!	Computes the actual new frame size and recalculates the size of
5317	the children as well.
5318	It doesn't contact the server, though - the only case where this
5319	is called outside of ResizeBy() is as reaction of resizing a view
5320	in the server (a.k.a. B_WINDOW_RESIZED).
5321	It also calls the BView's FrameResized() hook.
5322*/
5323void
5324BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
5325{
5326	fBounds.right += deltaWidth;
5327	fBounds.bottom += deltaHeight;
5328
5329	if (Window() == NULL) {
5330		// we're not supposed to exercise the resizing code in case
5331		// we haven't been attached to a window yet
5332		return;
5333	}
5334
5335	// layout the children
5336	if (fFlags & B_SUPPORTS_LAYOUT) {
5337		Relayout();
5338	} else {
5339		for (BView* child = fFirstChild; child; child = child->fNextSibling)
5340			child->_ParentResizedBy(deltaWidth, deltaHeight);
5341	}
5342
5343	if (fFlags & B_FRAME_EVENTS) {
5344		BMessage resized(B_VIEW_RESIZED);
5345		resized.AddInt64("when", system_time());
5346		resized.AddInt32("width", fBounds.IntegerWidth());
5347		resized.AddInt32("height", fBounds.IntegerHeight());
5348
5349		BMessenger target(this);
5350		target.SendMessage(&resized);
5351	}
5352}
5353
5354
5355/*!	Relayouts the view according to its resizing mode. */
5356void
5357BView::_ParentResizedBy(int32 x, int32 y)
5358{
5359	uint32 resizingMode = fFlags & _RESIZE_MASK_;
5360	BRect newFrame = Frame();
5361
5362	// follow with left side
5363	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
5364		newFrame.left += x;
5365	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
5366		newFrame.left += x / 2;
5367
5368	// follow with right side
5369	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
5370		newFrame.right += x;
5371	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
5372		newFrame.right += x / 2;
5373
5374	// follow with top side
5375	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
5376		newFrame.top += y;
5377	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
5378		newFrame.top += y / 2;
5379
5380	// follow with bottom side
5381	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
5382		newFrame.bottom += y;
5383	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
5384		newFrame.bottom += y / 2;
5385
5386	if (newFrame.LeftTop() != fParentOffset) {
5387		// move view
5388		_MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
5389	}
5390
5391	if (newFrame != Frame()) {
5392		// resize view
5393		int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
5394		int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
5395		_ResizeBy(widthDiff, heightDiff);
5396	}
5397}
5398
5399
5400void
5401BView::_Activate(bool active)
5402{
5403	WindowActivated(active);
5404
5405	for (BView* child = fFirstChild; child != NULL;
5406			child = child->fNextSibling) {
5407		child->_Activate(active);
5408	}
5409}
5410
5411
5412void
5413BView::_Attach()
5414{
5415	AttachedToWindow();
5416	fAttached = true;
5417
5418	// after giving the view a chance to do this itself,
5419	// check for the B_PULSE_NEEDED flag and make sure the
5420	// window set's up the pulse messaging
5421	if (fOwner) {
5422		if (fFlags & B_PULSE_NEEDED) {
5423			_CheckLock();
5424			if (fOwner->fPulseRunner == NULL)
5425				fOwner->SetPulseRate(fOwner->PulseRate());
5426		}
5427
5428		if (!fOwner->IsHidden())
5429			Invalidate();
5430	}
5431
5432	for (BView* child = fFirstChild; child != NULL;
5433			child = child->fNextSibling) {
5434		// we need to check for fAttached as new views could have been
5435		// added in AttachedToWindow() - and those are already attached
5436		if (!child->fAttached)
5437			child->_Attach();
5438	}
5439
5440	AllAttached();
5441}
5442
5443
5444void
5445BView::_Detach()
5446{
5447	DetachedFromWindow();
5448	fAttached = false;
5449
5450	for (BView* child = fFirstChild; child != NULL;
5451			child = child->fNextSibling) {
5452		child->_Detach();
5453	}
5454
5455	AllDetached();
5456
5457	if (fOwner) {
5458		_CheckLock();
5459
5460		if (!fOwner->IsHidden())
5461			Invalidate();
5462
5463		// make sure our owner doesn't need us anymore
5464
5465		if (fOwner->CurrentFocus() == this) {
5466			MakeFocus(false);
5467			// MakeFocus() is virtual and might not be
5468			// passing through to the BView version,
5469			// but we need to make sure at this point
5470			// that we are not the focus view anymore.
5471			if (fOwner->CurrentFocus() == this)
5472				fOwner->_SetFocus(NULL, true);
5473		}
5474
5475		if (fOwner->fDefaultButton == this)
5476			fOwner->SetDefaultButton(NULL);
5477
5478		if (fOwner->fKeyMenuBar == this)
5479			fOwner->fKeyMenuBar = NULL;
5480
5481		if (fOwner->fLastMouseMovedView == this)
5482			fOwner->fLastMouseMovedView = NULL;
5483
5484		if (fOwner->fLastViewToken == _get_object_token_(this))
5485			fOwner->fLastViewToken = B_NULL_TOKEN;
5486
5487		_SetOwner(NULL);
5488	}
5489}
5490
5491
5492void
5493BView::_Draw(BRect updateRect)
5494{
5495	if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
5496		return;
5497
5498	// NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
5499	// -> View is simply not drawn at all
5500
5501	_SwitchServerCurrentView();
5502
5503	ConvertFromScreen(&updateRect);
5504
5505	// TODO: make states robust (the hook implementation could
5506	// mess things up if it uses non-matching Push- and PopState(),
5507	// we would not be guaranteed to still have the same state on
5508	// the stack after having called Draw())
5509	PushState();
5510	Draw(updateRect);
5511	PopState();
5512	Flush();
5513}
5514
5515
5516void
5517BView::_DrawAfterChildren(BRect updateRect)
5518{
5519	if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
5520		|| !(Flags() & B_DRAW_ON_CHILDREN))
5521		return;
5522
5523	_SwitchServerCurrentView();
5524
5525	ConvertFromScreen(&updateRect);
5526
5527	// TODO: make states robust (see above)
5528	PushState();
5529	DrawAfterChildren(updateRect);
5530	PopState();
5531	Flush();
5532}
5533
5534
5535void
5536BView::_Pulse()
5537{
5538	if ((Flags() & B_PULSE_NEEDED) != 0)
5539		Pulse();
5540
5541	for (BView* child = fFirstChild; child != NULL;
5542			child = child->fNextSibling) {
5543		child->_Pulse();
5544	}
5545}
5546
5547
5548void
5549BView::_UpdateStateForRemove()
5550{
5551	// TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
5552	if (!_CheckOwnerLockAndSwitchCurrent())
5553		return;
5554
5555	fState->UpdateFrom(*fOwner->fLink);
5556//	if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
5557//		fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
5558//
5559//		status_t code;
5560//		if (fOwner->fLink->FlushWithReply(code) == B_OK
5561//			&& code == B_OK) {
5562//			fOwner->fLink->Read<BPoint>(&fParentOffset);
5563//			fOwner->fLink->Read<BRect>(&fBounds);
5564//			fState->valid_flags |= B_VIEW_FRAME_BIT;
5565//		}
5566//	}
5567
5568	// update children as well
5569
5570	for (BView* child = fFirstChild; child != NULL;
5571			child = child->fNextSibling) {
5572		if (child->fOwner)
5573			child->_UpdateStateForRemove();
5574	}
5575}
5576
5577
5578inline void
5579BView::_UpdatePattern(::pattern pattern)
5580{
5581	if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
5582		return;
5583
5584	if (fOwner) {
5585		_CheckLockAndSwitchCurrent();
5586
5587		fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
5588		fOwner->fLink->Attach< ::pattern>(pattern);
5589
5590		fState->valid_flags |= B_VIEW_PATTERN_BIT;
5591	}
5592
5593	fState->pattern = pattern;
5594}
5595
5596
5597void
5598BView::_FlushIfNotInTransaction()
5599{
5600	if (!fOwner->fInTransaction) {
5601		fOwner->Flush();
5602	}
5603}
5604
5605
5606BShelf*
5607BView::_Shelf() const
5608{
5609	return fShelf;
5610}
5611
5612
5613void
5614BView::_SetShelf(BShelf* shelf)
5615{
5616	if (fShelf != NULL && fOwner != NULL)
5617		fOwner->RemoveHandler(fShelf);
5618
5619	fShelf = shelf;
5620
5621	if (fShelf != NULL && fOwner != NULL)
5622		fOwner->AddHandler(fShelf);
5623}
5624
5625
5626status_t
5627BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
5628	uint32 followFlags, uint32 options)
5629{
5630	if (!_CheckOwnerLockAndSwitchCurrent())
5631		return B_ERROR;
5632
5633	int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
5634
5635	fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
5636	fOwner->fLink->Attach<int32>(serverToken);
5637	fOwner->fLink->Attach<BRect>(srcRect);
5638	fOwner->fLink->Attach<BRect>(dstRect);
5639	fOwner->fLink->Attach<int32>(followFlags);
5640	fOwner->fLink->Attach<int32>(options);
5641
5642	status_t status = B_ERROR;
5643	fOwner->fLink->FlushWithReply(status);
5644
5645	return status;
5646}
5647
5648
5649bool
5650BView::_CheckOwnerLockAndSwitchCurrent() const
5651{
5652	STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
5653
5654	if (fOwner == NULL) {
5655		debugger("View method requires owner and doesn't have one.");
5656		return false;
5657	}
5658
5659	_CheckLockAndSwitchCurrent();
5660
5661	return true;
5662}
5663
5664
5665bool
5666BView::_CheckOwnerLock() const
5667{
5668	if (fOwner) {
5669		fOwner->check_lock();
5670		return true;
5671	} else {
5672		debugger("View method requires owner and doesn't have one.");
5673		return false;
5674	}
5675}
5676
5677
5678void
5679BView::_CheckLockAndSwitchCurrent() const
5680{
5681	STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
5682
5683	if (!fOwner)
5684		return;
5685
5686	fOwner->check_lock();
5687
5688	_SwitchServerCurrentView();
5689}
5690
5691
5692void
5693BView::_CheckLock() const
5694{
5695	if (fOwner)
5696		fOwner->check_lock();
5697}
5698
5699
5700void
5701BView::_SwitchServerCurrentView() const
5702{
5703	int32 serverToken = _get_object_token_(this);
5704
5705	if (fOwner->fLastViewToken != serverToken) {
5706		STRACE(("contacting app_server... sending token: %ld\n", serverToken));
5707		fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
5708		fOwner->fLink->Attach<int32>(serverToken);
5709
5710		fOwner->fLastViewToken = serverToken;
5711	}
5712}
5713
5714
5715void
5716BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
5717{
5718	if (scrollBar == NULL || delta == 0.0f)
5719		return;
5720
5721	float smallStep, largeStep;
5722	scrollBar->GetSteps(&smallStep, &largeStep);
5723
5724	// pressing the shift key scrolls faster (following the pseudo-standard set
5725	// by other desktop environments).
5726	if ((modifiers() & B_SHIFT_KEY) != 0)
5727		delta *= largeStep;
5728	else
5729		delta *= smallStep * 3;
5730
5731	scrollBar->SetValue(scrollBar->Value() + delta);
5732}
5733
5734
5735#if __GNUC__ == 2
5736
5737
5738extern "C" void
5739_ReservedView1__5BView(BView* view, BRect rect)
5740{
5741	view->BView::DrawAfterChildren(rect);
5742}
5743
5744
5745extern "C" void
5746_ReservedView2__5BView(BView* view)
5747{
5748	// MinSize()
5749	perform_data_min_size data;
5750	view->Perform(PERFORM_CODE_MIN_SIZE, &data);
5751}
5752
5753
5754extern "C" void
5755_ReservedView3__5BView(BView* view)
5756{
5757	// MaxSize()
5758	perform_data_max_size data;
5759	view->Perform(PERFORM_CODE_MAX_SIZE, &data);
5760}
5761
5762
5763extern "C" BSize
5764_ReservedView4__5BView(BView* view)
5765{
5766	// PreferredSize()
5767	perform_data_preferred_size data;
5768	view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
5769	return data.return_value;
5770}
5771
5772
5773extern "C" BAlignment
5774_ReservedView5__5BView(BView* view)
5775{
5776	// LayoutAlignment()
5777	perform_data_layout_alignment data;
5778	view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
5779	return data.return_value;
5780}
5781
5782
5783extern "C" bool
5784_ReservedView6__5BView(BView* view)
5785{
5786	// HasHeightForWidth()
5787	perform_data_has_height_for_width data;
5788	view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
5789	return data.return_value;
5790}
5791
5792
5793extern "C" void
5794_ReservedView7__5BView(BView* view, float width, float* min, float* max,
5795	float* preferred)
5796{
5797	// GetHeightForWidth()
5798	perform_data_get_height_for_width data;
5799	data.width = width;
5800	view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
5801	if (min != NULL)
5802		*min = data.min;
5803	if (max != NULL)
5804		*max = data.max;
5805	if (preferred != NULL)
5806		*preferred = data.preferred;
5807}
5808
5809
5810extern "C" void
5811_ReservedView8__5BView(BView* view, BLayout* layout)
5812{
5813	// SetLayout()
5814	perform_data_set_layout data;
5815	data.layout = layout;
5816	view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
5817}
5818
5819
5820extern "C" void
5821_ReservedView9__5BView(BView* view, bool descendants)
5822{
5823	// LayoutInvalidated()
5824	perform_data_layout_invalidated data;
5825	data.descendants = descendants;
5826	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
5827}
5828
5829
5830extern "C" void
5831_ReservedView10__5BView(BView* view)
5832{
5833	// DoLayout()
5834	view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
5835}
5836
5837
5838#endif	// __GNUC__ == 2
5839
5840
5841extern "C" bool
5842B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
5843	BView* view, BPoint point, BToolTip** _toolTip)
5844{
5845	// GetToolTipAt()
5846	perform_data_get_tool_tip_at data;
5847	data.point = point;
5848	data.tool_tip = _toolTip;
5849	view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
5850	return data.return_value;
5851}
5852
5853
5854extern "C" void
5855B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
5856	BView* view)
5857{
5858	// LayoutChanged();
5859	view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
5860}
5861
5862
5863void BView::_ReservedView13() {}
5864void BView::_ReservedView14() {}
5865void BView::_ReservedView15() {}
5866void BView::_ReservedView16() {}
5867
5868
5869BView::BView(const BView& other)
5870	:
5871	BHandler()
5872{
5873	// this is private and not functional, but exported
5874}
5875
5876
5877BView&
5878BView::operator=(const BView& other)
5879{
5880	// this is private and not functional, but exported
5881	return *this;
5882}
5883
5884
5885void
5886BView::_PrintToStream()
5887{
5888	printf("BView::_PrintToStream()\n");
5889	printf("\tName: %s\n"
5890		"\tParent: %s\n"
5891		"\tFirstChild: %s\n"
5892		"\tNextSibling: %s\n"
5893		"\tPrevSibling: %s\n"
5894		"\tOwner(Window): %s\n"
5895		"\tToken: %" B_PRId32 "\n"
5896		"\tFlags: %" B_PRId32 "\n"
5897		"\tView origin: (%f,%f)\n"
5898		"\tView Bounds rectangle: (%f,%f,%f,%f)\n"
5899		"\tShow level: %d\n"
5900		"\tTopView?: %s\n"
5901		"\tBPicture: %s\n"
5902		"\tVertical Scrollbar %s\n"
5903		"\tHorizontal Scrollbar %s\n"
5904		"\tIs Printing?: %s\n"
5905		"\tShelf?: %s\n"
5906		"\tEventMask: %" B_PRId32 "\n"
5907		"\tEventOptions: %" B_PRId32 "\n",
5908	Name(),
5909	fParent ? fParent->Name() : "NULL",
5910	fFirstChild ? fFirstChild->Name() : "NULL",
5911	fNextSibling ? fNextSibling->Name() : "NULL",
5912	fPreviousSibling ? fPreviousSibling->Name() : "NULL",
5913	fOwner ? fOwner->Name() : "NULL",
5914	_get_object_token_(this),
5915	fFlags,
5916	fParentOffset.x, fParentOffset.y,
5917	fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
5918	fShowLevel,
5919	fTopLevelView ? "YES" : "NO",
5920	fCurrentPicture? "YES" : "NULL",
5921	fVerScroller? "YES" : "NULL",
5922	fHorScroller? "YES" : "NULL",
5923	fIsPrinting? "YES" : "NO",
5924	fShelf? "YES" : "NO",
5925	fEventMask,
5926	fEventOptions);
5927
5928	printf("\tState status:\n"
5929		"\t\tLocalCoordianteSystem: (%f,%f)\n"
5930		"\t\tPenLocation: (%f,%f)\n"
5931		"\t\tPenSize: %f\n"
5932		"\t\tHighColor: [%d,%d,%d,%d]\n"
5933		"\t\tLowColor: [%d,%d,%d,%d]\n"
5934		"\t\tViewColor: [%d,%d,%d,%d]\n"
5935		"\t\tPattern: %" B_PRIx64 "\n"
5936		"\t\tDrawingMode: %d\n"
5937		"\t\tLineJoinMode: %d\n"
5938		"\t\tLineCapMode: %d\n"
5939		"\t\tMiterLimit: %f\n"
5940		"\t\tAlphaSource: %d\n"
5941		"\t\tAlphaFuntion: %d\n"
5942		"\t\tScale: %f\n"
5943		"\t\t(Print)FontAliasing: %s\n"
5944		"\t\tFont Info:\n",
5945	fState->origin.x, fState->origin.y,
5946	fState->pen_location.x, fState->pen_location.y,
5947	fState->pen_size,
5948	fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
5949	fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
5950	fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
5951	*((uint64*)&(fState->pattern)),
5952	fState->drawing_mode,
5953	fState->line_join,
5954	fState->line_cap,
5955	fState->miter_limit,
5956	fState->alpha_source_mode,
5957	fState->alpha_function_mode,
5958	fState->scale,
5959	fState->font_aliasing? "YES" : "NO");
5960
5961	fState->font.PrintToStream();
5962
5963	// TODO: also print the line array.
5964}
5965
5966
5967void
5968BView::_PrintTree()
5969{
5970	int32 spaces = 2;
5971	BView* c = fFirstChild; //c = short for: current
5972	printf( "'%s'\n", Name() );
5973	if (c != NULL) {
5974		while(true) {
5975			// action block
5976			{
5977				for (int i = 0; i < spaces; i++)
5978					printf(" ");
5979
5980				printf( "'%s'\n", c->Name() );
5981			}
5982
5983			// go deep
5984			if (c->fFirstChild) {
5985				c = c->fFirstChild;
5986				spaces += 2;
5987			} else {
5988				// go right
5989				if (c->fNextSibling) {
5990					c = c->fNextSibling;
5991				} else {
5992					// go up
5993					while (!c->fParent->fNextSibling && c->fParent != this) {
5994						c = c->fParent;
5995						spaces -= 2;
5996					}
5997
5998					// that enough! We've reached this view.
5999					if (c->fParent == this)
6000						break;
6001
6002					c = c->fParent->fNextSibling;
6003					spaces -= 2;
6004				}
6005			}
6006		}
6007	}
6008}
6009
6010
6011// #pragma mark -
6012
6013
6014BLayoutItem*
6015BView::Private::LayoutItemAt(int32 index)
6016{
6017	return fView->fLayoutData->fLayoutItems.ItemAt(index);
6018}
6019
6020
6021int32
6022BView::Private::CountLayoutItems()
6023{
6024	return fView->fLayoutData->fLayoutItems.CountItems();
6025}
6026
6027
6028void
6029BView::Private::RegisterLayoutItem(BLayoutItem* item)
6030{
6031	fView->fLayoutData->fLayoutItems.AddItem(item);
6032}
6033
6034
6035void
6036BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6037{
6038	fView->fLayoutData->fLayoutItems.RemoveItem(item);
6039}
6040
6041
6042bool
6043BView::Private::MinMaxValid()
6044{
6045	return fView->fLayoutData->fMinMaxValid;
6046}
6047
6048
6049bool
6050BView::Private::WillLayout()
6051{
6052	BView::LayoutData* data = fView->fLayoutData;
6053	if (data->fLayoutInProgress)
6054		return false;
6055	if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6056		return true;
6057	return false;
6058}
6059