xref: /haiku/src/kits/interface/View.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
1 /*
2  * Copyright 2001-2013 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus, superstippi@gmx.de
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Adrian Oanca, adioanca@cotty.iren.ro
9  *		Ingo Weinhold. ingo_weinhold@gmx.de
10  */
11 
12 
13 #include <View.h>
14 
15 #include <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* point, bool checkLock) const
838 {
839 	if (!fParent) {
840 		if (fOwner)
841 			fOwner->ConvertToScreen(point);
842 
843 		return;
844 	}
845 
846 	if (checkLock)
847 		_CheckOwnerLock();
848 
849 	_ConvertToParent(point, false);
850 	fParent->_ConvertToScreen(point, false);
851 }
852 
853 
854 void
855 BView::ConvertToScreen(BPoint* point) const
856 {
857 	_ConvertToScreen(point, true);
858 }
859 
860 
861 BPoint
862 BView::ConvertToScreen(BPoint point) const
863 {
864 	ConvertToScreen(&point);
865 
866 	return point;
867 }
868 
869 
870 void
871 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const
872 {
873 	if (!fParent) {
874 		if (fOwner)
875 			fOwner->ConvertFromScreen(point);
876 
877 		return;
878 	}
879 
880 	if (checkLock)
881 		_CheckOwnerLock();
882 
883 	_ConvertFromParent(point, false);
884 	fParent->_ConvertFromScreen(point, false);
885 }
886 
887 
888 void
889 BView::ConvertFromScreen(BPoint* point) const
890 {
891 	_ConvertFromScreen(point, true);
892 }
893 
894 
895 BPoint
896 BView::ConvertFromScreen(BPoint point) const
897 {
898 	ConvertFromScreen(&point);
899 
900 	return point;
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 updateRect)
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 == NULL)
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* pointArray, int32 numPoints, BRect bounds,
2943 	bool closed, ::pattern pattern)
2944 {
2945 	if (pointArray == NULL
2946 		|| numPoints <= 1
2947 		|| fOwner == NULL)
2948 		return;
2949 
2950 	_CheckLockAndSwitchCurrent();
2951 	_UpdatePattern(pattern);
2952 
2953 	BPolygon polygon(pointArray, 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* pointArray, int32 numPoints, ::pattern pattern)
3025 {
3026 	if (pointArray == NULL)
3027 		return;
3028 
3029 	BPolygon polygon(pointArray, numPoints);
3030 	FillPolygon(&polygon, pattern);
3031 }
3032 
3033 
3034 void
3035 BView::FillPolygon(const BPoint* pointArray, int32 numPoints,
3036 	const BGradient& gradient)
3037 {
3038 	if (pointArray == NULL)
3039 		return;
3040 
3041 	BPolygon polygon(pointArray, numPoints);
3042 	FillPolygon(&polygon, gradient);
3043 }
3044 
3045 
3046 void
3047 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3048 	::pattern pattern)
3049 {
3050 	if (pointArray == NULL)
3051 		return;
3052 
3053 	BPolygon polygon(pointArray, numPoints);
3054 
3055 	polygon.MapTo(polygon.Frame(), bounds);
3056 	FillPolygon(&polygon, pattern);
3057 }
3058 
3059 
3060 void
3061 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3062 	const BGradient& gradient)
3063 {
3064 	if (pointArray == NULL)
3065 		return;
3066 
3067 	BPolygon polygon(pointArray, numPoints);
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 point1, BPoint point2, BPoint point3, 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>(point1);
3236 	fOwner->fLink->Attach<BPoint>(point2);
3237 	fOwner->fLink->Attach<BPoint>(point3);
3238 	fOwner->fLink->Attach<BRect>(bounds);
3239 
3240 	_FlushIfNotInTransaction();
3241 }
3242 
3243 
3244 void
3245 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3,
3246 	::pattern pattern)
3247 {
3248 	if (fOwner) {
3249 		// we construct the smallest rectangle that contains the 3 points
3250 		// for the 1st point
3251 		BRect bounds(point1, point1);
3252 
3253 		// for the 2nd point
3254 		if (point2.x < bounds.left)
3255 			bounds.left = point2.x;
3256 
3257 		if (point2.y < bounds.top)
3258 			bounds.top = point2.y;
3259 
3260 		if (point2.x > bounds.right)
3261 			bounds.right = point2.x;
3262 
3263 		if (point2.y > bounds.bottom)
3264 			bounds.bottom = point2.y;
3265 
3266 		// for the 3rd point
3267 		if (point3.x < bounds.left)
3268 			bounds.left = point3.x;
3269 
3270 		if (point3.y < bounds.top)
3271 			bounds.top = point3.y;
3272 
3273 		if (point3.x > bounds.right)
3274 			bounds.right = point3.x;
3275 
3276 		if (point3.y > bounds.bottom)
3277 			bounds.bottom = point3.y;
3278 
3279 		StrokeTriangle(point1, point2, point3, bounds, pattern);
3280 	}
3281 }
3282 
3283 
3284 void
3285 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3286 	::pattern pattern)
3287 {
3288 	if (fOwner) {
3289 		// we construct the smallest rectangle that contains the 3 points
3290 		// for the 1st point
3291 		BRect bounds(point1, point1);
3292 
3293 		// for the 2nd point
3294 		if (point2.x < bounds.left)
3295 			bounds.left = point2.x;
3296 
3297 		if (point2.y < bounds.top)
3298 			bounds.top = point2.y;
3299 
3300 		if (point2.x > bounds.right)
3301 			bounds.right = point2.x;
3302 
3303 		if (point2.y > bounds.bottom)
3304 			bounds.bottom = point2.y;
3305 
3306 		// for the 3rd point
3307 		if (point3.x < bounds.left)
3308 			bounds.left = point3.x;
3309 
3310 		if (point3.y < bounds.top)
3311 			bounds.top = point3.y;
3312 
3313 		if (point3.x > bounds.right)
3314 			bounds.right = point3.x;
3315 
3316 		if (point3.y > bounds.bottom)
3317 			bounds.bottom = point3.y;
3318 
3319 		FillTriangle(point1, point2, point3, bounds, pattern);
3320 	}
3321 }
3322 
3323 
3324 void
3325 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3326 	const BGradient& gradient)
3327 {
3328 	if (fOwner) {
3329 		// we construct the smallest rectangle that contains the 3 points
3330 		// for the 1st point
3331 		BRect bounds(point1, point1);
3332 
3333 		// for the 2nd point
3334 		if (point2.x < bounds.left)
3335 			bounds.left = point2.x;
3336 
3337 		if (point2.y < bounds.top)
3338 			bounds.top = point2.y;
3339 
3340 		if (point2.x > bounds.right)
3341 			bounds.right = point2.x;
3342 
3343 		if (point2.y > bounds.bottom)
3344 			bounds.bottom = point2.y;
3345 
3346 		// for the 3rd point
3347 		if (point3.x < bounds.left)
3348 			bounds.left = point3.x;
3349 
3350 		if (point3.y < bounds.top)
3351 			bounds.top = point3.y;
3352 
3353 		if (point3.x > bounds.right)
3354 			bounds.right = point3.x;
3355 
3356 		if (point3.y > bounds.bottom)
3357 			bounds.bottom = point3.y;
3358 
3359 		FillTriangle(point1, point2, point3, bounds, gradient);
3360 	}
3361 }
3362 
3363 
3364 void
3365 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3366 	BRect bounds, ::pattern pattern)
3367 {
3368 	if (fOwner == NULL)
3369 		return;
3370 
3371 	_CheckLockAndSwitchCurrent();
3372 	_UpdatePattern(pattern);
3373 
3374 	fOwner->fLink->StartMessage(AS_FILL_TRIANGLE);
3375 	fOwner->fLink->Attach<BPoint>(point1);
3376 	fOwner->fLink->Attach<BPoint>(point2);
3377 	fOwner->fLink->Attach<BPoint>(point3);
3378 	fOwner->fLink->Attach<BRect>(bounds);
3379 
3380 	_FlushIfNotInTransaction();
3381 }
3382 
3383 
3384 void
3385 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
3386 	const BGradient& gradient)
3387 {
3388 	if (fOwner == NULL)
3389 		return;
3390 
3391 	_CheckLockAndSwitchCurrent();
3392 	fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT);
3393 	fOwner->fLink->Attach<BPoint>(point1);
3394 	fOwner->fLink->Attach<BPoint>(point2);
3395 	fOwner->fLink->Attach<BPoint>(point3);
3396 	fOwner->fLink->Attach<BRect>(bounds);
3397 	fOwner->fLink->AttachGradient(gradient);
3398 
3399 	_FlushIfNotInTransaction();
3400 }
3401 
3402 
3403 void
3404 BView::StrokeLine(BPoint toPoint, ::pattern pattern)
3405 {
3406 	StrokeLine(PenLocation(), toPoint, pattern);
3407 }
3408 
3409 
3410 void
3411 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern)
3412 {
3413 	if (fOwner == NULL)
3414 		return;
3415 
3416 	_CheckLockAndSwitchCurrent();
3417 	_UpdatePattern(pattern);
3418 
3419 	ViewStrokeLineInfo info;
3420 	info.startPoint = start;
3421 	info.endPoint = end;
3422 
3423 	fOwner->fLink->StartMessage(AS_STROKE_LINE);
3424 	fOwner->fLink->Attach<ViewStrokeLineInfo>(info);
3425 
3426 	_FlushIfNotInTransaction();
3427 
3428 	// this modifies our pen location, so we invalidate the flag.
3429 	fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3430 }
3431 
3432 
3433 void
3434 BView::StrokeShape(BShape* shape, ::pattern pattern)
3435 {
3436 	if (shape == NULL || fOwner == NULL)
3437 		return;
3438 
3439 	shape_data* sd = (shape_data*)shape->fPrivateData;
3440 	if (sd->opCount == 0 || sd->ptCount == 0)
3441 		return;
3442 
3443 	_CheckLockAndSwitchCurrent();
3444 	_UpdatePattern(pattern);
3445 
3446 	fOwner->fLink->StartMessage(AS_STROKE_SHAPE);
3447 	fOwner->fLink->Attach<BRect>(shape->Bounds());
3448 	fOwner->fLink->Attach<int32>(sd->opCount);
3449 	fOwner->fLink->Attach<int32>(sd->ptCount);
3450 	fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
3451 	fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3452 
3453 	_FlushIfNotInTransaction();
3454 }
3455 
3456 
3457 void
3458 BView::FillShape(BShape* shape, ::pattern pattern)
3459 {
3460 	if (shape == NULL || fOwner == NULL)
3461 		return;
3462 
3463 	shape_data* sd = (shape_data*)(shape->fPrivateData);
3464 	if (sd->opCount == 0 || sd->ptCount == 0)
3465 		return;
3466 
3467 	_CheckLockAndSwitchCurrent();
3468 	_UpdatePattern(pattern);
3469 
3470 	fOwner->fLink->StartMessage(AS_FILL_SHAPE);
3471 	fOwner->fLink->Attach<BRect>(shape->Bounds());
3472 	fOwner->fLink->Attach<int32>(sd->opCount);
3473 	fOwner->fLink->Attach<int32>(sd->ptCount);
3474 	fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3475 	fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3476 
3477 	_FlushIfNotInTransaction();
3478 }
3479 
3480 
3481 void
3482 BView::FillShape(BShape* shape, const BGradient& gradient)
3483 {
3484 	if (shape == NULL || fOwner == NULL)
3485 		return;
3486 
3487 	shape_data* sd = (shape_data*)(shape->fPrivateData);
3488 	if (sd->opCount == 0 || sd->ptCount == 0)
3489 		return;
3490 
3491 	_CheckLockAndSwitchCurrent();
3492 
3493 	fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT);
3494 	fOwner->fLink->Attach<BRect>(shape->Bounds());
3495 	fOwner->fLink->Attach<int32>(sd->opCount);
3496 	fOwner->fLink->Attach<int32>(sd->ptCount);
3497 	fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3498 	fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3499 	fOwner->fLink->AttachGradient(gradient);
3500 
3501 	_FlushIfNotInTransaction();
3502 }
3503 
3504 
3505 void
3506 BView::BeginLineArray(int32 count)
3507 {
3508 	if (fOwner == NULL)
3509 		return;
3510 
3511 	if (count <= 0)
3512 		debugger("Calling BeginLineArray with a count <= 0");
3513 
3514 	_CheckLock();
3515 
3516 	if (fCommArray) {
3517 		debugger("Can't nest BeginLineArray calls");
3518 			// not fatal, but it helps during
3519 			// development of your app and is in
3520 			// line with R5...
3521 		delete[] fCommArray->array;
3522 		delete fCommArray;
3523 	}
3524 
3525 	// TODO: since this method cannot return failure, and further AddLine()
3526 	//	calls with a NULL fCommArray would drop into the debugger anyway,
3527 	//	we allow the possible std::bad_alloc exceptions here...
3528 	fCommArray = new _array_data_;
3529 	fCommArray->maxCount = count;
3530 	fCommArray->count = 0;
3531 	fCommArray->array = new ViewLineArrayInfo[count];
3532 }
3533 
3534 
3535 void
3536 BView::AddLine(BPoint start, BPoint end, rgb_color color)
3537 {
3538 	if (fOwner == NULL)
3539 		return;
3540 
3541 	if (!fCommArray)
3542 		debugger("BeginLineArray must be called before using AddLine");
3543 
3544 	_CheckLock();
3545 
3546 	const uint32 &arrayCount = fCommArray->count;
3547 	if (arrayCount < fCommArray->maxCount) {
3548 		fCommArray->array[arrayCount].startPoint = start;
3549 		fCommArray->array[arrayCount].endPoint = end;
3550 		fCommArray->array[arrayCount].color = color;
3551 
3552 		fCommArray->count++;
3553 	}
3554 }
3555 
3556 
3557 void
3558 BView::EndLineArray()
3559 {
3560 	if (fOwner == NULL)
3561 		return;
3562 
3563 	if (fCommArray == NULL)
3564 		debugger("Can't call EndLineArray before BeginLineArray");
3565 
3566 	_CheckLockAndSwitchCurrent();
3567 
3568 	fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY);
3569 	fOwner->fLink->Attach<int32>(fCommArray->count);
3570 	fOwner->fLink->Attach(fCommArray->array,
3571 		fCommArray->count * sizeof(ViewLineArrayInfo));
3572 
3573 	_FlushIfNotInTransaction();
3574 
3575 	_RemoveCommArray();
3576 }
3577 
3578 
3579 void
3580 BView::SetDiskMode(char* filename, long offset)
3581 {
3582 	// TODO: implement
3583 	// One BeBook version has this to say about SetDiskMode():
3584 	//
3585 	// "Begins recording a picture to the file with the given filename
3586 	// at the given offset. Subsequent drawing commands sent to the view
3587 	// will be written to the file until EndPicture() is called. The
3588 	// stored commands may be played from the file with DrawPicture()."
3589 }
3590 
3591 
3592 void
3593 BView::BeginPicture(BPicture* picture)
3594 {
3595 	if (_CheckOwnerLockAndSwitchCurrent()
3596 		&& picture && picture->fUsurped == NULL) {
3597 		picture->Usurp(fCurrentPicture);
3598 		fCurrentPicture = picture;
3599 
3600 		fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE);
3601 	}
3602 }
3603 
3604 
3605 void
3606 BView::AppendToPicture(BPicture* picture)
3607 {
3608 	_CheckLockAndSwitchCurrent();
3609 
3610 	if (picture && picture->fUsurped == NULL) {
3611 		int32 token = picture->Token();
3612 
3613 		if (token == -1) {
3614 			BeginPicture(picture);
3615 		} else {
3616 			picture->SetToken(-1);
3617 			picture->Usurp(fCurrentPicture);
3618 			fCurrentPicture = picture;
3619 			fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE);
3620 			fOwner->fLink->Attach<int32>(token);
3621 		}
3622 	}
3623 }
3624 
3625 
3626 BPicture*
3627 BView::EndPicture()
3628 {
3629 	if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) {
3630 		int32 token;
3631 
3632 		fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE);
3633 
3634 		int32 code;
3635 		if (fOwner->fLink->FlushWithReply(code) == B_OK
3636 			&& code == B_OK
3637 			&& fOwner->fLink->Read<int32>(&token) == B_OK) {
3638 			BPicture* picture = fCurrentPicture;
3639 			fCurrentPicture = picture->StepDown();
3640 			picture->SetToken(token);
3641 
3642 			// TODO do this more efficient e.g. use a shared area and let the
3643 			// client write into it
3644 			picture->_Download();
3645 			return picture;
3646 		}
3647 	}
3648 
3649 	return NULL;
3650 }
3651 
3652 
3653 void
3654 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
3655 	uint32 followFlags, uint32 options)
3656 {
3657 	_SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options);
3658 }
3659 
3660 
3661 void
3662 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options)
3663 {
3664 	BRect rect;
3665  	if (bitmap)
3666 		rect = bitmap->Bounds();
3667 
3668  	rect.OffsetTo(B_ORIGIN);
3669 
3670 	_SetViewBitmap(bitmap, rect, rect, followFlags, options);
3671 }
3672 
3673 
3674 void
3675 BView::ClearViewBitmap()
3676 {
3677 	_SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3678 }
3679 
3680 
3681 status_t
3682 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect,
3683 	rgb_color* colorKey, uint32 followFlags, uint32 options)
3684 {
3685 	if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0)
3686 		return B_BAD_VALUE;
3687 
3688 	status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags,
3689 		options | AS_REQUEST_COLOR_KEY);
3690 	if (status == B_OK) {
3691 		// read the color that will be treated as transparent
3692 		fOwner->fLink->Read<rgb_color>(colorKey);
3693 	}
3694 
3695 	return status;
3696 }
3697 
3698 
3699 status_t
3700 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey,
3701 	uint32 followFlags, uint32 options)
3702 {
3703 	if (overlay == NULL)
3704 		return B_BAD_VALUE;
3705 
3706 	BRect rect = overlay->Bounds();
3707  	rect.OffsetTo(B_ORIGIN);
3708 
3709 	return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options);
3710 }
3711 
3712 
3713 void
3714 BView::ClearViewOverlay()
3715 {
3716 	_SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3717 }
3718 
3719 
3720 void
3721 BView::CopyBits(BRect src, BRect dst)
3722 {
3723 	if (fOwner == NULL)
3724 		return;
3725 
3726 	if (!src.IsValid() || !dst.IsValid())
3727 		return;
3728 
3729 	_CheckLockAndSwitchCurrent();
3730 
3731 	fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS);
3732 	fOwner->fLink->Attach<BRect>(src);
3733 	fOwner->fLink->Attach<BRect>(dst);
3734 
3735 	_FlushIfNotInTransaction();
3736 }
3737 
3738 
3739 void
3740 BView::DrawPicture(const BPicture* picture)
3741 {
3742 	if (picture == NULL)
3743 		return;
3744 
3745 	DrawPictureAsync(picture, PenLocation());
3746 	Sync();
3747 }
3748 
3749 
3750 void
3751 BView::DrawPicture(const BPicture* picture, BPoint where)
3752 {
3753 	if (picture == NULL)
3754 		return;
3755 
3756 	DrawPictureAsync(picture, where);
3757 	Sync();
3758 }
3759 
3760 
3761 void
3762 BView::DrawPicture(const char* filename, long offset, BPoint where)
3763 {
3764 	if (!filename)
3765 		return;
3766 
3767 	DrawPictureAsync(filename, offset, where);
3768 	Sync();
3769 }
3770 
3771 
3772 void
3773 BView::DrawPictureAsync(const BPicture* picture)
3774 {
3775 	if (picture == NULL)
3776 		return;
3777 
3778 	DrawPictureAsync(picture, PenLocation());
3779 }
3780 
3781 
3782 void
3783 BView::DrawPictureAsync(const BPicture* picture, BPoint where)
3784 {
3785 	if (picture == NULL)
3786 		return;
3787 
3788 	if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) {
3789 		fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE);
3790 		fOwner->fLink->Attach<int32>(picture->Token());
3791 		fOwner->fLink->Attach<BPoint>(where);
3792 
3793 		_FlushIfNotInTransaction();
3794 	}
3795 }
3796 
3797 
3798 void
3799 BView::DrawPictureAsync(const char* filename, long offset, BPoint where)
3800 {
3801 	if (!filename)
3802 		return;
3803 
3804 	// TODO: Test
3805 	BFile file(filename, B_READ_ONLY);
3806 	if (file.InitCheck() < B_OK)
3807 		return;
3808 
3809 	file.Seek(offset, SEEK_SET);
3810 
3811 	BPicture picture;
3812 	if (picture.Unflatten(&file) < B_OK)
3813 		return;
3814 
3815 	DrawPictureAsync(&picture, where);
3816 }
3817 
3818 
3819 void
3820 BView::Invalidate(BRect invalRect)
3821 {
3822 	if (fOwner == NULL)
3823 		return;
3824 
3825 	// NOTE: This rounding of the invalid rect is to stay compatible with BeOS.
3826 	// On the server side, the invalid rect will be converted to a BRegion,
3827 	// which rounds in a different manner, so that it really includes the
3828 	// fractional coordinates of a BRect (ie ceilf(rect.right) &
3829 	// ceilf(rect.bottom)), which is also what BeOS does. So we have to do the
3830 	// different rounding here to stay compatible in both ways.
3831 	invalRect.left = (int)invalRect.left;
3832 	invalRect.top = (int)invalRect.top;
3833 	invalRect.right = (int)invalRect.right;
3834 	invalRect.bottom = (int)invalRect.bottom;
3835 	if (!invalRect.IsValid())
3836 		return;
3837 
3838 	_CheckLockAndSwitchCurrent();
3839 
3840 	fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT);
3841 	fOwner->fLink->Attach<BRect>(invalRect);
3842 
3843 // TODO: determine why this check isn't working correctly.
3844 #if 0
3845 	if (!fOwner->fUpdateRequested) {
3846 		fOwner->fLink->Flush();
3847 		fOwner->fUpdateRequested = true;
3848 	}
3849 #else
3850 	fOwner->fLink->Flush();
3851 #endif
3852 }
3853 
3854 
3855 void
3856 BView::Invalidate(const BRegion* region)
3857 {
3858 	if (region == NULL || fOwner == NULL)
3859 		return;
3860 
3861 	_CheckLockAndSwitchCurrent();
3862 
3863 	fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION);
3864 	fOwner->fLink->AttachRegion(*region);
3865 
3866 // TODO: See above.
3867 #if 0
3868 	if (!fOwner->fUpdateRequested) {
3869 		fOwner->fLink->Flush();
3870 		fOwner->fUpdateRequested = true;
3871 	}
3872 #else
3873 	fOwner->fLink->Flush();
3874 #endif
3875 }
3876 
3877 
3878 void
3879 BView::Invalidate()
3880 {
3881 	Invalidate(Bounds());
3882 }
3883 
3884 
3885 void
3886 BView::InvertRect(BRect rect)
3887 {
3888 	if (fOwner) {
3889 		_CheckLockAndSwitchCurrent();
3890 
3891 		fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT);
3892 		fOwner->fLink->Attach<BRect>(rect);
3893 
3894 		_FlushIfNotInTransaction();
3895 	}
3896 }
3897 
3898 
3899 //	#pragma mark - View Hierarchy Functions
3900 
3901 
3902 void
3903 BView::AddChild(BView* child, BView* before)
3904 {
3905 	STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n",
3906  		this->Name(),
3907  		child != NULL && child->Name() ? child->Name() : "NULL",
3908  		before != NULL && before->Name() ? before->Name() : "NULL"));
3909 
3910 	if (!_AddChild(child, before))
3911 		return;
3912 
3913 	if (fLayoutData->fLayout)
3914 		fLayoutData->fLayout->AddView(child);
3915 }
3916 
3917 
3918 bool
3919 BView::AddChild(BLayoutItem* child)
3920 {
3921 	if (!fLayoutData->fLayout)
3922 		return false;
3923 	return fLayoutData->fLayout->AddItem(child);
3924 }
3925 
3926 
3927 bool
3928 BView::_AddChild(BView* child, BView* before)
3929 {
3930 	if (!child)
3931 		return false;
3932 
3933 	if (child->fParent != NULL) {
3934 		debugger("AddChild failed - the view already has a parent.");
3935 		return false;
3936 	}
3937 
3938 	bool lockedOwner = false;
3939 	if (fOwner && !fOwner->IsLocked()) {
3940 		fOwner->Lock();
3941 		lockedOwner = true;
3942 	}
3943 
3944 	if (!_AddChildToList(child, before)) {
3945 		debugger("AddChild failed!");
3946 		if (lockedOwner)
3947 			fOwner->Unlock();
3948 		return false;
3949 	}
3950 
3951 	if (fOwner) {
3952 		_CheckLockAndSwitchCurrent();
3953 
3954 		child->_SetOwner(fOwner);
3955 		child->_CreateSelf();
3956 		child->_Attach();
3957 
3958 		if (lockedOwner)
3959 			fOwner->Unlock();
3960 	}
3961 
3962 	InvalidateLayout();
3963 
3964 	return true;
3965 }
3966 
3967 
3968 bool
3969 BView::RemoveChild(BView* child)
3970 {
3971 	STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
3972 
3973 	if (!child)
3974 		return false;
3975 
3976 	if (child->fParent != this)
3977 		return false;
3978 
3979 	return child->RemoveSelf();
3980 }
3981 
3982 
3983 int32
3984 BView::CountChildren() const
3985 {
3986 	_CheckLock();
3987 
3988 	uint32 count = 0;
3989 	BView* child = fFirstChild;
3990 
3991 	while (child != NULL) {
3992 		count++;
3993 		child = child->fNextSibling;
3994 	}
3995 
3996 	return count;
3997 }
3998 
3999 
4000 BView*
4001 BView::ChildAt(int32 index) const
4002 {
4003 	_CheckLock();
4004 
4005 	BView* child = fFirstChild;
4006 	while (child != NULL && index-- > 0) {
4007 		child = child->fNextSibling;
4008 	}
4009 
4010 	return child;
4011 }
4012 
4013 
4014 BView*
4015 BView::NextSibling() const
4016 {
4017 	return fNextSibling;
4018 }
4019 
4020 
4021 BView*
4022 BView::PreviousSibling() const
4023 {
4024 	return fPreviousSibling;
4025 }
4026 
4027 
4028 bool
4029 BView::RemoveSelf()
4030 {
4031 	if (fParent && fParent->fLayoutData->fLayout) {
4032 		int32 itemsRemaining = fLayoutData->fLayoutItems.CountItems();
4033 		while (itemsRemaining-- > 0) {
4034 			BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(0);
4035 				// always remove item at index 0, since items are shuffled
4036 				// downwards by BObjectList
4037 			item->Layout()->RemoveItem(item);
4038 				// removes item from fLayoutItems list
4039 			delete item;
4040 		}
4041 	}
4042 
4043 	return _RemoveSelf();
4044 }
4045 
4046 
4047 bool
4048 BView::_RemoveSelf()
4049 {
4050 	STRACE(("BView(%s)::_RemoveSelf()\n", Name()));
4051 
4052 	// Remove this child from its parent
4053 
4054 	BWindow* owner = fOwner;
4055 	_CheckLock();
4056 
4057 	if (owner != NULL) {
4058 		_UpdateStateForRemove();
4059 		_Detach();
4060 	}
4061 
4062 	BView* parent = fParent;
4063 	if (!parent || !parent->_RemoveChildFromList(this))
4064 		return false;
4065 
4066 	if (owner != NULL && !fTopLevelView) {
4067 		// the top level view is deleted by the app_server automatically
4068 		owner->fLink->StartMessage(AS_VIEW_DELETE);
4069 		owner->fLink->Attach<int32>(_get_object_token_(this));
4070 	}
4071 
4072 	parent->InvalidateLayout();
4073 
4074 	STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name()));
4075 
4076 	return true;
4077 }
4078 
4079 
4080 BView*
4081 BView::Parent() const
4082 {
4083 	if (fParent && fParent->fTopLevelView)
4084 		return NULL;
4085 
4086 	return fParent;
4087 }
4088 
4089 
4090 BView*
4091 BView::FindView(const char* name) const
4092 {
4093 	if (name == NULL)
4094 		return NULL;
4095 
4096 	if (Name() != NULL && !strcmp(Name(), name))
4097 		return const_cast<BView*>(this);
4098 
4099 	BView* child = fFirstChild;
4100 	while (child != NULL) {
4101 		BView* view = child->FindView(name);
4102 		if (view != NULL)
4103 			return view;
4104 
4105 		child = child->fNextSibling;
4106 	}
4107 
4108 	return NULL;
4109 }
4110 
4111 
4112 void
4113 BView::MoveBy(float deltaX, float deltaY)
4114 {
4115 	MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY));
4116 }
4117 
4118 
4119 void
4120 BView::MoveTo(BPoint where)
4121 {
4122 	MoveTo(where.x, where.y);
4123 }
4124 
4125 
4126 void
4127 BView::MoveTo(float x, float y)
4128 {
4129 	if (x == fParentOffset.x && y == fParentOffset.y)
4130 		return;
4131 
4132 	// BeBook says we should do this. And it makes sense.
4133 	x = roundf(x);
4134 	y = roundf(y);
4135 
4136 	if (fOwner) {
4137 		_CheckLockAndSwitchCurrent();
4138 		fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO);
4139 		fOwner->fLink->Attach<float>(x);
4140 		fOwner->fLink->Attach<float>(y);
4141 
4142 //		fState->valid_flags |= B_VIEW_FRAME_BIT;
4143 
4144 		_FlushIfNotInTransaction();
4145 	}
4146 
4147 	_MoveTo((int32)x, (int32)y);
4148 }
4149 
4150 
4151 void
4152 BView::ResizeBy(float deltaWidth, float deltaHeight)
4153 {
4154 	// BeBook says we should do this. And it makes sense.
4155 	deltaWidth = roundf(deltaWidth);
4156 	deltaHeight = roundf(deltaHeight);
4157 
4158 	if (deltaWidth == 0 && deltaHeight == 0)
4159 		return;
4160 
4161 	if (fOwner) {
4162 		_CheckLockAndSwitchCurrent();
4163 		fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO);
4164 
4165 		fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth);
4166 		fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight);
4167 
4168 //		fState->valid_flags |= B_VIEW_FRAME_BIT;
4169 
4170 		_FlushIfNotInTransaction();
4171 	}
4172 
4173 	_ResizeBy((int32)deltaWidth, (int32)deltaHeight);
4174 }
4175 
4176 
4177 void
4178 BView::ResizeTo(float width, float height)
4179 {
4180 	ResizeBy(width - fBounds.Width(), height - fBounds.Height());
4181 }
4182 
4183 
4184 void
4185 BView::ResizeTo(BSize size)
4186 {
4187 	ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height());
4188 }
4189 
4190 
4191 //	#pragma mark - Inherited Methods (from BHandler)
4192 
4193 
4194 status_t
4195 BView::GetSupportedSuites(BMessage* data)
4196 {
4197 	if (data == NULL)
4198 		return B_BAD_VALUE;
4199 
4200 	status_t status = data->AddString("suites", "suite/vnd.Be-view");
4201 	BPropertyInfo propertyInfo(sViewPropInfo);
4202 	if (status == B_OK)
4203 		status = data->AddFlat("messages", &propertyInfo);
4204 	if (status == B_OK)
4205 		return BHandler::GetSupportedSuites(data);
4206 	return status;
4207 }
4208 
4209 
4210 BHandler*
4211 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
4212 	int32 what, const char* property)
4213 {
4214 	if (message->what == B_WINDOW_MOVE_BY
4215 		|| message->what == B_WINDOW_MOVE_TO) {
4216 		return this;
4217 	}
4218 
4219 	BPropertyInfo propertyInfo(sViewPropInfo);
4220 	status_t err = B_BAD_SCRIPT_SYNTAX;
4221 	BMessage replyMsg(B_REPLY);
4222 
4223 	switch (propertyInfo.FindMatch(message, index, specifier, what, property)) {
4224 		case 0:
4225 		case 1:
4226 		case 3:
4227 			return this;
4228 
4229 		case 2:
4230 			if (fShelf) {
4231 				message->PopSpecifier();
4232 				return fShelf;
4233 			}
4234 
4235 			err = B_NAME_NOT_FOUND;
4236 			replyMsg.AddString("message", "This window doesn't have a shelf");
4237 			break;
4238 
4239 		case 4:
4240 		{
4241 			if (!fFirstChild) {
4242 				err = B_NAME_NOT_FOUND;
4243 				replyMsg.AddString("message", "This window doesn't have "
4244 					"children.");
4245 				break;
4246 			}
4247 			BView* child = NULL;
4248 			switch (what) {
4249 				case B_INDEX_SPECIFIER:
4250 				{
4251 					int32 index;
4252 					err = specifier->FindInt32("index", &index);
4253 					if (err == B_OK)
4254 						child = ChildAt(index);
4255 					break;
4256 				}
4257 				case B_REVERSE_INDEX_SPECIFIER:
4258 				{
4259 					int32 rindex;
4260 					err = specifier->FindInt32("index", &rindex);
4261 					if (err == B_OK)
4262 						child = ChildAt(CountChildren() - rindex);
4263 					break;
4264 				}
4265 				case B_NAME_SPECIFIER:
4266 				{
4267 					const char* name;
4268 					err = specifier->FindString("name", &name);
4269 					if (err == B_OK)
4270 						child = FindView(name);
4271 					break;
4272 				}
4273 			}
4274 
4275 			if (child != NULL) {
4276 				message->PopSpecifier();
4277 				return child;
4278 			}
4279 
4280 			if (err == B_OK)
4281 				err = B_BAD_INDEX;
4282 
4283 			replyMsg.AddString("message",
4284 				"Cannot find view at/with specified index/name.");
4285 			break;
4286 		}
4287 
4288 		default:
4289 			return BHandler::ResolveSpecifier(message, index, specifier, what,
4290 				property);
4291 	}
4292 
4293 	if (err < B_OK) {
4294 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4295 
4296 		if (err == B_BAD_SCRIPT_SYNTAX)
4297 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
4298 		else
4299 			replyMsg.AddString("message", strerror(err));
4300 	}
4301 
4302 	replyMsg.AddInt32("error", err);
4303 	message->SendReply(&replyMsg);
4304 	return NULL;
4305 }
4306 
4307 
4308 void
4309 BView::MessageReceived(BMessage* message)
4310 {
4311 	if (!message->HasSpecifiers()) {
4312 		switch (message->what) {
4313 			case B_VIEW_RESIZED:
4314 				// By the time the message arrives, the bounds may have
4315 				// changed already, that's why we don't use the values
4316 				// in the message itself.
4317 				FrameResized(fBounds.Width(), fBounds.Height());
4318 				break;
4319 
4320 			case B_VIEW_MOVED:
4321 				FrameMoved(fParentOffset);
4322 				break;
4323 
4324 			case B_MOUSE_IDLE:
4325 			{
4326 				BPoint where;
4327 				if (message->FindPoint("be:view_where", &where) != B_OK)
4328 					break;
4329 
4330 				BToolTip* tip;
4331 				if (GetToolTipAt(where, &tip))
4332 					ShowToolTip(tip);
4333 				else
4334 					BHandler::MessageReceived(message);
4335 				break;
4336 			}
4337 
4338 			case B_MOUSE_WHEEL_CHANGED:
4339 			{
4340 				BScrollBar* horizontal = ScrollBar(B_HORIZONTAL);
4341 				BScrollBar* vertical = ScrollBar(B_VERTICAL);
4342 				if (horizontal == NULL && vertical == NULL) {
4343 					// Pass the message to the next handler
4344 					BHandler::MessageReceived(message);
4345 					break;
4346 				}
4347 
4348 				float deltaX = 0.0f, deltaY = 0.0f;
4349 				if (horizontal != NULL)
4350 					message->FindFloat("be:wheel_delta_x", &deltaX);
4351 				if (vertical != NULL)
4352 					message->FindFloat("be:wheel_delta_y", &deltaY);
4353 
4354 				if (deltaX == 0.0f && deltaY == 0.0f)
4355 					break;
4356 
4357 				if (horizontal != NULL) {
4358 					ScrollWithMouseWheelDelta(horizontal, deltaX);
4359 				}
4360 
4361 				if (vertical != NULL) {
4362 					ScrollWithMouseWheelDelta(vertical, deltaY);
4363 				}
4364 				break;
4365 			}
4366 
4367 			default:
4368 				BHandler::MessageReceived(message);
4369 				break;
4370 		}
4371 
4372 		return;
4373 	}
4374 
4375 	// Scripting message
4376 
4377 	BMessage replyMsg(B_REPLY);
4378 	status_t err = B_BAD_SCRIPT_SYNTAX;
4379 	int32 index;
4380 	BMessage specifier;
4381 	int32 what;
4382 	const char* property;
4383 
4384 	if (message->GetCurrentSpecifier(&index, &specifier, &what, &property)
4385 			!= B_OK) {
4386 		return BHandler::MessageReceived(message);
4387 	}
4388 
4389 	BPropertyInfo propertyInfo(sViewPropInfo);
4390 	switch (propertyInfo.FindMatch(message, index, &specifier, what,
4391 			property)) {
4392 		case 0:
4393 			if (message->what == B_GET_PROPERTY) {
4394 				err = replyMsg.AddRect("result", Frame());
4395 			} else if (message->what == B_SET_PROPERTY) {
4396 				BRect newFrame;
4397 				err = message->FindRect("data", &newFrame);
4398 				if (err == B_OK) {
4399 					MoveTo(newFrame.LeftTop());
4400 					ResizeTo(newFrame.Width(), newFrame.Height());
4401 				}
4402 			}
4403 			break;
4404 		case 1:
4405 			if (message->what == B_GET_PROPERTY) {
4406 				err = replyMsg.AddBool("result", IsHidden());
4407 			} else if (message->what == B_SET_PROPERTY) {
4408 				bool newHiddenState;
4409 				err = message->FindBool("data", &newHiddenState);
4410 				if (err == B_OK) {
4411 					if (newHiddenState == true)
4412 						Hide();
4413 					else
4414 						Show();
4415 				}
4416 			}
4417 			break;
4418 		case 3:
4419 			err = replyMsg.AddInt32("result", CountChildren());
4420 			break;
4421 		default:
4422 			return BHandler::MessageReceived(message);
4423 	}
4424 
4425 	if (err != B_OK) {
4426 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4427 
4428 		if (err == B_BAD_SCRIPT_SYNTAX)
4429 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
4430 		else
4431 			replyMsg.AddString("message", strerror(err));
4432 
4433 		replyMsg.AddInt32("error", err);
4434 	}
4435 
4436 	message->SendReply(&replyMsg);
4437 }
4438 
4439 
4440 status_t
4441 BView::Perform(perform_code code, void* _data)
4442 {
4443 	switch (code) {
4444 		case PERFORM_CODE_MIN_SIZE:
4445 			((perform_data_min_size*)_data)->return_value
4446 				= BView::MinSize();
4447 			return B_OK;
4448 		case PERFORM_CODE_MAX_SIZE:
4449 			((perform_data_max_size*)_data)->return_value
4450 				= BView::MaxSize();
4451 			return B_OK;
4452 		case PERFORM_CODE_PREFERRED_SIZE:
4453 			((perform_data_preferred_size*)_data)->return_value
4454 				= BView::PreferredSize();
4455 			return B_OK;
4456 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
4457 			((perform_data_layout_alignment*)_data)->return_value
4458 				= BView::LayoutAlignment();
4459 			return B_OK;
4460 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
4461 			((perform_data_has_height_for_width*)_data)->return_value
4462 				= BView::HasHeightForWidth();
4463 			return B_OK;
4464 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
4465 		{
4466 			perform_data_get_height_for_width* data
4467 				= (perform_data_get_height_for_width*)_data;
4468 			BView::GetHeightForWidth(data->width, &data->min, &data->max,
4469 				&data->preferred);
4470 			return B_OK;
4471 		}
4472 		case PERFORM_CODE_SET_LAYOUT:
4473 		{
4474 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
4475 			BView::SetLayout(data->layout);
4476 			return B_OK;
4477 		}
4478 		case PERFORM_CODE_LAYOUT_INVALIDATED:
4479 		{
4480 			perform_data_layout_invalidated* data
4481 				= (perform_data_layout_invalidated*)_data;
4482 			BView::LayoutInvalidated(data->descendants);
4483 			return B_OK;
4484 		}
4485 		case PERFORM_CODE_DO_LAYOUT:
4486 		{
4487 			BView::DoLayout();
4488 			return B_OK;
4489 		}
4490 		case PERFORM_CODE_LAYOUT_CHANGED:
4491 		{
4492 			BView::LayoutChanged();
4493 			return B_OK;
4494 		}
4495 		case PERFORM_CODE_GET_TOOL_TIP_AT:
4496 		{
4497 			perform_data_get_tool_tip_at* data
4498 				= (perform_data_get_tool_tip_at*)_data;
4499 			data->return_value
4500 				= BView::GetToolTipAt(data->point, data->tool_tip);
4501 			return B_OK;
4502 		}
4503 		case PERFORM_CODE_ALL_UNARCHIVED:
4504 		{
4505 			perform_data_all_unarchived* data =
4506 				(perform_data_all_unarchived*)_data;
4507 
4508 			data->return_value = BView::AllUnarchived(data->archive);
4509 			return B_OK;
4510 		}
4511 		case PERFORM_CODE_ALL_ARCHIVED:
4512 		{
4513 			perform_data_all_archived* data =
4514 				(perform_data_all_archived*)_data;
4515 
4516 			data->return_value = BView::AllArchived(data->archive);
4517 			return B_OK;
4518 		}
4519 	}
4520 
4521 	return BHandler::Perform(code, _data);
4522 }
4523 
4524 
4525 // #pragma mark - Layout Functions
4526 
4527 
4528 BSize
4529 BView::MinSize()
4530 {
4531 	// TODO: make sure this works correctly when some methods are overridden
4532 	float width, height;
4533 	GetPreferredSize(&width, &height);
4534 
4535 	return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
4536 		(fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
4537 			: BSize(width, height)));
4538 }
4539 
4540 
4541 BSize
4542 BView::MaxSize()
4543 {
4544 	return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
4545 		(fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
4546 			: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
4547 }
4548 
4549 
4550 BSize
4551 BView::PreferredSize()
4552 {
4553 	// TODO: make sure this works correctly when some methods are overridden
4554 	float width, height;
4555 	GetPreferredSize(&width, &height);
4556 
4557 	return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
4558 		(fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
4559 			: BSize(width, height)));
4560 }
4561 
4562 
4563 BAlignment
4564 BView::LayoutAlignment()
4565 {
4566 	return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
4567 		(fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
4568 			: BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
4569 }
4570 
4571 
4572 void
4573 BView::SetExplicitMinSize(BSize size)
4574 {
4575 	fLayoutData->fMinSize = size;
4576 	InvalidateLayout();
4577 }
4578 
4579 
4580 void
4581 BView::SetExplicitMaxSize(BSize size)
4582 {
4583 	fLayoutData->fMaxSize = size;
4584 	InvalidateLayout();
4585 }
4586 
4587 
4588 void
4589 BView::SetExplicitPreferredSize(BSize size)
4590 {
4591 	fLayoutData->fPreferredSize = size;
4592 	InvalidateLayout();
4593 }
4594 
4595 
4596 void
4597 BView::SetExplicitSize(BSize size)
4598 {
4599 	fLayoutData->fMinSize = size;
4600 	fLayoutData->fMaxSize = size;
4601 	fLayoutData->fPreferredSize = size;
4602 	InvalidateLayout();
4603 }
4604 
4605 
4606 void
4607 BView::SetExplicitAlignment(BAlignment alignment)
4608 {
4609 	fLayoutData->fAlignment = alignment;
4610 	InvalidateLayout();
4611 }
4612 
4613 
4614 BSize
4615 BView::ExplicitMinSize() const
4616 {
4617 	return fLayoutData->fMinSize;
4618 }
4619 
4620 
4621 BSize
4622 BView::ExplicitMaxSize() const
4623 {
4624 	return fLayoutData->fMaxSize;
4625 }
4626 
4627 
4628 BSize
4629 BView::ExplicitPreferredSize() const
4630 {
4631 	return fLayoutData->fPreferredSize;
4632 }
4633 
4634 
4635 BAlignment
4636 BView::ExplicitAlignment() const
4637 {
4638 	return fLayoutData->fAlignment;
4639 }
4640 
4641 
4642 bool
4643 BView::HasHeightForWidth()
4644 {
4645 	return (fLayoutData->fLayout
4646 		? fLayoutData->fLayout->HasHeightForWidth() : false);
4647 }
4648 
4649 
4650 void
4651 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
4652 {
4653 	if (fLayoutData->fLayout)
4654 		fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
4655 }
4656 
4657 
4658 void
4659 BView::SetLayout(BLayout* layout)
4660 {
4661 	if (layout == fLayoutData->fLayout)
4662 		return;
4663 
4664 	if (layout && layout->Layout())
4665 		debugger("BView::SetLayout() failed, layout is already in use.");
4666 
4667 	fFlags |= B_SUPPORTS_LAYOUT;
4668 
4669 	// unset and delete the old layout
4670 	if (fLayoutData->fLayout) {
4671 		fLayoutData->fLayout->SetOwner(NULL);
4672 		delete fLayoutData->fLayout;
4673 	}
4674 
4675 	fLayoutData->fLayout = layout;
4676 
4677 	if (fLayoutData->fLayout) {
4678 		fLayoutData->fLayout->SetOwner(this);
4679 
4680 		// add all children
4681 		int count = CountChildren();
4682 		for (int i = 0; i < count; i++)
4683 			fLayoutData->fLayout->AddView(ChildAt(i));
4684 	}
4685 
4686 	InvalidateLayout();
4687 }
4688 
4689 
4690 BLayout*
4691 BView::GetLayout() const
4692 {
4693 	return fLayoutData->fLayout;
4694 }
4695 
4696 
4697 void
4698 BView::InvalidateLayout(bool descendants)
4699 {
4700 	// printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
4701 	//	this, descendants, fLayoutData->fLayoutValid,
4702 	//	fLayoutData->fLayoutInProgress);
4703 
4704 	if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
4705  			|| fLayoutData->fLayoutInvalidationDisabled > 0) {
4706 		return;
4707 	}
4708 
4709 	fLayoutData->fLayoutValid = false;
4710 	fLayoutData->fMinMaxValid = false;
4711 	LayoutInvalidated(descendants);
4712 
4713 	if (descendants) {
4714 		for (BView* child = fFirstChild;
4715 			child; child = child->fNextSibling) {
4716 			child->InvalidateLayout(descendants);
4717 		}
4718 	}
4719 
4720 	if (fLayoutData->fLayout)
4721 		fLayoutData->fLayout->InvalidateLayout(descendants);
4722 	else
4723 		_InvalidateParentLayout();
4724 
4725 	if (fTopLevelView && fOwner)
4726 		fOwner->PostMessage(B_LAYOUT_WINDOW);
4727 }
4728 
4729 
4730 void
4731 BView::EnableLayoutInvalidation()
4732 {
4733 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4734 		fLayoutData->fLayoutInvalidationDisabled--;
4735 }
4736 
4737 
4738 void
4739 BView::DisableLayoutInvalidation()
4740 {
4741 	fLayoutData->fLayoutInvalidationDisabled++;
4742 }
4743 
4744 
4745 bool
4746 BView::IsLayoutInvalidationDisabled()
4747 {
4748 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4749 		return true;
4750 	return false;
4751 }
4752 
4753 
4754 bool
4755 BView::IsLayoutValid() const
4756 {
4757 	return fLayoutData->fLayoutValid;
4758 }
4759 
4760 
4761 void
4762 BView::ResetLayoutInvalidation()
4763 {
4764 	fLayoutData->fMinMaxValid = true;
4765 }
4766 
4767 
4768 BLayoutContext*
4769 BView::LayoutContext() const
4770 {
4771 	return fLayoutData->fLayoutContext;
4772 }
4773 
4774 
4775 void
4776 BView::Layout(bool force)
4777 {
4778 	BLayoutContext context;
4779 	_Layout(force, &context);
4780 }
4781 
4782 
4783 void
4784 BView::Relayout()
4785 {
4786 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
4787 		fLayoutData->fNeedsRelayout = true;
4788 		if (fLayoutData->fLayout)
4789 			fLayoutData->fLayout->RequireLayout();
4790 
4791 		// Layout() is recursive, that is if the parent view is currently laid
4792 		// out, we don't call layout() on this view, but wait for the parent's
4793 		// Layout() to do that for us.
4794 		if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
4795 			Layout(false);
4796 	}
4797 }
4798 
4799 
4800 void
4801 BView::LayoutInvalidated(bool descendants)
4802 {
4803 	// hook method
4804 }
4805 
4806 
4807 void
4808 BView::DoLayout()
4809 {
4810 	if (fLayoutData->fLayout)
4811 		fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
4812 }
4813 
4814 
4815 void
4816 BView::SetToolTip(const char* text)
4817 {
4818 	if (text == NULL || text[0] == '\0') {
4819 		SetToolTip((BToolTip*)NULL);
4820 		return;
4821 	}
4822 
4823 	if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
4824 		tip->SetText(text);
4825 	else
4826 		SetToolTip(new BTextToolTip(text));
4827 }
4828 
4829 
4830 void
4831 BView::SetToolTip(BToolTip* tip)
4832 {
4833 	if (fToolTip == tip)
4834 		return;
4835 	else if (tip == NULL)
4836 		HideToolTip();
4837 
4838 	if (fToolTip != NULL)
4839 		fToolTip->ReleaseReference();
4840 
4841 	fToolTip = tip;
4842 
4843 	if (fToolTip != NULL)
4844 		fToolTip->AcquireReference();
4845 }
4846 
4847 
4848 BToolTip*
4849 BView::ToolTip() const
4850 {
4851 	return fToolTip;
4852 }
4853 
4854 
4855 void
4856 BView::ShowToolTip(BToolTip* tip)
4857 {
4858 	if (tip == NULL)
4859 		return;
4860 
4861 	BPoint where;
4862 	GetMouse(&where, NULL, false);
4863 
4864 	BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
4865 }
4866 
4867 
4868 void
4869 BView::HideToolTip()
4870 {
4871 	BToolTipManager::Manager()->HideTip();
4872 }
4873 
4874 
4875 bool
4876 BView::GetToolTipAt(BPoint point, BToolTip** _tip)
4877 {
4878 	if (fToolTip != NULL) {
4879 		*_tip = fToolTip;
4880 		return true;
4881 	}
4882 
4883 	*_tip = NULL;
4884 	return false;
4885 }
4886 
4887 
4888 void
4889 BView::LayoutChanged()
4890 {
4891 	// hook method
4892 }
4893 
4894 
4895 void
4896 BView::_Layout(bool force, BLayoutContext* context)
4897 {
4898 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
4899 //printf("  fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
4900 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
4901 //fLayoutData->fLayoutInProgress);
4902 	if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
4903 		fLayoutData->fLayoutValid = false;
4904 
4905 		if (fLayoutData->fLayoutInProgress)
4906 			return;
4907 
4908 		BLayoutContext* oldContext = fLayoutData->fLayoutContext;
4909 		fLayoutData->fLayoutContext = context;
4910 
4911 		fLayoutData->fLayoutInProgress = true;
4912 		DoLayout();
4913 		fLayoutData->fLayoutInProgress = false;
4914 
4915 		fLayoutData->fLayoutValid = true;
4916 		fLayoutData->fMinMaxValid = true;
4917 		fLayoutData->fNeedsRelayout = false;
4918 
4919 		// layout children
4920 		for(BView* child = fFirstChild; child; child = child->fNextSibling) {
4921 			if (!child->IsHidden(child))
4922 				child->_Layout(force, context);
4923 		}
4924 
4925 		LayoutChanged();
4926 
4927 		fLayoutData->fLayoutContext = oldContext;
4928 
4929 		// invalidate the drawn content, if requested
4930 		if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
4931 			Invalidate();
4932 	}
4933 }
4934 
4935 
4936 void
4937 BView::_LayoutLeft(BLayout* deleted)
4938 {
4939 	// If our layout is added to another layout (via BLayout::AddItem())
4940 	// then we share ownership of our layout. In the event that our layout gets
4941 	// deleted by the layout it has been added to, this method is called so
4942 	// that we don't double-delete our layout.
4943 	if (fLayoutData->fLayout == deleted)
4944 		fLayoutData->fLayout = NULL;
4945 	InvalidateLayout();
4946 }
4947 
4948 
4949 void
4950 BView::_InvalidateParentLayout()
4951 {
4952 	if (!fParent)
4953 		return;
4954 
4955 	BLayout* layout = fLayoutData->fLayout;
4956 	BLayout* layoutParent = layout ? layout->Layout() : NULL;
4957 	if (layoutParent) {
4958 		layoutParent->InvalidateLayout();
4959 	} else if (fLayoutData->fLayoutItems.CountItems() > 0) {
4960 		int32 count = fLayoutData->fLayoutItems.CountItems();
4961 		for (int32 i = 0; i < count; i++) {
4962 			fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
4963 		}
4964 	} else {
4965 		fParent->InvalidateLayout();
4966 	}
4967 }
4968 
4969 
4970 //	#pragma mark - Private Functions
4971 
4972 
4973 void
4974 BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
4975 	uint32 flags)
4976 {
4977 	// Info: The name of the view is set by BHandler constructor
4978 
4979 	STRACE(("BView::_InitData: enter\n"));
4980 
4981 	// initialize members
4982 	if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
4983 		printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
4984 
4985 	// There are applications that swap the resize mask and the flags in the
4986 	// BView constructor. This does not cause problems under BeOS as it just
4987 	// ors the two fields to one 32bit flag.
4988 	// For now we do the same but print the above warning message.
4989 	// TODO: this should be removed at some point and the original
4990 	// version restored:
4991 	// fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
4992 	fFlags = resizingMode | flags;
4993 
4994 	// handle rounding
4995 	frame.left = roundf(frame.left);
4996 	frame.top = roundf(frame.top);
4997 	frame.right = roundf(frame.right);
4998 	frame.bottom = roundf(frame.bottom);
4999 
5000 	fParentOffset.Set(frame.left, frame.top);
5001 
5002 	fOwner = NULL;
5003 	fParent = NULL;
5004 	fNextSibling = NULL;
5005 	fPreviousSibling = NULL;
5006 	fFirstChild = NULL;
5007 
5008 	fShowLevel = 0;
5009 	fTopLevelView = false;
5010 
5011 	fCurrentPicture = NULL;
5012 	fCommArray = NULL;
5013 
5014 	fVerScroller = NULL;
5015 	fHorScroller = NULL;
5016 
5017 	fIsPrinting = false;
5018 	fAttached = false;
5019 
5020 	// TODO: Since we cannot communicate failure, we don't use std::nothrow here
5021 	// TODO: Maybe we could auto-delete those views on AddChild() instead?
5022 	fState = new BPrivate::ViewState;
5023 
5024 	fBounds = frame.OffsetToCopy(B_ORIGIN);
5025 	fShelf = NULL;
5026 
5027 	fEventMask = 0;
5028 	fEventOptions = 0;
5029 	fMouseEventOptions = 0;
5030 
5031 	fLayoutData = new LayoutData;
5032 
5033 	fToolTip = NULL;
5034 }
5035 
5036 
5037 void
5038 BView::_RemoveCommArray()
5039 {
5040 	if (fCommArray) {
5041 		delete [] fCommArray->array;
5042 		delete fCommArray;
5043 		fCommArray = NULL;
5044 	}
5045 }
5046 
5047 
5048 void
5049 BView::_SetOwner(BWindow* newOwner)
5050 {
5051 	if (!newOwner)
5052 		_RemoveCommArray();
5053 
5054 	if (fOwner != newOwner && fOwner) {
5055 		if (fOwner->fFocus == this)
5056 			MakeFocus(false);
5057 
5058 		if (fOwner->fLastMouseMovedView == this)
5059 			fOwner->fLastMouseMovedView = NULL;
5060 
5061 		fOwner->RemoveHandler(this);
5062 		if (fShelf)
5063 			fOwner->RemoveHandler(fShelf);
5064 	}
5065 
5066 	if (newOwner && newOwner != fOwner) {
5067 		newOwner->AddHandler(this);
5068 		if (fShelf)
5069 			newOwner->AddHandler(fShelf);
5070 
5071 		if (fTopLevelView)
5072 			SetNextHandler(newOwner);
5073 		else
5074 			SetNextHandler(fParent);
5075 	}
5076 
5077 	fOwner = newOwner;
5078 
5079 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5080 		child->_SetOwner(newOwner);
5081 }
5082 
5083 
5084 void
5085 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5086 {
5087 	if (!picture)
5088 		return;
5089 
5090 #if 1
5091 	// TODO: Move the implementation to the server!!!
5092 	// This implementation is pretty slow, since just creating an offscreen
5093 	// bitmap takes a lot of time. That's the main reason why it should be moved
5094 	// to the server.
5095 
5096 	// Here the idea is to get rid of the padding bytes in the bitmap,
5097 	// as padding complicates and slows down the iteration.
5098 	// TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned
5099 	// to a 4 byte boundary.
5100 	BRect bounds(Bounds());
5101 	if ((bounds.IntegerWidth() + 1) % 32) {
5102 		bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1)
5103 			* 32 - 1;
5104 	}
5105 
5106 	// TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work.
5107 	BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true);
5108 	if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) {
5109 		BView* view = new(std::nothrow) BView(bounds, "drawing view",
5110 			B_FOLLOW_NONE, 0);
5111 		if (view != NULL) {
5112 			bitmap->AddChild(view);
5113 			view->DrawPicture(picture, where);
5114 			view->Sync();
5115 		}
5116 		bitmap->Unlock();
5117 	}
5118 
5119 	BRegion region;
5120 	int32 width = bounds.IntegerWidth() + 1;
5121 	int32 height = bounds.IntegerHeight() + 1;
5122 	if (bitmap != NULL && bitmap->LockBits() == B_OK) {
5123 		uint32 bit = 0;
5124 		uint32* bits = (uint32*)bitmap->Bits();
5125 		clipping_rect rect;
5126 
5127 		// TODO: A possible optimization would be adding "spans" instead
5128 		// of 1x1 rects. That would probably help with very complex
5129 		// BPictures
5130 		for (int32 y = 0; y < height; y++) {
5131 			for (int32 x = 0; x < width; x++) {
5132 				bit = *bits++;
5133 				if (bit != 0xFFFFFFFF) {
5134 					rect.left = x;
5135 					rect.right = rect.left;
5136 					rect.top = rect.bottom = y;
5137 					region.Include(rect);
5138 				}
5139 			}
5140 		}
5141 		bitmap->UnlockBits();
5142 	}
5143 	delete bitmap;
5144 
5145 	if (invert) {
5146 		BRegion inverseRegion;
5147 		inverseRegion.Include(Bounds());
5148 		inverseRegion.Exclude(&region);
5149 		ConstrainClippingRegion(&inverseRegion);
5150 	} else
5151 		ConstrainClippingRegion(&region);
5152 #else
5153 	if (_CheckOwnerLockAndSwitchCurrent()) {
5154 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5155 		fOwner->fLink->Attach<int32>(picture->Token());
5156 		fOwner->fLink->Attach<BPoint>(where);
5157 		fOwner->fLink->Attach<bool>(invert);
5158 
5159 		// TODO: I think that "sync" means another thing here:
5160 		// the bebook, at least, says so.
5161 		if (sync)
5162 			fOwner->fLink->Flush();
5163 
5164 		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
5165 	}
5166 
5167 	fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
5168 #endif
5169 }
5170 
5171 
5172 bool
5173 BView::_RemoveChildFromList(BView* child)
5174 {
5175 	if (child->fParent != this)
5176 		return false;
5177 
5178 	if (fFirstChild == child) {
5179 		// it's the first view in the list
5180 		fFirstChild = child->fNextSibling;
5181 	} else {
5182 		// there must be a previous sibling
5183 		child->fPreviousSibling->fNextSibling = child->fNextSibling;
5184 	}
5185 
5186 	if (child->fNextSibling)
5187 		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
5188 
5189 	child->fParent = NULL;
5190 	child->fNextSibling = NULL;
5191 	child->fPreviousSibling = NULL;
5192 
5193 	return true;
5194 }
5195 
5196 
5197 bool
5198 BView::_AddChildToList(BView* child, BView* before)
5199 {
5200 	if (!child)
5201 		return false;
5202 	if (child->fParent != NULL) {
5203 		debugger("View already belongs to someone else");
5204 		return false;
5205 	}
5206 	if (before != NULL && before->fParent != this) {
5207 		debugger("Invalid before view");
5208 		return false;
5209 	}
5210 
5211 	if (before != NULL) {
5212 		// add view before this one
5213 		child->fNextSibling = before;
5214 		child->fPreviousSibling = before->fPreviousSibling;
5215 		if (child->fPreviousSibling != NULL)
5216 			child->fPreviousSibling->fNextSibling = child;
5217 
5218 		before->fPreviousSibling = child;
5219 		if (fFirstChild == before)
5220 			fFirstChild = child;
5221 	} else {
5222 		// add view to the end of the list
5223 		BView* last = fFirstChild;
5224 		while (last != NULL && last->fNextSibling != NULL) {
5225 			last = last->fNextSibling;
5226 		}
5227 
5228 		if (last != NULL) {
5229 			last->fNextSibling = child;
5230 			child->fPreviousSibling = last;
5231 		} else {
5232 			fFirstChild = child;
5233 			child->fPreviousSibling = NULL;
5234 		}
5235 
5236 		child->fNextSibling = NULL;
5237 	}
5238 
5239 	child->fParent = this;
5240 	return true;
5241 }
5242 
5243 
5244 /*!	\brief Creates the server counterpart of this view.
5245 	This is only done for views that are part of the view hierarchy, ie. when
5246 	they are attached to a window.
5247 	RemoveSelf() deletes the server object again.
5248 */
5249 bool
5250 BView::_CreateSelf()
5251 {
5252 	// AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
5253 	// current view mechanism via _CheckLockAndSwitchCurrent() - the token
5254 	// of the view and its parent are both send to the server.
5255 
5256 	if (fTopLevelView)
5257 		fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
5258 	else
5259  		fOwner->fLink->StartMessage(AS_VIEW_CREATE);
5260 
5261 	fOwner->fLink->Attach<int32>(_get_object_token_(this));
5262 	fOwner->fLink->AttachString(Name());
5263 	fOwner->fLink->Attach<BRect>(Frame());
5264 	fOwner->fLink->Attach<BPoint>(LeftTop());
5265 	fOwner->fLink->Attach<uint32>(ResizingMode());
5266 	fOwner->fLink->Attach<uint32>(fEventMask);
5267 	fOwner->fLink->Attach<uint32>(fEventOptions);
5268 	fOwner->fLink->Attach<uint32>(Flags());
5269 	fOwner->fLink->Attach<bool>(IsHidden(this));
5270 	fOwner->fLink->Attach<rgb_color>(fState->view_color);
5271 	if (fTopLevelView)
5272 		fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
5273 	else
5274 		fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
5275 	fOwner->fLink->Flush();
5276 
5277 	_CheckOwnerLockAndSwitchCurrent();
5278 	fState->UpdateServerState(*fOwner->fLink);
5279 
5280 	// we create all its children, too
5281 
5282 	for (BView* child = fFirstChild; child != NULL;
5283 			child = child->fNextSibling) {
5284 		child->_CreateSelf();
5285 	}
5286 
5287 	fOwner->fLink->Flush();
5288 	return true;
5289 }
5290 
5291 
5292 /*!	Sets the new view position.
5293 	It doesn't contact the server, though - the only case where this
5294 	is called outside of MoveTo() is as reaction of moving a view
5295 	in the server (a.k.a. B_WINDOW_RESIZED).
5296 	It also calls the BView's FrameMoved() hook.
5297 */
5298 void
5299 BView::_MoveTo(int32 x, int32 y)
5300 {
5301 	fParentOffset.Set(x, y);
5302 
5303 	if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
5304 		BMessage moved(B_VIEW_MOVED);
5305 		moved.AddInt64("when", system_time());
5306 		moved.AddPoint("where", BPoint(x, y));
5307 
5308 		BMessenger target(this);
5309 		target.SendMessage(&moved);
5310 	}
5311 }
5312 
5313 
5314 /*!	Computes the actual new frame size and recalculates the size of
5315 	the children as well.
5316 	It doesn't contact the server, though - the only case where this
5317 	is called outside of ResizeBy() is as reaction of resizing a view
5318 	in the server (a.k.a. B_WINDOW_RESIZED).
5319 	It also calls the BView's FrameResized() hook.
5320 */
5321 void
5322 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
5323 {
5324 	fBounds.right += deltaWidth;
5325 	fBounds.bottom += deltaHeight;
5326 
5327 	if (Window() == NULL) {
5328 		// we're not supposed to exercise the resizing code in case
5329 		// we haven't been attached to a window yet
5330 		return;
5331 	}
5332 
5333 	// layout the children
5334 	if (fFlags & B_SUPPORTS_LAYOUT) {
5335 		Relayout();
5336 	} else {
5337 		for (BView* child = fFirstChild; child; child = child->fNextSibling)
5338 			child->_ParentResizedBy(deltaWidth, deltaHeight);
5339 	}
5340 
5341 	if (fFlags & B_FRAME_EVENTS) {
5342 		BMessage resized(B_VIEW_RESIZED);
5343 		resized.AddInt64("when", system_time());
5344 		resized.AddInt32("width", fBounds.IntegerWidth());
5345 		resized.AddInt32("height", fBounds.IntegerHeight());
5346 
5347 		BMessenger target(this);
5348 		target.SendMessage(&resized);
5349 	}
5350 }
5351 
5352 
5353 /*!	Relayouts the view according to its resizing mode. */
5354 void
5355 BView::_ParentResizedBy(int32 x, int32 y)
5356 {
5357 	uint32 resizingMode = fFlags & _RESIZE_MASK_;
5358 	BRect newFrame = Frame();
5359 
5360 	// follow with left side
5361 	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
5362 		newFrame.left += x;
5363 	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
5364 		newFrame.left += x / 2;
5365 
5366 	// follow with right side
5367 	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
5368 		newFrame.right += x;
5369 	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
5370 		newFrame.right += x / 2;
5371 
5372 	// follow with top side
5373 	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
5374 		newFrame.top += y;
5375 	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
5376 		newFrame.top += y / 2;
5377 
5378 	// follow with bottom side
5379 	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
5380 		newFrame.bottom += y;
5381 	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
5382 		newFrame.bottom += y / 2;
5383 
5384 	if (newFrame.LeftTop() != fParentOffset) {
5385 		// move view
5386 		_MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
5387 	}
5388 
5389 	if (newFrame != Frame()) {
5390 		// resize view
5391 		int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
5392 		int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
5393 		_ResizeBy(widthDiff, heightDiff);
5394 	}
5395 }
5396 
5397 
5398 void
5399 BView::_Activate(bool active)
5400 {
5401 	WindowActivated(active);
5402 
5403 	for (BView* child = fFirstChild; child != NULL;
5404 			child = child->fNextSibling) {
5405 		child->_Activate(active);
5406 	}
5407 }
5408 
5409 
5410 void
5411 BView::_Attach()
5412 {
5413 	AttachedToWindow();
5414 	fAttached = true;
5415 
5416 	// after giving the view a chance to do this itself,
5417 	// check for the B_PULSE_NEEDED flag and make sure the
5418 	// window set's up the pulse messaging
5419 	if (fOwner) {
5420 		if (fFlags & B_PULSE_NEEDED) {
5421 			_CheckLock();
5422 			if (fOwner->fPulseRunner == NULL)
5423 				fOwner->SetPulseRate(fOwner->PulseRate());
5424 		}
5425 
5426 		if (!fOwner->IsHidden())
5427 			Invalidate();
5428 	}
5429 
5430 	for (BView* child = fFirstChild; child != NULL;
5431 			child = child->fNextSibling) {
5432 		// we need to check for fAttached as new views could have been
5433 		// added in AttachedToWindow() - and those are already attached
5434 		if (!child->fAttached)
5435 			child->_Attach();
5436 	}
5437 
5438 	AllAttached();
5439 }
5440 
5441 
5442 void
5443 BView::_Detach()
5444 {
5445 	DetachedFromWindow();
5446 	fAttached = false;
5447 
5448 	for (BView* child = fFirstChild; child != NULL;
5449 			child = child->fNextSibling) {
5450 		child->_Detach();
5451 	}
5452 
5453 	AllDetached();
5454 
5455 	if (fOwner) {
5456 		_CheckLock();
5457 
5458 		if (!fOwner->IsHidden())
5459 			Invalidate();
5460 
5461 		// make sure our owner doesn't need us anymore
5462 
5463 		if (fOwner->CurrentFocus() == this) {
5464 			MakeFocus(false);
5465 			// MakeFocus() is virtual and might not be
5466 			// passing through to the BView version,
5467 			// but we need to make sure at this point
5468 			// that we are not the focus view anymore.
5469 			if (fOwner->CurrentFocus() == this)
5470 				fOwner->_SetFocus(NULL, true);
5471 		}
5472 
5473 		if (fOwner->fDefaultButton == this)
5474 			fOwner->SetDefaultButton(NULL);
5475 
5476 		if (fOwner->fKeyMenuBar == this)
5477 			fOwner->fKeyMenuBar = NULL;
5478 
5479 		if (fOwner->fLastMouseMovedView == this)
5480 			fOwner->fLastMouseMovedView = NULL;
5481 
5482 		if (fOwner->fLastViewToken == _get_object_token_(this))
5483 			fOwner->fLastViewToken = B_NULL_TOKEN;
5484 
5485 		_SetOwner(NULL);
5486 	}
5487 }
5488 
5489 
5490 void
5491 BView::_Draw(BRect updateRect)
5492 {
5493 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
5494 		return;
5495 
5496 	// NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
5497 	// -> View is simply not drawn at all
5498 
5499 	_SwitchServerCurrentView();
5500 
5501 	ConvertFromScreen(&updateRect);
5502 
5503 	// TODO: make states robust (the hook implementation could
5504 	// mess things up if it uses non-matching Push- and PopState(),
5505 	// we would not be guaranteed to still have the same state on
5506 	// the stack after having called Draw())
5507 	PushState();
5508 	Draw(updateRect);
5509 	PopState();
5510 	Flush();
5511 }
5512 
5513 
5514 void
5515 BView::_DrawAfterChildren(BRect updateRect)
5516 {
5517 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
5518 		|| !(Flags() & B_DRAW_ON_CHILDREN))
5519 		return;
5520 
5521 	_SwitchServerCurrentView();
5522 
5523 	ConvertFromScreen(&updateRect);
5524 
5525 	// TODO: make states robust (see above)
5526 	PushState();
5527 	DrawAfterChildren(updateRect);
5528 	PopState();
5529 	Flush();
5530 }
5531 
5532 
5533 void
5534 BView::_Pulse()
5535 {
5536 	if ((Flags() & B_PULSE_NEEDED) != 0)
5537 		Pulse();
5538 
5539 	for (BView* child = fFirstChild; child != NULL;
5540 			child = child->fNextSibling) {
5541 		child->_Pulse();
5542 	}
5543 }
5544 
5545 
5546 void
5547 BView::_UpdateStateForRemove()
5548 {
5549 	// TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
5550 	if (!_CheckOwnerLockAndSwitchCurrent())
5551 		return;
5552 
5553 	fState->UpdateFrom(*fOwner->fLink);
5554 //	if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
5555 //		fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
5556 //
5557 //		status_t code;
5558 //		if (fOwner->fLink->FlushWithReply(code) == B_OK
5559 //			&& code == B_OK) {
5560 //			fOwner->fLink->Read<BPoint>(&fParentOffset);
5561 //			fOwner->fLink->Read<BRect>(&fBounds);
5562 //			fState->valid_flags |= B_VIEW_FRAME_BIT;
5563 //		}
5564 //	}
5565 
5566 	// update children as well
5567 
5568 	for (BView* child = fFirstChild; child != NULL;
5569 			child = child->fNextSibling) {
5570 		if (child->fOwner)
5571 			child->_UpdateStateForRemove();
5572 	}
5573 }
5574 
5575 
5576 inline void
5577 BView::_UpdatePattern(::pattern pattern)
5578 {
5579 	if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
5580 		return;
5581 
5582 	if (fOwner) {
5583 		_CheckLockAndSwitchCurrent();
5584 
5585 		fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
5586 		fOwner->fLink->Attach< ::pattern>(pattern);
5587 
5588 		fState->valid_flags |= B_VIEW_PATTERN_BIT;
5589 	}
5590 
5591 	fState->pattern = pattern;
5592 }
5593 
5594 
5595 void
5596 BView::_FlushIfNotInTransaction()
5597 {
5598 	if (!fOwner->fInTransaction) {
5599 		fOwner->Flush();
5600 	}
5601 }
5602 
5603 
5604 BShelf*
5605 BView::_Shelf() const
5606 {
5607 	return fShelf;
5608 }
5609 
5610 
5611 void
5612 BView::_SetShelf(BShelf* shelf)
5613 {
5614 	if (fShelf != NULL && fOwner != NULL)
5615 		fOwner->RemoveHandler(fShelf);
5616 
5617 	fShelf = shelf;
5618 
5619 	if (fShelf != NULL && fOwner != NULL)
5620 		fOwner->AddHandler(fShelf);
5621 }
5622 
5623 
5624 status_t
5625 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
5626 	uint32 followFlags, uint32 options)
5627 {
5628 	if (!_CheckOwnerLockAndSwitchCurrent())
5629 		return B_ERROR;
5630 
5631 	int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
5632 
5633 	fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
5634 	fOwner->fLink->Attach<int32>(serverToken);
5635 	fOwner->fLink->Attach<BRect>(srcRect);
5636 	fOwner->fLink->Attach<BRect>(dstRect);
5637 	fOwner->fLink->Attach<int32>(followFlags);
5638 	fOwner->fLink->Attach<int32>(options);
5639 
5640 	status_t status = B_ERROR;
5641 	fOwner->fLink->FlushWithReply(status);
5642 
5643 	return status;
5644 }
5645 
5646 
5647 bool
5648 BView::_CheckOwnerLockAndSwitchCurrent() const
5649 {
5650 	STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
5651 
5652 	if (fOwner == NULL) {
5653 		debugger("View method requires owner and doesn't have one.");
5654 		return false;
5655 	}
5656 
5657 	_CheckLockAndSwitchCurrent();
5658 
5659 	return true;
5660 }
5661 
5662 
5663 bool
5664 BView::_CheckOwnerLock() const
5665 {
5666 	if (fOwner) {
5667 		fOwner->check_lock();
5668 		return true;
5669 	} else {
5670 		debugger("View method requires owner and doesn't have one.");
5671 		return false;
5672 	}
5673 }
5674 
5675 
5676 void
5677 BView::_CheckLockAndSwitchCurrent() const
5678 {
5679 	STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
5680 
5681 	if (!fOwner)
5682 		return;
5683 
5684 	fOwner->check_lock();
5685 
5686 	_SwitchServerCurrentView();
5687 }
5688 
5689 
5690 void
5691 BView::_CheckLock() const
5692 {
5693 	if (fOwner)
5694 		fOwner->check_lock();
5695 }
5696 
5697 
5698 void
5699 BView::_SwitchServerCurrentView() const
5700 {
5701 	int32 serverToken = _get_object_token_(this);
5702 
5703 	if (fOwner->fLastViewToken != serverToken) {
5704 		STRACE(("contacting app_server... sending token: %ld\n", serverToken));
5705 		fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
5706 		fOwner->fLink->Attach<int32>(serverToken);
5707 
5708 		fOwner->fLastViewToken = serverToken;
5709 	}
5710 }
5711 
5712 
5713 void
5714 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
5715 {
5716 	if (scrollBar == NULL || delta == 0.0f)
5717 		return;
5718 
5719 	float smallStep, largeStep;
5720 	scrollBar->GetSteps(&smallStep, &largeStep);
5721 
5722 	// pressing the shift key scrolls faster (following the pseudo-standard set
5723 	// by other desktop environments).
5724 	if ((modifiers() & B_SHIFT_KEY) != 0)
5725 		delta *= largeStep;
5726 	else
5727 		delta *= smallStep * 3;
5728 
5729 	scrollBar->SetValue(scrollBar->Value() + delta);
5730 }
5731 
5732 
5733 #if __GNUC__ == 2
5734 
5735 
5736 extern "C" void
5737 _ReservedView1__5BView(BView* view, BRect rect)
5738 {
5739 	view->BView::DrawAfterChildren(rect);
5740 }
5741 
5742 
5743 extern "C" void
5744 _ReservedView2__5BView(BView* view)
5745 {
5746 	// MinSize()
5747 	perform_data_min_size data;
5748 	view->Perform(PERFORM_CODE_MIN_SIZE, &data);
5749 }
5750 
5751 
5752 extern "C" void
5753 _ReservedView3__5BView(BView* view)
5754 {
5755 	// MaxSize()
5756 	perform_data_max_size data;
5757 	view->Perform(PERFORM_CODE_MAX_SIZE, &data);
5758 }
5759 
5760 
5761 extern "C" BSize
5762 _ReservedView4__5BView(BView* view)
5763 {
5764 	// PreferredSize()
5765 	perform_data_preferred_size data;
5766 	view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
5767 	return data.return_value;
5768 }
5769 
5770 
5771 extern "C" BAlignment
5772 _ReservedView5__5BView(BView* view)
5773 {
5774 	// LayoutAlignment()
5775 	perform_data_layout_alignment data;
5776 	view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
5777 	return data.return_value;
5778 }
5779 
5780 
5781 extern "C" bool
5782 _ReservedView6__5BView(BView* view)
5783 {
5784 	// HasHeightForWidth()
5785 	perform_data_has_height_for_width data;
5786 	view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
5787 	return data.return_value;
5788 }
5789 
5790 
5791 extern "C" void
5792 _ReservedView7__5BView(BView* view, float width, float* min, float* max,
5793 	float* preferred)
5794 {
5795 	// GetHeightForWidth()
5796 	perform_data_get_height_for_width data;
5797 	data.width = width;
5798 	view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
5799 	if (min != NULL)
5800 		*min = data.min;
5801 	if (max != NULL)
5802 		*max = data.max;
5803 	if (preferred != NULL)
5804 		*preferred = data.preferred;
5805 }
5806 
5807 
5808 extern "C" void
5809 _ReservedView8__5BView(BView* view, BLayout* layout)
5810 {
5811 	// SetLayout()
5812 	perform_data_set_layout data;
5813 	data.layout = layout;
5814 	view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
5815 }
5816 
5817 
5818 extern "C" void
5819 _ReservedView9__5BView(BView* view, bool descendants)
5820 {
5821 	// LayoutInvalidated()
5822 	perform_data_layout_invalidated data;
5823 	data.descendants = descendants;
5824 	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
5825 }
5826 
5827 
5828 extern "C" void
5829 _ReservedView10__5BView(BView* view)
5830 {
5831 	// DoLayout()
5832 	view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
5833 }
5834 
5835 
5836 #endif	// __GNUC__ == 2
5837 
5838 
5839 extern "C" bool
5840 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
5841 	BView* view, BPoint point, BToolTip** _toolTip)
5842 {
5843 	// GetToolTipAt()
5844 	perform_data_get_tool_tip_at data;
5845 	data.point = point;
5846 	data.tool_tip = _toolTip;
5847 	view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
5848 	return data.return_value;
5849 }
5850 
5851 
5852 extern "C" void
5853 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
5854 	BView* view)
5855 {
5856 	// LayoutChanged();
5857 	view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
5858 }
5859 
5860 
5861 void BView::_ReservedView13() {}
5862 void BView::_ReservedView14() {}
5863 void BView::_ReservedView15() {}
5864 void BView::_ReservedView16() {}
5865 
5866 
5867 BView::BView(const BView& other)
5868 	:
5869 	BHandler()
5870 {
5871 	// this is private and not functional, but exported
5872 }
5873 
5874 
5875 BView&
5876 BView::operator=(const BView& other)
5877 {
5878 	// this is private and not functional, but exported
5879 	return *this;
5880 }
5881 
5882 
5883 void
5884 BView::_PrintToStream()
5885 {
5886 	printf("BView::_PrintToStream()\n");
5887 	printf("\tName: %s\n"
5888 		"\tParent: %s\n"
5889 		"\tFirstChild: %s\n"
5890 		"\tNextSibling: %s\n"
5891 		"\tPrevSibling: %s\n"
5892 		"\tOwner(Window): %s\n"
5893 		"\tToken: %" B_PRId32 "\n"
5894 		"\tFlags: %" B_PRId32 "\n"
5895 		"\tView origin: (%f,%f)\n"
5896 		"\tView Bounds rectangle: (%f,%f,%f,%f)\n"
5897 		"\tShow level: %d\n"
5898 		"\tTopView?: %s\n"
5899 		"\tBPicture: %s\n"
5900 		"\tVertical Scrollbar %s\n"
5901 		"\tHorizontal Scrollbar %s\n"
5902 		"\tIs Printing?: %s\n"
5903 		"\tShelf?: %s\n"
5904 		"\tEventMask: %" B_PRId32 "\n"
5905 		"\tEventOptions: %" B_PRId32 "\n",
5906 	Name(),
5907 	fParent ? fParent->Name() : "NULL",
5908 	fFirstChild ? fFirstChild->Name() : "NULL",
5909 	fNextSibling ? fNextSibling->Name() : "NULL",
5910 	fPreviousSibling ? fPreviousSibling->Name() : "NULL",
5911 	fOwner ? fOwner->Name() : "NULL",
5912 	_get_object_token_(this),
5913 	fFlags,
5914 	fParentOffset.x, fParentOffset.y,
5915 	fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
5916 	fShowLevel,
5917 	fTopLevelView ? "YES" : "NO",
5918 	fCurrentPicture? "YES" : "NULL",
5919 	fVerScroller? "YES" : "NULL",
5920 	fHorScroller? "YES" : "NULL",
5921 	fIsPrinting? "YES" : "NO",
5922 	fShelf? "YES" : "NO",
5923 	fEventMask,
5924 	fEventOptions);
5925 
5926 	printf("\tState status:\n"
5927 		"\t\tLocalCoordianteSystem: (%f,%f)\n"
5928 		"\t\tPenLocation: (%f,%f)\n"
5929 		"\t\tPenSize: %f\n"
5930 		"\t\tHighColor: [%d,%d,%d,%d]\n"
5931 		"\t\tLowColor: [%d,%d,%d,%d]\n"
5932 		"\t\tViewColor: [%d,%d,%d,%d]\n"
5933 		"\t\tPattern: %" B_PRIx64 "\n"
5934 		"\t\tDrawingMode: %d\n"
5935 		"\t\tLineJoinMode: %d\n"
5936 		"\t\tLineCapMode: %d\n"
5937 		"\t\tMiterLimit: %f\n"
5938 		"\t\tAlphaSource: %d\n"
5939 		"\t\tAlphaFuntion: %d\n"
5940 		"\t\tScale: %f\n"
5941 		"\t\t(Print)FontAliasing: %s\n"
5942 		"\t\tFont Info:\n",
5943 	fState->origin.x, fState->origin.y,
5944 	fState->pen_location.x, fState->pen_location.y,
5945 	fState->pen_size,
5946 	fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
5947 	fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
5948 	fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
5949 	*((uint64*)&(fState->pattern)),
5950 	fState->drawing_mode,
5951 	fState->line_join,
5952 	fState->line_cap,
5953 	fState->miter_limit,
5954 	fState->alpha_source_mode,
5955 	fState->alpha_function_mode,
5956 	fState->scale,
5957 	fState->font_aliasing? "YES" : "NO");
5958 
5959 	fState->font.PrintToStream();
5960 
5961 	// TODO: also print the line array.
5962 }
5963 
5964 
5965 void
5966 BView::_PrintTree()
5967 {
5968 	int32 spaces = 2;
5969 	BView* c = fFirstChild; //c = short for: current
5970 	printf( "'%s'\n", Name() );
5971 	if (c != NULL) {
5972 		while(true) {
5973 			// action block
5974 			{
5975 				for (int i = 0; i < spaces; i++)
5976 					printf(" ");
5977 
5978 				printf( "'%s'\n", c->Name() );
5979 			}
5980 
5981 			// go deep
5982 			if (c->fFirstChild) {
5983 				c = c->fFirstChild;
5984 				spaces += 2;
5985 			} else {
5986 				// go right
5987 				if (c->fNextSibling) {
5988 					c = c->fNextSibling;
5989 				} else {
5990 					// go up
5991 					while (!c->fParent->fNextSibling && c->fParent != this) {
5992 						c = c->fParent;
5993 						spaces -= 2;
5994 					}
5995 
5996 					// that enough! We've reached this view.
5997 					if (c->fParent == this)
5998 						break;
5999 
6000 					c = c->fParent->fNextSibling;
6001 					spaces -= 2;
6002 				}
6003 			}
6004 		}
6005 	}
6006 }
6007 
6008 
6009 // #pragma mark -
6010 
6011 
6012 BLayoutItem*
6013 BView::Private::LayoutItemAt(int32 index)
6014 {
6015 	return fView->fLayoutData->fLayoutItems.ItemAt(index);
6016 }
6017 
6018 
6019 int32
6020 BView::Private::CountLayoutItems()
6021 {
6022 	return fView->fLayoutData->fLayoutItems.CountItems();
6023 }
6024 
6025 
6026 void
6027 BView::Private::RegisterLayoutItem(BLayoutItem* item)
6028 {
6029 	fView->fLayoutData->fLayoutItems.AddItem(item);
6030 }
6031 
6032 
6033 void
6034 BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6035 {
6036 	fView->fLayoutData->fLayoutItems.RemoveItem(item);
6037 }
6038 
6039 
6040 bool
6041 BView::Private::MinMaxValid()
6042 {
6043 	return fView->fLayoutData->fMinMaxValid;
6044 }
6045 
6046 
6047 bool
6048 BView::Private::WillLayout()
6049 {
6050 	BView::LayoutData* data = fView->fLayoutData;
6051 	if (data->fLayoutInProgress)
6052 		return false;
6053 	if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6054 		return true;
6055 	return false;
6056 }
6057