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