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