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