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