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