xref: /haiku/src/kits/interface/View.cpp (revision 70449c90d95aeea01b25f686d51da4217fe41317)
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 				if (horizontal != NULL) {
4354 					ScrollWithMouseWheelDelta(horizontal, deltaX);
4355 				}
4356 
4357 				if (vertical != NULL) {
4358 					ScrollWithMouseWheelDelta(vertical, deltaY);
4359 				}
4360 				break;
4361 			}
4362 
4363 			default:
4364 				BHandler::MessageReceived(msg);
4365 				break;
4366 		}
4367 
4368 		return;
4369 	}
4370 
4371 	// Scripting message
4372 
4373 	BMessage replyMsg(B_REPLY);
4374 	status_t err = B_BAD_SCRIPT_SYNTAX;
4375 	int32 index;
4376 	BMessage specifier;
4377 	int32 what;
4378 	const char* property;
4379 
4380 	if (msg->GetCurrentSpecifier(&index, &specifier, &what, &property) != B_OK)
4381 		return BHandler::MessageReceived(msg);
4382 
4383 	BPropertyInfo propertyInfo(sViewPropInfo);
4384 	switch (propertyInfo.FindMatch(msg, index, &specifier, what, property)) {
4385 		case 0:
4386 			if (msg->what == B_GET_PROPERTY) {
4387 				err = replyMsg.AddRect("result", Frame());
4388 			} else if (msg->what == B_SET_PROPERTY) {
4389 				BRect newFrame;
4390 				err = msg->FindRect("data", &newFrame);
4391 				if (err == B_OK) {
4392 					MoveTo(newFrame.LeftTop());
4393 					ResizeTo(newFrame.Width(), newFrame.Height());
4394 				}
4395 			}
4396 			break;
4397 		case 1:
4398 			if (msg->what == B_GET_PROPERTY) {
4399 				err = replyMsg.AddBool("result", IsHidden());
4400 			} else if (msg->what == B_SET_PROPERTY) {
4401 				bool newHiddenState;
4402 				err = msg->FindBool("data", &newHiddenState);
4403 				if (err == B_OK) {
4404 					if (newHiddenState == true)
4405 						Hide();
4406 					else
4407 						Show();
4408 				}
4409 			}
4410 			break;
4411 		case 3:
4412 			err = replyMsg.AddInt32("result", CountChildren());
4413 			break;
4414 		default:
4415 			return BHandler::MessageReceived(msg);
4416 	}
4417 
4418 	if (err != B_OK) {
4419 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4420 
4421 		if (err == B_BAD_SCRIPT_SYNTAX)
4422 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
4423 		else
4424 			replyMsg.AddString("message", strerror(err));
4425 
4426 		replyMsg.AddInt32("error", err);
4427 	}
4428 
4429 	msg->SendReply(&replyMsg);
4430 }
4431 
4432 
4433 status_t
4434 BView::Perform(perform_code code, void* _data)
4435 {
4436 	switch (code) {
4437 		case PERFORM_CODE_MIN_SIZE:
4438 			((perform_data_min_size*)_data)->return_value
4439 				= BView::MinSize();
4440 			return B_OK;
4441 		case PERFORM_CODE_MAX_SIZE:
4442 			((perform_data_max_size*)_data)->return_value
4443 				= BView::MaxSize();
4444 			return B_OK;
4445 		case PERFORM_CODE_PREFERRED_SIZE:
4446 			((perform_data_preferred_size*)_data)->return_value
4447 				= BView::PreferredSize();
4448 			return B_OK;
4449 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
4450 			((perform_data_layout_alignment*)_data)->return_value
4451 				= BView::LayoutAlignment();
4452 			return B_OK;
4453 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
4454 			((perform_data_has_height_for_width*)_data)->return_value
4455 				= BView::HasHeightForWidth();
4456 			return B_OK;
4457 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
4458 		{
4459 			perform_data_get_height_for_width* data
4460 				= (perform_data_get_height_for_width*)_data;
4461 			BView::GetHeightForWidth(data->width, &data->min, &data->max,
4462 				&data->preferred);
4463 			return B_OK;
4464 		}
4465 		case PERFORM_CODE_SET_LAYOUT:
4466 		{
4467 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
4468 			BView::SetLayout(data->layout);
4469 			return B_OK;
4470 		}
4471 		case PERFORM_CODE_LAYOUT_INVALIDATED:
4472 		{
4473 			perform_data_layout_invalidated* data
4474 				= (perform_data_layout_invalidated*)_data;
4475 			BView::LayoutInvalidated(data->descendants);
4476 			return B_OK;
4477 		}
4478 		case PERFORM_CODE_DO_LAYOUT:
4479 		{
4480 			BView::DoLayout();
4481 			return B_OK;
4482 		}
4483 		case PERFORM_CODE_LAYOUT_CHANGED:
4484 		{
4485 			BView::LayoutChanged();
4486 			return B_OK;
4487 		}
4488 		case PERFORM_CODE_GET_TOOL_TIP_AT:
4489 		{
4490 			perform_data_get_tool_tip_at* data
4491 				= (perform_data_get_tool_tip_at*)_data;
4492 			data->return_value
4493 				= BView::GetToolTipAt(data->point, data->tool_tip);
4494 			return B_OK;
4495 		}
4496 		case PERFORM_CODE_ALL_UNARCHIVED:
4497 		{
4498 			perform_data_all_unarchived* data =
4499 				(perform_data_all_unarchived*)_data;
4500 
4501 			data->return_value = BView::AllUnarchived(data->archive);
4502 			return B_OK;
4503 		}
4504 		case PERFORM_CODE_ALL_ARCHIVED:
4505 		{
4506 			perform_data_all_archived* data =
4507 				(perform_data_all_archived*)_data;
4508 
4509 			data->return_value = BView::AllArchived(data->archive);
4510 			return B_OK;
4511 		}
4512 	}
4513 
4514 	return BHandler::Perform(code, _data);
4515 }
4516 
4517 
4518 // #pragma mark - Layout Functions
4519 
4520 
4521 BSize
4522 BView::MinSize()
4523 {
4524 	// TODO: make sure this works correctly when some methods are overridden
4525 	float width, height;
4526 	GetPreferredSize(&width, &height);
4527 
4528 	return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
4529 		(fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
4530 			: BSize(width, height)));
4531 }
4532 
4533 
4534 BSize
4535 BView::MaxSize()
4536 {
4537 	return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
4538 		(fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
4539 			: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
4540 }
4541 
4542 
4543 BSize
4544 BView::PreferredSize()
4545 {
4546 	// TODO: make sure this works correctly when some methods are overridden
4547 	float width, height;
4548 	GetPreferredSize(&width, &height);
4549 
4550 	return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
4551 		(fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
4552 			: BSize(width, height)));
4553 }
4554 
4555 
4556 BAlignment
4557 BView::LayoutAlignment()
4558 {
4559 	return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
4560 		(fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
4561 			: BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
4562 }
4563 
4564 
4565 void
4566 BView::SetExplicitMinSize(BSize size)
4567 {
4568 	fLayoutData->fMinSize = size;
4569 	InvalidateLayout();
4570 }
4571 
4572 
4573 void
4574 BView::SetExplicitMaxSize(BSize size)
4575 {
4576 	fLayoutData->fMaxSize = size;
4577 	InvalidateLayout();
4578 }
4579 
4580 
4581 void
4582 BView::SetExplicitPreferredSize(BSize size)
4583 {
4584 	fLayoutData->fPreferredSize = size;
4585 	InvalidateLayout();
4586 }
4587 
4588 
4589 void
4590 BView::SetExplicitAlignment(BAlignment alignment)
4591 {
4592 	fLayoutData->fAlignment = alignment;
4593 	InvalidateLayout();
4594 }
4595 
4596 
4597 BSize
4598 BView::ExplicitMinSize() const
4599 {
4600 	return fLayoutData->fMinSize;
4601 }
4602 
4603 
4604 BSize
4605 BView::ExplicitMaxSize() const
4606 {
4607 	return fLayoutData->fMaxSize;
4608 }
4609 
4610 
4611 BSize
4612 BView::ExplicitPreferredSize() const
4613 {
4614 	return fLayoutData->fPreferredSize;
4615 }
4616 
4617 
4618 BAlignment
4619 BView::ExplicitAlignment() const
4620 {
4621 	return fLayoutData->fAlignment;
4622 }
4623 
4624 
4625 bool
4626 BView::HasHeightForWidth()
4627 {
4628 	return (fLayoutData->fLayout
4629 		? fLayoutData->fLayout->HasHeightForWidth() : false);
4630 }
4631 
4632 
4633 void
4634 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
4635 {
4636 	if (fLayoutData->fLayout)
4637 		fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
4638 }
4639 
4640 
4641 void
4642 BView::SetLayout(BLayout* layout)
4643 {
4644 	if (layout == fLayoutData->fLayout)
4645 		return;
4646 
4647 	if (layout && layout->Layout())
4648 		debugger("BView::SetLayout() failed, layout is already in use.");
4649 
4650 	fFlags |= B_SUPPORTS_LAYOUT;
4651 
4652 	// unset and delete the old layout
4653 	if (fLayoutData->fLayout) {
4654 		fLayoutData->fLayout->SetOwner(NULL);
4655 		delete fLayoutData->fLayout;
4656 	}
4657 
4658 	fLayoutData->fLayout = layout;
4659 
4660 	if (fLayoutData->fLayout) {
4661 		fLayoutData->fLayout->SetOwner(this);
4662 
4663 		// add all children
4664 		int count = CountChildren();
4665 		for (int i = 0; i < count; i++)
4666 			fLayoutData->fLayout->AddView(ChildAt(i));
4667 	}
4668 
4669 	InvalidateLayout();
4670 }
4671 
4672 
4673 BLayout*
4674 BView::GetLayout() const
4675 {
4676 	return fLayoutData->fLayout;
4677 }
4678 
4679 
4680 void
4681 BView::InvalidateLayout(bool descendants)
4682 {
4683 	// printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
4684 	//	this, descendants, fLayoutData->fLayoutValid,
4685 	//	fLayoutData->fLayoutInProgress);
4686 
4687 	if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
4688  			|| fLayoutData->fLayoutInvalidationDisabled > 0) {
4689 		return;
4690 	}
4691 
4692 	fLayoutData->fLayoutValid = false;
4693 	fLayoutData->fMinMaxValid = false;
4694 	LayoutInvalidated(descendants);
4695 
4696 	if (descendants) {
4697 		for (BView* child = fFirstChild;
4698 			child; child = child->fNextSibling) {
4699 			child->InvalidateLayout(descendants);
4700 		}
4701 	}
4702 
4703 	if (fLayoutData->fLayout)
4704 		fLayoutData->fLayout->InvalidateLayout(descendants);
4705 	else
4706 		_InvalidateParentLayout();
4707 
4708 	if (fTopLevelView && fOwner)
4709 		fOwner->PostMessage(B_LAYOUT_WINDOW);
4710 }
4711 
4712 
4713 void
4714 BView::EnableLayoutInvalidation()
4715 {
4716 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4717 		fLayoutData->fLayoutInvalidationDisabled--;
4718 }
4719 
4720 
4721 void
4722 BView::DisableLayoutInvalidation()
4723 {
4724 	fLayoutData->fLayoutInvalidationDisabled++;
4725 }
4726 
4727 
4728 bool
4729 BView::IsLayoutInvalidationDisabled()
4730 {
4731 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4732 		return true;
4733 	return false;
4734 }
4735 
4736 
4737 bool
4738 BView::IsLayoutValid() const
4739 {
4740 	return fLayoutData->fLayoutValid;
4741 }
4742 
4743 
4744 /*!	\brief Service call for BView derived classes reenabling
4745 	InvalidateLayout() notifications.
4746 
4747 	BLayout & BView will avoid calling InvalidateLayout on views that have
4748 	already been invalidated, but if the view caches internal layout information
4749 	which it updates in methods other than DoLayout(), it has to invoke this
4750 	method, when it has done so, since otherwise the information might become
4751 	obsolete without the layout noticing.
4752 */
4753 void
4754 BView::ResetLayoutInvalidation()
4755 {
4756 	fLayoutData->fMinMaxValid = true;
4757 }
4758 
4759 
4760 BLayoutContext*
4761 BView::LayoutContext() const
4762 {
4763 	return fLayoutData->fLayoutContext;
4764 }
4765 
4766 
4767 void
4768 BView::Layout(bool force)
4769 {
4770 	BLayoutContext context;
4771 	_Layout(force, &context);
4772 }
4773 
4774 
4775 void
4776 BView::Relayout()
4777 {
4778 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
4779 		fLayoutData->fNeedsRelayout = true;
4780 		if (fLayoutData->fLayout)
4781 			fLayoutData->fLayout->RequireLayout();
4782 
4783 		// Layout() is recursive, that is if the parent view is currently laid
4784 		// out, we don't call layout() on this view, but wait for the parent's
4785 		// Layout() to do that for us.
4786 		if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
4787 			Layout(false);
4788 	}
4789 }
4790 
4791 
4792 void
4793 BView::LayoutInvalidated(bool descendants)
4794 {
4795 	// hook method
4796 }
4797 
4798 
4799 void
4800 BView::DoLayout()
4801 {
4802 	if (fLayoutData->fLayout)
4803 		fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
4804 }
4805 
4806 
4807 void
4808 BView::SetToolTip(const char* text)
4809 {
4810 	if (text == NULL || text[0] == '\0') {
4811 		SetToolTip((BToolTip*)NULL);
4812 		return;
4813 	}
4814 
4815 	if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
4816 		tip->SetText(text);
4817 	else
4818 		SetToolTip(new BTextToolTip(text));
4819 }
4820 
4821 
4822 void
4823 BView::SetToolTip(BToolTip* tip)
4824 {
4825 	if (fToolTip == tip)
4826 		return;
4827 	else if (tip == NULL)
4828 		HideToolTip();
4829 
4830 	if (fToolTip != NULL)
4831 		fToolTip->ReleaseReference();
4832 
4833 	fToolTip = tip;
4834 
4835 	if (fToolTip != NULL)
4836 		fToolTip->AcquireReference();
4837 }
4838 
4839 
4840 BToolTip*
4841 BView::ToolTip() const
4842 {
4843 	return fToolTip;
4844 }
4845 
4846 
4847 void
4848 BView::ShowToolTip(BToolTip* tip)
4849 {
4850 	if (tip == NULL)
4851 		return;
4852 
4853 	BPoint where;
4854 	GetMouse(&where, NULL, false);
4855 
4856 	BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
4857 }
4858 
4859 
4860 void
4861 BView::HideToolTip()
4862 {
4863 	BToolTipManager::Manager()->HideTip();
4864 }
4865 
4866 
4867 bool
4868 BView::GetToolTipAt(BPoint point, BToolTip** _tip)
4869 {
4870 	if (fToolTip != NULL) {
4871 		*_tip = fToolTip;
4872 		return true;
4873 	}
4874 
4875 	*_tip = NULL;
4876 	return false;
4877 }
4878 
4879 
4880 void
4881 BView::LayoutChanged()
4882 {
4883 	// hook method
4884 }
4885 
4886 
4887 void
4888 BView::_Layout(bool force, BLayoutContext* context)
4889 {
4890 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
4891 //printf("  fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
4892 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
4893 //fLayoutData->fLayoutInProgress);
4894 	if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
4895 		fLayoutData->fLayoutValid = false;
4896 
4897 		if (fLayoutData->fLayoutInProgress)
4898 			return;
4899 
4900 		BLayoutContext* oldContext = fLayoutData->fLayoutContext;
4901 		fLayoutData->fLayoutContext = context;
4902 
4903 		fLayoutData->fLayoutInProgress = true;
4904 		DoLayout();
4905 		fLayoutData->fLayoutInProgress = false;
4906 
4907 		fLayoutData->fLayoutValid = true;
4908 		fLayoutData->fMinMaxValid = true;
4909 		fLayoutData->fNeedsRelayout = false;
4910 
4911 		// layout children
4912 		for(BView* child = fFirstChild; child; child = child->fNextSibling) {
4913 			if (!child->IsHidden(child))
4914 				child->_Layout(force, context);
4915 		}
4916 
4917 		LayoutChanged();
4918 
4919 		fLayoutData->fLayoutContext = oldContext;
4920 
4921 		// invalidate the drawn content, if requested
4922 		if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
4923 			Invalidate();
4924 	}
4925 }
4926 
4927 
4928 void
4929 BView::_LayoutLeft(BLayout* deleted)
4930 {
4931 	// If our layout is added to another layout (via BLayout::AddItem())
4932 	// then we share ownership of our layout. In the event that our layout gets
4933 	// deleted by the layout it has been added to, this method is called so
4934 	// that we don't double-delete our layout.
4935 	if (fLayoutData->fLayout == deleted)
4936 		fLayoutData->fLayout = NULL;
4937 	InvalidateLayout();
4938 }
4939 
4940 
4941 void
4942 BView::_InvalidateParentLayout()
4943 {
4944 	if (!fParent)
4945 		return;
4946 
4947 	BLayout* layout = fLayoutData->fLayout;
4948 	BLayout* layoutParent = layout ? layout->Layout() : NULL;
4949 	if (layoutParent) {
4950 		layoutParent->InvalidateLayout();
4951 	} else if (fLayoutData->fLayoutItems.CountItems() > 0) {
4952 		int32 count = fLayoutData->fLayoutItems.CountItems();
4953 		for (int32 i = 0; i < count; i++) {
4954 			fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
4955 		}
4956 	} else {
4957 		fParent->InvalidateLayout();
4958 	}
4959 }
4960 
4961 
4962 //	#pragma mark - Private Functions
4963 
4964 
4965 void
4966 BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
4967 	uint32 flags)
4968 {
4969 	// Info: The name of the view is set by BHandler constructor
4970 
4971 	STRACE(("BView::_InitData: enter\n"));
4972 
4973 	// initialize members
4974 	if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
4975 		printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
4976 
4977 	// There are applications that swap the resize mask and the flags in the
4978 	// BView constructor. This does not cause problems under BeOS as it just
4979 	// ors the two fields to one 32bit flag.
4980 	// For now we do the same but print the above warning message.
4981 	// TODO: this should be removed at some point and the original
4982 	// version restored:
4983 	// fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
4984 	fFlags = resizingMode | flags;
4985 
4986 	// handle rounding
4987 	frame.left = roundf(frame.left);
4988 	frame.top = roundf(frame.top);
4989 	frame.right = roundf(frame.right);
4990 	frame.bottom = roundf(frame.bottom);
4991 
4992 	fParentOffset.Set(frame.left, frame.top);
4993 
4994 	fOwner = NULL;
4995 	fParent = NULL;
4996 	fNextSibling = NULL;
4997 	fPreviousSibling = NULL;
4998 	fFirstChild = NULL;
4999 
5000 	fShowLevel = 0;
5001 	fTopLevelView = false;
5002 
5003 	fCurrentPicture = NULL;
5004 	fCommArray = NULL;
5005 
5006 	fVerScroller = NULL;
5007 	fHorScroller = NULL;
5008 
5009 	fIsPrinting = false;
5010 	fAttached = false;
5011 
5012 	// TODO: Since we cannot communicate failure, we don't use std::nothrow here
5013 	// TODO: Maybe we could auto-delete those views on AddChild() instead?
5014 	fState = new BPrivate::ViewState;
5015 
5016 	fBounds = frame.OffsetToCopy(B_ORIGIN);
5017 	fShelf = NULL;
5018 
5019 	fEventMask = 0;
5020 	fEventOptions = 0;
5021 	fMouseEventOptions = 0;
5022 
5023 	fLayoutData = new LayoutData;
5024 
5025 	fToolTip = NULL;
5026 }
5027 
5028 
5029 void
5030 BView::_RemoveCommArray()
5031 {
5032 	if (fCommArray) {
5033 		delete [] fCommArray->array;
5034 		delete fCommArray;
5035 		fCommArray = NULL;
5036 	}
5037 }
5038 
5039 
5040 void
5041 BView::_SetOwner(BWindow* newOwner)
5042 {
5043 	if (!newOwner)
5044 		_RemoveCommArray();
5045 
5046 	if (fOwner != newOwner && fOwner) {
5047 		if (fOwner->fFocus == this)
5048 			MakeFocus(false);
5049 
5050 		if (fOwner->fLastMouseMovedView == this)
5051 			fOwner->fLastMouseMovedView = NULL;
5052 
5053 		fOwner->RemoveHandler(this);
5054 		if (fShelf)
5055 			fOwner->RemoveHandler(fShelf);
5056 	}
5057 
5058 	if (newOwner && newOwner != fOwner) {
5059 		newOwner->AddHandler(this);
5060 		if (fShelf)
5061 			newOwner->AddHandler(fShelf);
5062 
5063 		if (fTopLevelView)
5064 			SetNextHandler(newOwner);
5065 		else
5066 			SetNextHandler(fParent);
5067 	}
5068 
5069 	fOwner = newOwner;
5070 
5071 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5072 		child->_SetOwner(newOwner);
5073 }
5074 
5075 
5076 void
5077 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5078 {
5079 	if (!picture)
5080 		return;
5081 
5082 #if 1
5083 	// TODO: Move the implementation to the server!!!
5084 	// This implementation is pretty slow, since just creating an offscreen
5085 	// bitmap takes a lot of time. That's the main reason why it should be moved
5086 	// to the server.
5087 
5088 	// Here the idea is to get rid of the padding bytes in the bitmap,
5089 	// as padding complicates and slows down the iteration.
5090 	// TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned
5091 	// to a 4 byte boundary.
5092 	BRect bounds(Bounds());
5093 	if ((bounds.IntegerWidth() + 1) % 32) {
5094 		bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1)
5095 			* 32 - 1;
5096 	}
5097 
5098 	// TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work.
5099 	BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true);
5100 	if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) {
5101 		BView* view = new(std::nothrow) BView(bounds, "drawing view",
5102 			B_FOLLOW_NONE, 0);
5103 		if (view != NULL) {
5104 			bitmap->AddChild(view);
5105 			view->DrawPicture(picture, where);
5106 			view->Sync();
5107 		}
5108 		bitmap->Unlock();
5109 	}
5110 
5111 	BRegion region;
5112 	int32 width = bounds.IntegerWidth() + 1;
5113 	int32 height = bounds.IntegerHeight() + 1;
5114 	if (bitmap != NULL && bitmap->LockBits() == B_OK) {
5115 		uint32 bit = 0;
5116 		uint32* bits = (uint32*)bitmap->Bits();
5117 		clipping_rect rect;
5118 
5119 		// TODO: A possible optimization would be adding "spans" instead
5120 		// of 1x1 rects. That would probably help with very complex
5121 		// BPictures
5122 		for (int32 y = 0; y < height; y++) {
5123 			for (int32 x = 0; x < width; x++) {
5124 				bit = *bits++;
5125 				if (bit != 0xFFFFFFFF) {
5126 					rect.left = x;
5127 					rect.right = rect.left;
5128 					rect.top = rect.bottom = y;
5129 					region.Include(rect);
5130 				}
5131 			}
5132 		}
5133 		bitmap->UnlockBits();
5134 	}
5135 	delete bitmap;
5136 
5137 	if (invert) {
5138 		BRegion inverseRegion;
5139 		inverseRegion.Include(Bounds());
5140 		inverseRegion.Exclude(&region);
5141 		ConstrainClippingRegion(&inverseRegion);
5142 	} else
5143 		ConstrainClippingRegion(&region);
5144 #else
5145 	if (_CheckOwnerLockAndSwitchCurrent()) {
5146 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5147 		fOwner->fLink->Attach<int32>(picture->Token());
5148 		fOwner->fLink->Attach<BPoint>(where);
5149 		fOwner->fLink->Attach<bool>(invert);
5150 
5151 		// TODO: I think that "sync" means another thing here:
5152 		// the bebook, at least, says so.
5153 		if (sync)
5154 			fOwner->fLink->Flush();
5155 
5156 		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
5157 	}
5158 
5159 	fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
5160 #endif
5161 }
5162 
5163 
5164 bool
5165 BView::_RemoveChildFromList(BView* child)
5166 {
5167 	if (child->fParent != this)
5168 		return false;
5169 
5170 	if (fFirstChild == child) {
5171 		// it's the first view in the list
5172 		fFirstChild = child->fNextSibling;
5173 	} else {
5174 		// there must be a previous sibling
5175 		child->fPreviousSibling->fNextSibling = child->fNextSibling;
5176 	}
5177 
5178 	if (child->fNextSibling)
5179 		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
5180 
5181 	child->fParent = NULL;
5182 	child->fNextSibling = NULL;
5183 	child->fPreviousSibling = NULL;
5184 
5185 	return true;
5186 }
5187 
5188 
5189 bool
5190 BView::_AddChildToList(BView* child, BView* before)
5191 {
5192 	if (!child)
5193 		return false;
5194 	if (child->fParent != NULL) {
5195 		debugger("View already belongs to someone else");
5196 		return false;
5197 	}
5198 	if (before != NULL && before->fParent != this) {
5199 		debugger("Invalid before view");
5200 		return false;
5201 	}
5202 
5203 	if (before != NULL) {
5204 		// add view before this one
5205 		child->fNextSibling = before;
5206 		child->fPreviousSibling = before->fPreviousSibling;
5207 		if (child->fPreviousSibling != NULL)
5208 			child->fPreviousSibling->fNextSibling = child;
5209 
5210 		before->fPreviousSibling = child;
5211 		if (fFirstChild == before)
5212 			fFirstChild = child;
5213 	} else {
5214 		// add view to the end of the list
5215 		BView* last = fFirstChild;
5216 		while (last != NULL && last->fNextSibling != NULL) {
5217 			last = last->fNextSibling;
5218 		}
5219 
5220 		if (last != NULL) {
5221 			last->fNextSibling = child;
5222 			child->fPreviousSibling = last;
5223 		} else {
5224 			fFirstChild = child;
5225 			child->fPreviousSibling = NULL;
5226 		}
5227 
5228 		child->fNextSibling = NULL;
5229 	}
5230 
5231 	child->fParent = this;
5232 	return true;
5233 }
5234 
5235 
5236 /*!	\brief Creates the server counterpart of this view.
5237 	This is only done for views that are part of the view hierarchy, ie. when
5238 	they are attached to a window.
5239 	RemoveSelf() deletes the server object again.
5240 */
5241 bool
5242 BView::_CreateSelf()
5243 {
5244 	// AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
5245 	// current view mechanism via _CheckLockAndSwitchCurrent() - the token
5246 	// of the view and its parent are both send to the server.
5247 
5248 	if (fTopLevelView)
5249 		fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
5250 	else
5251  		fOwner->fLink->StartMessage(AS_VIEW_CREATE);
5252 
5253 	fOwner->fLink->Attach<int32>(_get_object_token_(this));
5254 	fOwner->fLink->AttachString(Name());
5255 	fOwner->fLink->Attach<BRect>(Frame());
5256 	fOwner->fLink->Attach<BPoint>(LeftTop());
5257 	fOwner->fLink->Attach<uint32>(ResizingMode());
5258 	fOwner->fLink->Attach<uint32>(fEventMask);
5259 	fOwner->fLink->Attach<uint32>(fEventOptions);
5260 	fOwner->fLink->Attach<uint32>(Flags());
5261 	fOwner->fLink->Attach<bool>(IsHidden(this));
5262 	fOwner->fLink->Attach<rgb_color>(fState->view_color);
5263 	if (fTopLevelView)
5264 		fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
5265 	else
5266 		fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
5267 	fOwner->fLink->Flush();
5268 
5269 	_CheckOwnerLockAndSwitchCurrent();
5270 	fState->UpdateServerState(*fOwner->fLink);
5271 
5272 	// we create all its children, too
5273 
5274 	for (BView* child = fFirstChild; child != NULL;
5275 			child = child->fNextSibling) {
5276 		child->_CreateSelf();
5277 	}
5278 
5279 	fOwner->fLink->Flush();
5280 	return true;
5281 }
5282 
5283 
5284 /*!	Sets the new view position.
5285 	It doesn't contact the server, though - the only case where this
5286 	is called outside of MoveTo() is as reaction of moving a view
5287 	in the server (a.k.a. B_WINDOW_RESIZED).
5288 	It also calls the BView's FrameMoved() hook.
5289 */
5290 void
5291 BView::_MoveTo(int32 x, int32 y)
5292 {
5293 	fParentOffset.Set(x, y);
5294 
5295 	if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
5296 		BMessage moved(B_VIEW_MOVED);
5297 		moved.AddInt64("when", system_time());
5298 		moved.AddPoint("where", BPoint(x, y));
5299 
5300 		BMessenger target(this);
5301 		target.SendMessage(&moved);
5302 	}
5303 }
5304 
5305 
5306 /*!	Computes the actual new frame size and recalculates the size of
5307 	the children as well.
5308 	It doesn't contact the server, though - the only case where this
5309 	is called outside of ResizeBy() is as reaction of resizing a view
5310 	in the server (a.k.a. B_WINDOW_RESIZED).
5311 	It also calls the BView's FrameResized() hook.
5312 */
5313 void
5314 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
5315 {
5316 	fBounds.right += deltaWidth;
5317 	fBounds.bottom += deltaHeight;
5318 
5319 	if (Window() == NULL) {
5320 		// we're not supposed to exercise the resizing code in case
5321 		// we haven't been attached to a window yet
5322 		return;
5323 	}
5324 
5325 	// layout the children
5326 	if (fFlags & B_SUPPORTS_LAYOUT) {
5327 		Relayout();
5328 	} else {
5329 		for (BView* child = fFirstChild; child; child = child->fNextSibling)
5330 			child->_ParentResizedBy(deltaWidth, deltaHeight);
5331 	}
5332 
5333 	if (fFlags & B_FRAME_EVENTS) {
5334 		BMessage resized(B_VIEW_RESIZED);
5335 		resized.AddInt64("when", system_time());
5336 		resized.AddInt32("width", fBounds.IntegerWidth());
5337 		resized.AddInt32("height", fBounds.IntegerHeight());
5338 
5339 		BMessenger target(this);
5340 		target.SendMessage(&resized);
5341 	}
5342 }
5343 
5344 
5345 /*!	Relayouts the view according to its resizing mode. */
5346 void
5347 BView::_ParentResizedBy(int32 x, int32 y)
5348 {
5349 	uint32 resizingMode = fFlags & _RESIZE_MASK_;
5350 	BRect newFrame = Frame();
5351 
5352 	// follow with left side
5353 	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
5354 		newFrame.left += x;
5355 	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
5356 		newFrame.left += x / 2;
5357 
5358 	// follow with right side
5359 	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
5360 		newFrame.right += x;
5361 	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
5362 		newFrame.right += x / 2;
5363 
5364 	// follow with top side
5365 	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
5366 		newFrame.top += y;
5367 	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
5368 		newFrame.top += y / 2;
5369 
5370 	// follow with bottom side
5371 	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
5372 		newFrame.bottom += y;
5373 	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
5374 		newFrame.bottom += y / 2;
5375 
5376 	if (newFrame.LeftTop() != fParentOffset) {
5377 		// move view
5378 		_MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
5379 	}
5380 
5381 	if (newFrame != Frame()) {
5382 		// resize view
5383 		int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
5384 		int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
5385 		_ResizeBy(widthDiff, heightDiff);
5386 	}
5387 }
5388 
5389 
5390 void
5391 BView::_Activate(bool active)
5392 {
5393 	WindowActivated(active);
5394 
5395 	for (BView* child = fFirstChild; child != NULL;
5396 			child = child->fNextSibling) {
5397 		child->_Activate(active);
5398 	}
5399 }
5400 
5401 
5402 void
5403 BView::_Attach()
5404 {
5405 	AttachedToWindow();
5406 	fAttached = true;
5407 
5408 	// after giving the view a chance to do this itself,
5409 	// check for the B_PULSE_NEEDED flag and make sure the
5410 	// window set's up the pulse messaging
5411 	if (fOwner) {
5412 		if (fFlags & B_PULSE_NEEDED) {
5413 			_CheckLock();
5414 			if (fOwner->fPulseRunner == NULL)
5415 				fOwner->SetPulseRate(fOwner->PulseRate());
5416 		}
5417 
5418 		if (!fOwner->IsHidden())
5419 			Invalidate();
5420 	}
5421 
5422 	for (BView* child = fFirstChild; child != NULL;
5423 			child = child->fNextSibling) {
5424 		// we need to check for fAttached as new views could have been
5425 		// added in AttachedToWindow() - and those are already attached
5426 		if (!child->fAttached)
5427 			child->_Attach();
5428 	}
5429 
5430 	AllAttached();
5431 }
5432 
5433 
5434 void
5435 BView::_Detach()
5436 {
5437 	DetachedFromWindow();
5438 	fAttached = false;
5439 
5440 	for (BView* child = fFirstChild; child != NULL;
5441 			child = child->fNextSibling) {
5442 		child->_Detach();
5443 	}
5444 
5445 	AllDetached();
5446 
5447 	if (fOwner) {
5448 		_CheckLock();
5449 
5450 		if (!fOwner->IsHidden())
5451 			Invalidate();
5452 
5453 		// make sure our owner doesn't need us anymore
5454 
5455 		if (fOwner->CurrentFocus() == this) {
5456 			MakeFocus(false);
5457 			// MakeFocus() is virtual and might not be
5458 			// passing through to the BView version,
5459 			// but we need to make sure at this point
5460 			// that we are not the focus view anymore.
5461 			if (fOwner->CurrentFocus() == this)
5462 				fOwner->_SetFocus(NULL, true);
5463 		}
5464 
5465 		if (fOwner->fDefaultButton == this)
5466 			fOwner->SetDefaultButton(NULL);
5467 
5468 		if (fOwner->fKeyMenuBar == this)
5469 			fOwner->fKeyMenuBar = NULL;
5470 
5471 		if (fOwner->fLastMouseMovedView == this)
5472 			fOwner->fLastMouseMovedView = NULL;
5473 
5474 		if (fOwner->fLastViewToken == _get_object_token_(this))
5475 			fOwner->fLastViewToken = B_NULL_TOKEN;
5476 
5477 		_SetOwner(NULL);
5478 	}
5479 }
5480 
5481 
5482 void
5483 BView::_Draw(BRect updateRect)
5484 {
5485 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
5486 		return;
5487 
5488 	// NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
5489 	// -> View is simply not drawn at all
5490 
5491 	_SwitchServerCurrentView();
5492 
5493 	ConvertFromScreen(&updateRect);
5494 
5495 	// TODO: make states robust (the hook implementation could
5496 	// mess things up if it uses non-matching Push- and PopState(),
5497 	// we would not be guaranteed to still have the same state on
5498 	// the stack after having called Draw())
5499 	PushState();
5500 	Draw(updateRect);
5501 	PopState();
5502 	Flush();
5503 }
5504 
5505 
5506 void
5507 BView::_DrawAfterChildren(BRect updateRect)
5508 {
5509 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
5510 		|| !(Flags() & B_DRAW_ON_CHILDREN))
5511 		return;
5512 
5513 	_SwitchServerCurrentView();
5514 
5515 	ConvertFromScreen(&updateRect);
5516 
5517 	// TODO: make states robust (see above)
5518 	PushState();
5519 	DrawAfterChildren(updateRect);
5520 	PopState();
5521 	Flush();
5522 }
5523 
5524 
5525 void
5526 BView::_Pulse()
5527 {
5528 	if ((Flags() & B_PULSE_NEEDED) != 0)
5529 		Pulse();
5530 
5531 	for (BView* child = fFirstChild; child != NULL;
5532 			child = child->fNextSibling) {
5533 		child->_Pulse();
5534 	}
5535 }
5536 
5537 
5538 void
5539 BView::_UpdateStateForRemove()
5540 {
5541 	// TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
5542 	if (!_CheckOwnerLockAndSwitchCurrent())
5543 		return;
5544 
5545 	fState->UpdateFrom(*fOwner->fLink);
5546 //	if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
5547 //		fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
5548 //
5549 //		status_t code;
5550 //		if (fOwner->fLink->FlushWithReply(code) == B_OK
5551 //			&& code == B_OK) {
5552 //			fOwner->fLink->Read<BPoint>(&fParentOffset);
5553 //			fOwner->fLink->Read<BRect>(&fBounds);
5554 //			fState->valid_flags |= B_VIEW_FRAME_BIT;
5555 //		}
5556 //	}
5557 
5558 	// update children as well
5559 
5560 	for (BView* child = fFirstChild; child != NULL;
5561 			child = child->fNextSibling) {
5562 		if (child->fOwner)
5563 			child->_UpdateStateForRemove();
5564 	}
5565 }
5566 
5567 
5568 inline void
5569 BView::_UpdatePattern(::pattern pattern)
5570 {
5571 	if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
5572 		return;
5573 
5574 	if (fOwner) {
5575 		_CheckLockAndSwitchCurrent();
5576 
5577 		fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
5578 		fOwner->fLink->Attach< ::pattern>(pattern);
5579 
5580 		fState->valid_flags |= B_VIEW_PATTERN_BIT;
5581 	}
5582 
5583 	fState->pattern = pattern;
5584 }
5585 
5586 
5587 void
5588 BView::_FlushIfNotInTransaction()
5589 {
5590 	if (!fOwner->fInTransaction) {
5591 		fOwner->Flush();
5592 	}
5593 }
5594 
5595 
5596 BShelf*
5597 BView::_Shelf() const
5598 {
5599 	return fShelf;
5600 }
5601 
5602 
5603 void
5604 BView::_SetShelf(BShelf* shelf)
5605 {
5606 	if (fShelf != NULL && fOwner != NULL)
5607 		fOwner->RemoveHandler(fShelf);
5608 
5609 	fShelf = shelf;
5610 
5611 	if (fShelf != NULL && fOwner != NULL)
5612 		fOwner->AddHandler(fShelf);
5613 }
5614 
5615 
5616 status_t
5617 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
5618 	uint32 followFlags, uint32 options)
5619 {
5620 	if (!_CheckOwnerLockAndSwitchCurrent())
5621 		return B_ERROR;
5622 
5623 	int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
5624 
5625 	fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
5626 	fOwner->fLink->Attach<int32>(serverToken);
5627 	fOwner->fLink->Attach<BRect>(srcRect);
5628 	fOwner->fLink->Attach<BRect>(dstRect);
5629 	fOwner->fLink->Attach<int32>(followFlags);
5630 	fOwner->fLink->Attach<int32>(options);
5631 
5632 	status_t status = B_ERROR;
5633 	fOwner->fLink->FlushWithReply(status);
5634 
5635 	return status;
5636 }
5637 
5638 
5639 bool
5640 BView::_CheckOwnerLockAndSwitchCurrent() const
5641 {
5642 	STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
5643 
5644 	if (fOwner == NULL) {
5645 		debugger("View method requires owner and doesn't have one.");
5646 		return false;
5647 	}
5648 
5649 	_CheckLockAndSwitchCurrent();
5650 
5651 	return true;
5652 }
5653 
5654 
5655 bool
5656 BView::_CheckOwnerLock() const
5657 {
5658 	if (fOwner) {
5659 		fOwner->check_lock();
5660 		return true;
5661 	} else {
5662 		debugger("View method requires owner and doesn't have one.");
5663 		return false;
5664 	}
5665 }
5666 
5667 
5668 void
5669 BView::_CheckLockAndSwitchCurrent() const
5670 {
5671 	STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
5672 
5673 	if (!fOwner)
5674 		return;
5675 
5676 	fOwner->check_lock();
5677 
5678 	_SwitchServerCurrentView();
5679 }
5680 
5681 
5682 void
5683 BView::_CheckLock() const
5684 {
5685 	if (fOwner)
5686 		fOwner->check_lock();
5687 }
5688 
5689 
5690 void
5691 BView::_SwitchServerCurrentView() const
5692 {
5693 	int32 serverToken = _get_object_token_(this);
5694 
5695 	if (fOwner->fLastViewToken != serverToken) {
5696 		STRACE(("contacting app_server... sending token: %ld\n", serverToken));
5697 		fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
5698 		fOwner->fLink->Attach<int32>(serverToken);
5699 
5700 		fOwner->fLastViewToken = serverToken;
5701 	}
5702 }
5703 
5704 
5705 void
5706 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
5707 {
5708 	if (scrollBar == NULL || delta == 0.0f)
5709 		return;
5710 
5711 	float smallStep, largeStep;
5712 	scrollBar->GetSteps(&smallStep, &largeStep);
5713 
5714 	// pressing the option/command/control key scrolls faster
5715 	if (modifiers()
5716 			& (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) {
5717 		delta *= largeStep;
5718 	} else
5719 		delta *= smallStep * 3;
5720 
5721 	scrollBar->SetValue(scrollBar->Value() + delta);
5722 }
5723 
5724 
5725 #if __GNUC__ == 2
5726 
5727 
5728 extern "C" void
5729 _ReservedView1__5BView(BView* view, BRect rect)
5730 {
5731 	view->BView::DrawAfterChildren(rect);
5732 }
5733 
5734 
5735 extern "C" void
5736 _ReservedView2__5BView(BView* view)
5737 {
5738 	// MinSize()
5739 	perform_data_min_size data;
5740 	view->Perform(PERFORM_CODE_MIN_SIZE, &data);
5741 }
5742 
5743 
5744 extern "C" void
5745 _ReservedView3__5BView(BView* view)
5746 {
5747 	// MaxSize()
5748 	perform_data_max_size data;
5749 	view->Perform(PERFORM_CODE_MAX_SIZE, &data);
5750 }
5751 
5752 
5753 extern "C" BSize
5754 _ReservedView4__5BView(BView* view)
5755 {
5756 	// PreferredSize()
5757 	perform_data_preferred_size data;
5758 	view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
5759 	return data.return_value;
5760 }
5761 
5762 
5763 extern "C" BAlignment
5764 _ReservedView5__5BView(BView* view)
5765 {
5766 	// LayoutAlignment()
5767 	perform_data_layout_alignment data;
5768 	view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
5769 	return data.return_value;
5770 }
5771 
5772 
5773 extern "C" bool
5774 _ReservedView6__5BView(BView* view)
5775 {
5776 	// HasHeightForWidth()
5777 	perform_data_has_height_for_width data;
5778 	view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
5779 	return data.return_value;
5780 }
5781 
5782 
5783 extern "C" void
5784 _ReservedView7__5BView(BView* view, float width, float* min, float* max,
5785 	float* preferred)
5786 {
5787 	// GetHeightForWidth()
5788 	perform_data_get_height_for_width data;
5789 	data.width = width;
5790 	view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
5791 	if (min != NULL)
5792 		*min = data.min;
5793 	if (max != NULL)
5794 		*max = data.max;
5795 	if (preferred != NULL)
5796 		*preferred = data.preferred;
5797 }
5798 
5799 
5800 extern "C" void
5801 _ReservedView8__5BView(BView* view, BLayout* layout)
5802 {
5803 	// SetLayout()
5804 	perform_data_set_layout data;
5805 	data.layout = layout;
5806 	view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
5807 }
5808 
5809 
5810 extern "C" void
5811 _ReservedView9__5BView(BView* view, bool descendants)
5812 {
5813 	// LayoutInvalidated()
5814 	perform_data_layout_invalidated data;
5815 	data.descendants = descendants;
5816 	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
5817 }
5818 
5819 
5820 extern "C" void
5821 _ReservedView10__5BView(BView* view)
5822 {
5823 	// DoLayout()
5824 	view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
5825 }
5826 
5827 
5828 #endif	// __GNUC__ == 2
5829 
5830 
5831 extern "C" bool
5832 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
5833 	BView* view, BPoint point, BToolTip** _toolTip)
5834 {
5835 	// GetToolTipAt()
5836 	perform_data_get_tool_tip_at data;
5837 	data.point = point;
5838 	data.tool_tip = _toolTip;
5839 	view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
5840 	return data.return_value;
5841 }
5842 
5843 
5844 extern "C" void
5845 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
5846 	BView* view)
5847 {
5848 	// LayoutChanged();
5849 	view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
5850 }
5851 
5852 
5853 void BView::_ReservedView13() {}
5854 void BView::_ReservedView14() {}
5855 void BView::_ReservedView15() {}
5856 void BView::_ReservedView16() {}
5857 
5858 
5859 BView::BView(const BView& other)
5860 	:
5861 	BHandler()
5862 {
5863 	// this is private and not functional, but exported
5864 }
5865 
5866 
5867 BView&
5868 BView::operator=(const BView& other)
5869 {
5870 	// this is private and not functional, but exported
5871 	return *this;
5872 }
5873 
5874 
5875 void
5876 BView::_PrintToStream()
5877 {
5878 	printf("BView::_PrintToStream()\n");
5879 	printf("\tName: %s\n"
5880 		"\tParent: %s\n"
5881 		"\tFirstChild: %s\n"
5882 		"\tNextSibling: %s\n"
5883 		"\tPrevSibling: %s\n"
5884 		"\tOwner(Window): %s\n"
5885 		"\tToken: %ld\n"
5886 		"\tFlags: %ld\n"
5887 		"\tView origin: (%f,%f)\n"
5888 		"\tView Bounds rectangle: (%f,%f,%f,%f)\n"
5889 		"\tShow level: %d\n"
5890 		"\tTopView?: %s\n"
5891 		"\tBPicture: %s\n"
5892 		"\tVertical Scrollbar %s\n"
5893 		"\tHorizontal Scrollbar %s\n"
5894 		"\tIs Printing?: %s\n"
5895 		"\tShelf?: %s\n"
5896 		"\tEventMask: %ld\n"
5897 		"\tEventOptions: %ld\n",
5898 	Name(),
5899 	fParent ? fParent->Name() : "NULL",
5900 	fFirstChild ? fFirstChild->Name() : "NULL",
5901 	fNextSibling ? fNextSibling->Name() : "NULL",
5902 	fPreviousSibling ? fPreviousSibling->Name() : "NULL",
5903 	fOwner ? fOwner->Name() : "NULL",
5904 	_get_object_token_(this),
5905 	fFlags,
5906 	fParentOffset.x, fParentOffset.y,
5907 	fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
5908 	fShowLevel,
5909 	fTopLevelView ? "YES" : "NO",
5910 	fCurrentPicture? "YES" : "NULL",
5911 	fVerScroller? "YES" : "NULL",
5912 	fHorScroller? "YES" : "NULL",
5913 	fIsPrinting? "YES" : "NO",
5914 	fShelf? "YES" : "NO",
5915 	fEventMask,
5916 	fEventOptions);
5917 
5918 	printf("\tState status:\n"
5919 		"\t\tLocalCoordianteSystem: (%f,%f)\n"
5920 		"\t\tPenLocation: (%f,%f)\n"
5921 		"\t\tPenSize: %f\n"
5922 		"\t\tHighColor: [%d,%d,%d,%d]\n"
5923 		"\t\tLowColor: [%d,%d,%d,%d]\n"
5924 		"\t\tViewColor: [%d,%d,%d,%d]\n"
5925 		"\t\tPattern: %llx\n"
5926 		"\t\tDrawingMode: %d\n"
5927 		"\t\tLineJoinMode: %d\n"
5928 		"\t\tLineCapMode: %d\n"
5929 		"\t\tMiterLimit: %f\n"
5930 		"\t\tAlphaSource: %d\n"
5931 		"\t\tAlphaFuntion: %d\n"
5932 		"\t\tScale: %f\n"
5933 		"\t\t(Print)FontAliasing: %s\n"
5934 		"\t\tFont Info:\n",
5935 	fState->origin.x, fState->origin.y,
5936 	fState->pen_location.x, fState->pen_location.y,
5937 	fState->pen_size,
5938 	fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
5939 	fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
5940 	fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
5941 	*((uint64*)&(fState->pattern)),
5942 	fState->drawing_mode,
5943 	fState->line_join,
5944 	fState->line_cap,
5945 	fState->miter_limit,
5946 	fState->alpha_source_mode,
5947 	fState->alpha_function_mode,
5948 	fState->scale,
5949 	fState->font_aliasing? "YES" : "NO");
5950 
5951 	fState->font.PrintToStream();
5952 
5953 	// TODO: also print the line array.
5954 }
5955 
5956 
5957 void
5958 BView::_PrintTree()
5959 {
5960 	int32 spaces = 2;
5961 	BView* c = fFirstChild; //c = short for: current
5962 	printf( "'%s'\n", Name() );
5963 	if (c != NULL) {
5964 		while(true) {
5965 			// action block
5966 			{
5967 				for (int i = 0; i < spaces; i++)
5968 					printf(" ");
5969 
5970 				printf( "'%s'\n", c->Name() );
5971 			}
5972 
5973 			// go deep
5974 			if (c->fFirstChild) {
5975 				c = c->fFirstChild;
5976 				spaces += 2;
5977 			} else {
5978 				// go right
5979 				if (c->fNextSibling) {
5980 					c = c->fNextSibling;
5981 				} else {
5982 					// go up
5983 					while (!c->fParent->fNextSibling && c->fParent != this) {
5984 						c = c->fParent;
5985 						spaces -= 2;
5986 					}
5987 
5988 					// that enough! We've reached this view.
5989 					if (c->fParent == this)
5990 						break;
5991 
5992 					c = c->fParent->fNextSibling;
5993 					spaces -= 2;
5994 				}
5995 			}
5996 		}
5997 	}
5998 }
5999 
6000 
6001 // #pragma mark -
6002 
6003 
6004 BLayoutItem*
6005 BView::Private::LayoutItemAt(int32 index)
6006 {
6007 	return fView->fLayoutData->fLayoutItems.ItemAt(index);
6008 }
6009 
6010 
6011 int32
6012 BView::Private::CountLayoutItems()
6013 {
6014 	return fView->fLayoutData->fLayoutItems.CountItems();
6015 }
6016 
6017 
6018 void
6019 BView::Private::RegisterLayoutItem(BLayoutItem* item)
6020 {
6021 	fView->fLayoutData->fLayoutItems.AddItem(item);
6022 }
6023 
6024 
6025 void
6026 BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6027 {
6028 	fView->fLayoutData->fLayoutItems.RemoveItem(item);
6029 }
6030 
6031 
6032 bool
6033 BView::Private::MinMaxValid()
6034 {
6035 	return fView->fLayoutData->fMinMaxValid;
6036 }
6037 
6038 
6039 bool
6040 BView::Private::WillLayout()
6041 {
6042 	BView::LayoutData* data = fView->fLayoutData;
6043 	if (data->fLayoutInProgress)
6044 		return false;
6045 	if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6046 		return true;
6047 	return false;
6048 }
6049