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