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