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