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