xref: /haiku/src/kits/interface/View.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
1 /*
2  * Copyright 2001-2008, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Adrian Oanca <adioanca@cotty.iren.ro>
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Stephan Aßmus <superstippi@gmx.de>
9  *		Ingo Weinhold <bonefish@cs.tu-berlin.de>
10  */
11 
12 
13 #include <AppMisc.h>
14 #include <AppServerLink.h>
15 #include <MessagePrivate.h>
16 #include <MessageUtils.h>
17 #include <PortLink.h>
18 #include <ServerProtocol.h>
19 #include <ShapePrivate.h>
20 #include <TokenSpace.h>
21 #include <ViewPrivate.h>
22 
23 #include <Application.h>
24 #include <Bitmap.h>
25 #include <Button.h>
26 #include <Cursor.h>
27 #include <File.h>
28 #include <InterfaceDefs.h>
29 #include <Layout.h>
30 #include <LayoutContext.h>
31 #include <LayoutUtils.h>
32 #include <MenuBar.h>
33 #include <Message.h>
34 #include <MessageQueue.h>
35 #include <Picture.h>
36 #include <Point.h>
37 #include <Polygon.h>
38 #include <PropertyInfo.h>
39 #include <Region.h>
40 #include <ScrollBar.h>
41 #include <Shape.h>
42 #include <Shelf.h>
43 #include <String.h>
44 #include <View.h>
45 #include <Window.h>
46 
47 #include <math.h>
48 #include <new>
49 #include <stdio.h>
50 
51 
52 using std::nothrow;
53 
54 //#define DEBUG_BVIEW
55 #ifdef DEBUG_BVIEW
56 #	include <stdio.h>
57 #	define STRACE(x) printf x
58 #	define BVTRACE _PrintToStream()
59 #else
60 #	define STRACE(x) ;
61 #	define BVTRACE ;
62 #endif
63 
64 #define MAX_ATTACHMENT_SIZE 49152
65 
66 
67 static property_info sViewPropInfo[] = {
68 	{ "Frame", { B_GET_PROPERTY, 0 },
69 		{ B_DIRECT_SPECIFIER, 0 }, "Returns the view's frame rectangle.", 0, { 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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_SET_EVENT_MASK);
1601 		fOwner->fLink->Attach<uint32>(mask);
1602 		fOwner->fLink->Attach<uint32>(options);
1603 		fOwner->fLink->Flush();
1604 	}
1605 
1606 	return B_OK;
1607 }
1608 
1609 
1610 uint32
1611 BView::EventMask()
1612 {
1613 	return fEventMask;
1614 }
1615 
1616 
1617 status_t
1618 BView::SetMouseEventMask(uint32 mask, uint32 options)
1619 {
1620 	// Just don't do anything if the view is not yet attached
1621 	// or we were called outside of BView::MouseDown()
1622 	if (fOwner != NULL
1623 		&& fOwner->CurrentMessage() != NULL
1624 		&& fOwner->CurrentMessage()->what == B_MOUSE_DOWN) {
1625 		_CheckLockAndSwitchCurrent();
1626 		fMouseEventOptions = options;
1627 
1628 		fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK);
1629 		fOwner->fLink->Attach<uint32>(mask);
1630 		fOwner->fLink->Attach<uint32>(options);
1631 		fOwner->fLink->Flush();
1632 		return B_OK;
1633 	}
1634 
1635 	return B_ERROR;
1636 }
1637 
1638 
1639 //	#pragma mark - Graphic State Functions
1640 
1641 
1642 void
1643 BView::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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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_VIEW_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 		debugger("AddChild failed - the view already has a parent.");
3416 		return false;
3417 	}
3418 
3419 	bool lockedOwner = false;
3420 	if (fOwner && !fOwner->IsLocked()) {
3421 		fOwner->Lock();
3422 		lockedOwner = true;
3423 	}
3424 
3425 	if (!_AddChildToList(child, before)) {
3426 		debugger("AddChild failed!");
3427 		if (lockedOwner)
3428 			fOwner->Unlock();
3429 		return false;
3430 	}
3431 
3432 	if (fOwner) {
3433 		_CheckLockAndSwitchCurrent();
3434 
3435 		child->_SetOwner(fOwner);
3436 		child->_CreateSelf();
3437 		child->_Attach();
3438 
3439 		if (lockedOwner)
3440 			fOwner->Unlock();
3441 	}
3442 
3443 	InvalidateLayout();
3444 
3445 	return true;
3446 }
3447 
3448 
3449 bool
3450 BView::RemoveChild(BView *child)
3451 {
3452 	STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
3453 
3454 	if (!child)
3455 		return false;
3456 
3457 	return child->RemoveSelf();
3458 }
3459 
3460 int32
3461 BView::CountChildren() const
3462 {
3463 	_CheckLock();
3464 
3465 	uint32 count = 0;
3466 	BView *child = fFirstChild;
3467 
3468 	while (child != NULL) {
3469 		count++;
3470 		child = child->fNextSibling;
3471 	}
3472 
3473 	return count;
3474 }
3475 
3476 
3477 BView *
3478 BView::ChildAt(int32 index) const
3479 {
3480 	_CheckLock();
3481 
3482 	BView *child = fFirstChild;
3483 	while (child != NULL && index-- > 0) {
3484 		child = child->fNextSibling;
3485 	}
3486 
3487 	return child;
3488 }
3489 
3490 
3491 BView *
3492 BView::NextSibling() const
3493 {
3494 	return fNextSibling;
3495 }
3496 
3497 
3498 BView *
3499 BView::PreviousSibling() const
3500 {
3501 	return fPreviousSibling;
3502 }
3503 
3504 
3505 bool
3506 BView::RemoveSelf()
3507 {
3508 	if (fParent && fParent->fLayoutData->fLayout)
3509 		return fParent->fLayoutData->fLayout->RemoveView(this);
3510 	else
3511 		return _RemoveSelf();
3512 }
3513 
3514 
3515 bool
3516 BView::_RemoveSelf()
3517 {
3518 	STRACE(("BView(%s)::RemoveSelf()...\n", Name()));
3519 
3520 	// Remove this child from its parent
3521 
3522 	BWindow* owner = fOwner;
3523 	_CheckLock();
3524 
3525 	if (owner != NULL) {
3526 		_UpdateStateForRemove();
3527 		_Detach();
3528 	}
3529 
3530 	BView* parent = fParent;
3531 	if (!parent || !parent->_RemoveChildFromList(this))
3532 		return false;
3533 
3534 	if (owner != NULL && !fTopLevelView) {
3535 		// the top level view is deleted by the app_server automatically
3536 		owner->fLink->StartMessage(AS_VIEW_DELETE);
3537 		owner->fLink->Attach<int32>(_get_object_token_(this));
3538 	}
3539 
3540 	parent->InvalidateLayout();
3541 
3542 	STRACE(("DONE: BView(%s)::RemoveSelf()\n", Name()));
3543 
3544 	return true;
3545 }
3546 
3547 
3548 BView *
3549 BView::Parent() const
3550 {
3551 	if (fParent && fParent->fTopLevelView)
3552 		return NULL;
3553 
3554 	return fParent;
3555 }
3556 
3557 
3558 BView *
3559 BView::FindView(const char *name) const
3560 {
3561 	if (name == NULL)
3562 		return NULL;
3563 
3564 	if (Name() != NULL && !strcmp(Name(), name))
3565 		return const_cast<BView *>(this);
3566 
3567 	BView *child = fFirstChild;
3568 	while (child != NULL) {
3569 		BView *view = child->FindView(name);
3570 		if (view != NULL)
3571 			return view;
3572 
3573 		child = child->fNextSibling;
3574 	}
3575 
3576 	return NULL;
3577 }
3578 
3579 
3580 void
3581 BView::MoveBy(float deltaX, float deltaY)
3582 {
3583 	MoveTo(fParentOffset.x + deltaX, fParentOffset.y + deltaY);
3584 }
3585 
3586 
3587 void
3588 BView::MoveTo(BPoint where)
3589 {
3590 	MoveTo(where.x, where.y);
3591 }
3592 
3593 
3594 void
3595 BView::MoveTo(float x, float y)
3596 {
3597 	if (x == fParentOffset.x && y == fParentOffset.y)
3598 		return;
3599 
3600 	// BeBook says we should do this. And it makes sense.
3601 	x = roundf(x);
3602 	y = roundf(y);
3603 
3604 	if (fOwner) {
3605 		_CheckLockAndSwitchCurrent();
3606 		fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO);
3607 		fOwner->fLink->Attach<float>(x);
3608 		fOwner->fLink->Attach<float>(y);
3609 
3610 //		fState->valid_flags |= B_VIEW_FRAME_BIT;
3611 
3612 		_FlushIfNotInTransaction();
3613 	}
3614 
3615 	_MoveTo((int32)x, (int32)y);
3616 }
3617 
3618 
3619 void
3620 BView::ResizeBy(float deltaWidth, float deltaHeight)
3621 {
3622 	// BeBook says we should do this. And it makes sense.
3623 	deltaWidth = roundf(deltaWidth);
3624 	deltaHeight = roundf(deltaHeight);
3625 
3626 	if (deltaWidth == 0 && deltaHeight == 0)
3627 		return;
3628 
3629 	if (fOwner) {
3630 		_CheckLockAndSwitchCurrent();
3631 		fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO);
3632 
3633 		fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth);
3634 		fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight);
3635 
3636 //		fState->valid_flags |= B_VIEW_FRAME_BIT;
3637 
3638 		_FlushIfNotInTransaction();
3639 	}
3640 
3641 	_ResizeBy((int32)deltaWidth, (int32)deltaHeight);
3642 }
3643 
3644 
3645 void
3646 BView::ResizeTo(float width, float height)
3647 {
3648 	ResizeBy(width - fBounds.Width(), height - fBounds.Height());
3649 }
3650 
3651 
3652 void
3653 BView::ResizeTo(BSize size)
3654 {
3655 	ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height());
3656 }
3657 
3658 
3659 //	#pragma mark - Inherited Methods (from BHandler)
3660 
3661 
3662 status_t
3663 BView::GetSupportedSuites(BMessage *data)
3664 {
3665 	if (data == NULL)
3666 		return B_BAD_VALUE;
3667 
3668 	status_t status = data->AddString("suites", "suite/vnd.Be-view");
3669 	BPropertyInfo propertyInfo(sViewPropInfo);
3670 	if (status == B_OK)
3671 		status = data->AddFlat("messages", &propertyInfo);
3672 	if (status == B_OK)
3673 		return BHandler::GetSupportedSuites(data);
3674 	return status;
3675 }
3676 
3677 
3678 BHandler *
3679 BView::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier,
3680 	int32 what,	const char *property)
3681 {
3682 	if (msg->what == B_WINDOW_MOVE_BY
3683 		|| msg->what == B_WINDOW_MOVE_TO)
3684 		return this;
3685 
3686 	BPropertyInfo propertyInfo(sViewPropInfo);
3687 	status_t err = B_BAD_SCRIPT_SYNTAX;
3688 	BMessage replyMsg(B_REPLY);
3689 
3690 	switch (propertyInfo.FindMatch(msg, index, specifier, what, property)) {
3691 		case 0:
3692 		case 1:
3693 		case 2:
3694 		case 3:
3695 		case 5:
3696 			return this;
3697 
3698 		case 4:
3699 			if (fShelf) {
3700 				msg->PopSpecifier();
3701 				return fShelf;
3702 			}
3703 
3704 			err = B_NAME_NOT_FOUND;
3705 			replyMsg.AddString("message", "This window doesn't have a shelf");
3706 			break;
3707 
3708 		case 6: {
3709 			if (!fFirstChild) {
3710 				err = B_NAME_NOT_FOUND;
3711 				replyMsg.AddString("message", "This window doesn't have children.");
3712 				break;
3713 			}
3714 			BView *child = NULL;
3715 			switch (what) {
3716 				case B_INDEX_SPECIFIER:	{
3717 					int32 index;
3718 					err = specifier->FindInt32("index", &index);
3719 					if (err == B_OK)
3720 						child = ChildAt(index);
3721 					break;
3722 				}
3723 				case B_REVERSE_INDEX_SPECIFIER: {
3724 					int32 rindex;
3725 					err = specifier->FindInt32("index", &rindex);
3726 					if (err == B_OK)
3727 						child = ChildAt(CountChildren() - rindex);
3728 					break;
3729 				}
3730 				case B_NAME_SPECIFIER: {
3731 					const char *name;
3732 					err = specifier->FindString("name", &name);
3733 					if (err == B_OK)
3734 						child = FindView(name);
3735 					break;
3736 				}
3737 			}
3738 
3739 			if (child != NULL) {
3740 				msg->PopSpecifier();
3741 				return child;
3742 			}
3743 
3744 			if (err == B_OK)
3745 				err = B_BAD_INDEX;
3746 			replyMsg.AddString("message", "Cannot find view at/with specified index/name.");
3747 			break;
3748 		}
3749 		default:
3750 			return BHandler::ResolveSpecifier(msg, index, specifier, what, property);
3751 	}
3752 
3753 	if (err < B_OK) {
3754 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
3755 
3756 		if (err == B_BAD_SCRIPT_SYNTAX)
3757 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
3758 		else
3759 			replyMsg.AddString("message", strerror(err));
3760 	}
3761 
3762 	replyMsg.AddInt32("error", err);
3763 	msg->SendReply(&replyMsg);
3764 	return NULL;
3765 }
3766 
3767 
3768 void
3769 BView::MessageReceived(BMessage *msg)
3770 {
3771 	if (!msg->HasSpecifiers()) {
3772 		switch (msg->what) {
3773 			case B_VIEW_RESIZED:
3774 				// By the time the message arrives, the bounds may have
3775 				// changed already, that's why we don't use the values
3776 				// in the message itself.
3777 				FrameResized(fBounds.Width(), fBounds.Height());
3778 				break;
3779 
3780 			case B_VIEW_MOVED:
3781 				FrameMoved(fParentOffset);
3782 				break;
3783 
3784 			case B_MOUSE_WHEEL_CHANGED:
3785 			{
3786 				float deltaX = 0.0f, deltaY = 0.0f;
3787 
3788 				BScrollBar *horizontal = ScrollBar(B_HORIZONTAL);
3789 				if (horizontal != NULL)
3790 					msg->FindFloat("be:wheel_delta_x", &deltaX);
3791 
3792 				BScrollBar *vertical = ScrollBar(B_VERTICAL);
3793 				if (vertical != NULL)
3794 					msg->FindFloat("be:wheel_delta_y", &deltaY);
3795 
3796 				if (deltaX == 0.0f && deltaY == 0.0f)
3797 					return;
3798 
3799 				float smallStep, largeStep;
3800 				if (horizontal != NULL) {
3801 					horizontal->GetSteps(&smallStep, &largeStep);
3802 
3803 					// pressing the option key scrolls faster
3804 					if (modifiers() & B_OPTION_KEY)
3805 						deltaX *= largeStep;
3806 					else
3807 						deltaX *= smallStep * 3;
3808 
3809 					horizontal->SetValue(horizontal->Value() + deltaX);
3810 				}
3811 
3812 				if (vertical != NULL) {
3813 					vertical->GetSteps(&smallStep, &largeStep);
3814 
3815 					// pressing the option key scrolls faster
3816 					if (modifiers() & B_OPTION_KEY)
3817 						deltaY *= largeStep;
3818 					else
3819 						deltaY *= smallStep * 3;
3820 
3821 					vertical->SetValue(vertical->Value() + deltaY);
3822 				}
3823 				break;
3824 			}
3825 
3826 			default:
3827 				return BHandler::MessageReceived(msg);
3828 		}
3829 
3830 		return;
3831 	}
3832 
3833 	// Scripting message
3834 
3835 	BMessage replyMsg(B_REPLY);
3836 	status_t err = B_BAD_SCRIPT_SYNTAX;
3837 	int32 index;
3838 	BMessage specifier;
3839 	int32 what;
3840 	const char *prop;
3841 
3842 	if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK)
3843 		return BHandler::MessageReceived(msg);
3844 
3845 	BPropertyInfo propertyInfo(sViewPropInfo);
3846 	switch (propertyInfo.FindMatch(msg, index, &specifier, what, prop)) {
3847 		case 0:
3848 			err = replyMsg.AddRect("result", Frame());
3849 			break;
3850 		case 1: {
3851 			BRect newFrame;
3852 			err = msg->FindRect("data", &newFrame);
3853 			if (err == B_OK) {
3854 				MoveTo(newFrame.LeftTop());
3855 				ResizeTo(newFrame.right, newFrame.bottom);
3856 			}
3857 			break;
3858 		}
3859 		case 2:
3860 			err = replyMsg.AddBool( "result", IsHidden());
3861 			break;
3862 		case 3: {
3863 			bool newHiddenState;
3864 			err = msg->FindBool("data", &newHiddenState);
3865 			if (err == B_OK) {
3866 				if (!IsHidden() && newHiddenState == true)
3867 					Hide();
3868 				else if (IsHidden() && newHiddenState == false)
3869 					Show();
3870 			}
3871 		}
3872 		case 5:
3873 			err = replyMsg.AddInt32("result", CountChildren());
3874 			break;
3875 		default:
3876 			return BHandler::MessageReceived(msg);
3877 	}
3878 
3879 	if (err < B_OK) {
3880 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
3881 
3882 		if (err == B_BAD_SCRIPT_SYNTAX)
3883 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
3884 		else
3885 			replyMsg.AddString("message", strerror(err));
3886 	}
3887 
3888 	replyMsg.AddInt32("error", err);
3889 	msg->SendReply(&replyMsg);
3890 }
3891 
3892 
3893 status_t
3894 BView::Perform(perform_code d, void* arg)
3895 {
3896 	return B_BAD_VALUE;
3897 }
3898 
3899 
3900 // #pragma mark - Layout Functions
3901 
3902 
3903 BSize
3904 BView::MinSize()
3905 {
3906 	// TODO: make sure this works correctly when some methods are overridden
3907 	float width, height;
3908 	GetPreferredSize(&width, &height);
3909 
3910 	return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
3911 		(fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
3912 			: BSize(width, height)));
3913 }
3914 
3915 
3916 BSize
3917 BView::MaxSize()
3918 {
3919 	return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
3920 		(fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
3921 			: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
3922 }
3923 
3924 
3925 BSize
3926 BView::PreferredSize()
3927 {
3928 	// TODO: make sure this works correctly when some methods are overridden
3929 	float width, height;
3930 	GetPreferredSize(&width, &height);
3931 
3932 	return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
3933 		(fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
3934 			: BSize(width, height)));
3935 }
3936 
3937 
3938 BAlignment
3939 BView::Alignment()
3940 {
3941 	return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
3942 		(fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
3943 			: BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
3944 }
3945 
3946 
3947 void
3948 BView::SetExplicitMinSize(BSize size)
3949 {
3950 	fLayoutData->fMinSize = size;
3951 	InvalidateLayout();
3952 }
3953 
3954 
3955 void
3956 BView::SetExplicitMaxSize(BSize size)
3957 {
3958 	fLayoutData->fMaxSize = size;
3959 	InvalidateLayout();
3960 }
3961 
3962 
3963 void
3964 BView::SetExplicitPreferredSize(BSize size)
3965 {
3966 	fLayoutData->fPreferredSize = size;
3967 	InvalidateLayout();
3968 }
3969 
3970 
3971 void
3972 BView::SetExplicitAlignment(BAlignment alignment)
3973 {
3974 	fLayoutData->fAlignment = alignment;
3975 	InvalidateLayout();
3976 }
3977 
3978 
3979 BSize
3980 BView::ExplicitMinSize() const
3981 {
3982 	return fLayoutData->fMinSize;
3983 }
3984 
3985 
3986 BSize
3987 BView::ExplicitMaxSize() const
3988 {
3989 	return fLayoutData->fMaxSize;
3990 }
3991 
3992 
3993 BSize
3994 BView::ExplicitPreferredSize() const
3995 {
3996 	return fLayoutData->fPreferredSize;
3997 }
3998 
3999 
4000 BAlignment
4001 BView::ExplicitAlignment() const
4002 {
4003 	return fLayoutData->fAlignment;
4004 }
4005 
4006 
4007 bool
4008 BView::HasHeightForWidth()
4009 {
4010 	return (fLayoutData->fLayout
4011 		? fLayoutData->fLayout->HasHeightForWidth() : false);
4012 }
4013 
4014 
4015 void
4016 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
4017 {
4018 	if (fLayoutData->fLayout)
4019 		fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
4020 }
4021 
4022 
4023 void
4024 BView::SetLayout(BLayout* layout)
4025 {
4026 	if (layout == fLayoutData->fLayout)
4027 		return;
4028 
4029 	fFlags |= B_SUPPORTS_LAYOUT;
4030 
4031 	// unset and delete the old layout
4032 	if (fLayoutData->fLayout) {
4033 		fLayoutData->fLayout->SetView(NULL);
4034 		delete fLayoutData->fLayout;
4035 	}
4036 
4037 	fLayoutData->fLayout = layout;
4038 
4039 	if (fLayoutData->fLayout) {
4040 		fLayoutData->fLayout->SetView(this);
4041 
4042 		// add all children
4043 		int count = CountChildren();
4044 		for (int i = 0; i < count; i++)
4045 			fLayoutData->fLayout->AddView(ChildAt(i));
4046 	}
4047 
4048 	InvalidateLayout();
4049 }
4050 
4051 
4052 BLayout*
4053 BView::GetLayout() const
4054 {
4055 	return fLayoutData->fLayout;
4056 }
4057 
4058 
4059 void
4060 BView::InvalidateLayout(bool descendants)
4061 {
4062 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress
4063 		&& fLayoutData->fLayoutInvalidationDisabled == 0) {
4064 		if (fParent && fParent->fLayoutData->fLayoutValid)
4065 			fParent->InvalidateLayout(false);
4066 
4067 		fLayoutData->fLayoutValid = false;
4068 
4069 		if (fLayoutData->fLayout)
4070 			fLayoutData->fLayout->InvalidateLayout();
4071 
4072 		if (descendants) {
4073 			int count = CountChildren();
4074 			for (int i = 0; i < count; i++)
4075 				ChildAt(i)->InvalidateLayout(descendants);
4076 		}
4077 
4078 		if (fTopLevelView) {
4079 			// trigger layout process
4080 			if (fOwner)
4081 				fOwner->PostMessage(B_LAYOUT_WINDOW);
4082 		}
4083 	}
4084 }
4085 
4086 
4087 void
4088 BView::EnableLayoutInvalidation()
4089 {
4090 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4091 		fLayoutData->fLayoutInvalidationDisabled--;
4092 }
4093 
4094 
4095 void
4096 BView::DisableLayoutInvalidation()
4097 {
4098 	fLayoutData->fLayoutInvalidationDisabled++;
4099 }
4100 
4101 
4102 bool
4103 BView::IsLayoutValid() const
4104 {
4105 	return fLayoutData->fLayoutValid;
4106 }
4107 
4108 
4109 BLayoutContext*
4110 BView::LayoutContext() const
4111 {
4112 	return fLayoutData->fLayoutContext;
4113 }
4114 
4115 
4116 void
4117 BView::Layout(bool force)
4118 {
4119 	BLayoutContext context;
4120 	_Layout(force, &context);
4121 }
4122 
4123 
4124 void
4125 BView::Relayout()
4126 {
4127 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
4128 		fLayoutData->fNeedsRelayout = true;
4129 
4130 		// Layout() is recursive, that is if the parent view is currently laid
4131 		// out, we don't call layout() on this view, but wait for the parent's
4132 		// Layout() to do that for us.
4133 		if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
4134 			Layout(false);
4135 	}
4136 }
4137 
4138 
4139 void
4140 BView::DoLayout()
4141 {
4142 	if (fLayoutData->fLayout)
4143 		fLayoutData->fLayout->LayoutView();
4144 }
4145 
4146 
4147 void
4148 BView::_Layout(bool force, BLayoutContext* context)
4149 {
4150 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
4151 //printf("  fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
4152 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, fLayoutData->fLayoutInProgress);
4153 	if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
4154 		fLayoutData->fLayoutValid = false;
4155 
4156 		if (fLayoutData->fLayoutInProgress)
4157 			return;
4158 
4159 		BLayoutContext* oldContext = fLayoutData->fLayoutContext;
4160 		fLayoutData->fLayoutContext = context;
4161 
4162 		fLayoutData->fLayoutInProgress = true;
4163 		DoLayout();
4164 		fLayoutData->fLayoutInProgress = false;
4165 
4166 		fLayoutData->fLayoutValid = true;
4167 		fLayoutData->fNeedsRelayout = false;
4168 
4169 		// layout children
4170 		int32 childCount = CountChildren();
4171 		for (int32 i = 0; i < childCount; i++) {
4172 			BView* child = ChildAt(i);
4173 			if (!child->IsHidden(child))
4174 				child->_Layout(force, context);
4175 		}
4176 
4177 		fLayoutData->fLayoutContext = oldContext;
4178 
4179 		// invalidate the drawn content, if requested
4180 		if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
4181 			Invalidate();
4182 	}
4183 }
4184 
4185 
4186 //	#pragma mark - Private Functions
4187 
4188 
4189 void
4190 BView::_InitData(BRect frame, const char *name, uint32 resizingMode, uint32 flags)
4191 {
4192 	// Info: The name of the view is set by BHandler constructor
4193 
4194 	STRACE(("BView::InitData: enter\n"));
4195 
4196 	// initialize members
4197 	if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
4198 		printf("%s BView::InitData(): resizing mode or flags swapped\n", name);
4199 
4200 	// There are applications that swap the resize mask and the flags in the
4201 	// BView constructor. This does not cause problems under BeOS as it just
4202 	// ors the two fields to one 32bit flag.
4203 	// For now we do the same but print the above warning message.
4204 	// ToDo: this should be removed at some point and the original
4205 	// version restored:
4206 	// fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
4207 	fFlags = resizingMode | flags;
4208 
4209 	// handle rounding
4210 	frame.left = roundf(frame.left);
4211 	frame.top = roundf(frame.top);
4212 	frame.right = roundf(frame.right);
4213 	frame.bottom = roundf(frame.bottom);
4214 
4215 	fParentOffset.Set(frame.left, frame.top);
4216 
4217 	fOwner = NULL;
4218 	fParent = NULL;
4219 	fNextSibling = NULL;
4220 	fPreviousSibling = NULL;
4221 	fFirstChild = NULL;
4222 
4223 	fShowLevel = 0;
4224 	fTopLevelView = false;
4225 
4226 	cpicture = NULL;
4227 	comm = NULL;
4228 
4229 	fVerScroller = NULL;
4230 	fHorScroller = NULL;
4231 
4232 	f_is_printing = false;
4233 	fAttached = false;
4234 
4235 	fState = new BPrivate::ViewState;
4236 
4237 	fBounds = frame.OffsetToCopy(B_ORIGIN);
4238 	fShelf = NULL;
4239 
4240 	fEventMask = 0;
4241 	fEventOptions = 0;
4242 	fMouseEventOptions = 0;
4243 
4244 	fLayoutData = new LayoutData;
4245 }
4246 
4247 
4248 void
4249 BView::_RemoveCommArray()
4250 {
4251 	if (comm) {
4252 		delete [] comm->array;
4253 		delete comm;
4254 		comm = NULL;
4255 	}
4256 }
4257 
4258 
4259 void
4260 BView::_SetOwner(BWindow *newOwner)
4261 {
4262 	if (!newOwner)
4263 		_RemoveCommArray();
4264 
4265 	if (fOwner != newOwner && fOwner) {
4266 		if (fOwner->fFocus == this)
4267 			MakeFocus(false);
4268 
4269 		if (fOwner->fLastMouseMovedView == this)
4270 			fOwner->fLastMouseMovedView = NULL;
4271 
4272 		fOwner->RemoveHandler(this);
4273 		if (fShelf)
4274 			fOwner->RemoveHandler(fShelf);
4275 	}
4276 
4277 	if (newOwner && newOwner != fOwner) {
4278 		newOwner->AddHandler(this);
4279 		if (fShelf)
4280 			newOwner->AddHandler(fShelf);
4281 
4282 		if (fTopLevelView)
4283 			SetNextHandler(newOwner);
4284 		else
4285 			SetNextHandler(fParent);
4286 	}
4287 
4288 	fOwner = newOwner;
4289 
4290 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling)
4291 		child->_SetOwner(newOwner);
4292 }
4293 
4294 
4295 void
4296 BView::_ClipToPicture(BPicture *picture, BPoint where,
4297 	bool invert, bool sync)
4298 {
4299 	if (!picture)
4300 		return;
4301 
4302 	if (_CheckOwnerLockAndSwitchCurrent()) {
4303 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
4304 		fOwner->fLink->Attach<int32>(picture->Token());
4305 		fOwner->fLink->Attach<BPoint>(where);
4306 		fOwner->fLink->Attach<bool>(invert);
4307 
4308 		// TODO: I think that "sync" means another thing here:
4309 		// the bebook, at least, says so.
4310 		if (sync)
4311 			fOwner->fLink->Flush();
4312 
4313 		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
4314 	}
4315 
4316 	fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
4317 }
4318 
4319 
4320 bool
4321 BView::_RemoveChildFromList(BView* child)
4322 {
4323 	if (child->fParent != this)
4324 		return false;
4325 
4326 	if (fFirstChild == child) {
4327 		// it's the first view in the list
4328 		fFirstChild = child->fNextSibling;
4329 	} else {
4330 		// there must be a previous sibling
4331 		child->fPreviousSibling->fNextSibling = child->fNextSibling;
4332 	}
4333 
4334 	if (child->fNextSibling)
4335 		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
4336 
4337 	child->fParent = NULL;
4338 	child->fNextSibling = NULL;
4339 	child->fPreviousSibling = NULL;
4340 
4341 	return true;
4342 }
4343 
4344 
4345 bool
4346 BView::_AddChildToList(BView* child, BView* before)
4347 {
4348 	if (!child)
4349 		return false;
4350 	if (child->fParent != NULL) {
4351 		debugger("View already belongs to someone else");
4352 		return false;
4353 	}
4354 	if (before != NULL && before->fParent != this) {
4355 		debugger("Invalid before view");
4356 		return false;
4357 	}
4358 
4359 	if (before != NULL) {
4360 		// add view before this one
4361 		child->fNextSibling = before;
4362 		child->fPreviousSibling = before->fPreviousSibling;
4363 		if (child->fPreviousSibling != NULL)
4364 			child->fPreviousSibling->fNextSibling = child;
4365 
4366 		before->fPreviousSibling = child;
4367 		if (fFirstChild == before)
4368 			fFirstChild = child;
4369 	} else {
4370 		// add view to the end of the list
4371 		BView *last = fFirstChild;
4372 		while (last != NULL && last->fNextSibling != NULL) {
4373 			last = last->fNextSibling;
4374 		}
4375 
4376 		if (last != NULL) {
4377 			last->fNextSibling = child;
4378 			child->fPreviousSibling = last;
4379 		} else {
4380 			fFirstChild = child;
4381 			child->fPreviousSibling = NULL;
4382 		}
4383 
4384 		child->fNextSibling = NULL;
4385 	}
4386 
4387 	child->fParent = this;
4388 	return true;
4389 }
4390 
4391 
4392 /*!	\brief Creates the server counterpart of this view.
4393 	This is only done for views that are part of the view hierarchy, ie. when
4394 	they are attached to a window.
4395 	RemoveSelf() deletes the server object again.
4396 */
4397 bool
4398 BView::_CreateSelf()
4399 {
4400 	// AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
4401 	// current view mechanism via _CheckLockAndSwitchCurrent() - the token
4402 	// of the view and its parent are both send to the server.
4403 
4404 	if (fTopLevelView)
4405 		fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
4406 	else
4407  		fOwner->fLink->StartMessage(AS_VIEW_CREATE);
4408 
4409 	fOwner->fLink->Attach<int32>(_get_object_token_(this));
4410 	fOwner->fLink->AttachString(Name());
4411 	fOwner->fLink->Attach<BRect>(Frame());
4412 	fOwner->fLink->Attach<BPoint>(LeftTop());
4413 	fOwner->fLink->Attach<uint32>(ResizingMode());
4414 	fOwner->fLink->Attach<uint32>(fEventMask);
4415 	fOwner->fLink->Attach<uint32>(fEventOptions);
4416 	fOwner->fLink->Attach<uint32>(Flags());
4417 	fOwner->fLink->Attach<bool>(IsHidden(this));
4418 	fOwner->fLink->Attach<rgb_color>(fState->view_color);
4419 	if (fTopLevelView)
4420 		fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
4421 	else
4422 		fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
4423 	fOwner->fLink->Flush();
4424 
4425 	_CheckOwnerLockAndSwitchCurrent();
4426 	fState->UpdateServerState(*fOwner->fLink);
4427 
4428 	// we create all its children, too
4429 
4430 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4431 		child->_CreateSelf();
4432 	}
4433 
4434 	fOwner->fLink->Flush();
4435 	return true;
4436 }
4437 
4438 
4439 /*!
4440 	Sets the new view position.
4441 	It doesn't contact the server, though - the only case where this
4442 	is called outside of MoveTo() is as reaction of moving a view
4443 	in the server (a.k.a. B_WINDOW_RESIZED).
4444 	It also calls the BView's FrameMoved() hook.
4445 */
4446 void
4447 BView::_MoveTo(int32 x, int32 y)
4448 {
4449 	fParentOffset.Set(x, y);
4450 
4451 	if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
4452 		BMessage moved(B_VIEW_MOVED);
4453 		moved.AddInt64("when", system_time());
4454 		moved.AddPoint("where", BPoint(x, y));
4455 
4456 		BMessenger target(this);
4457 		target.SendMessage(&moved);
4458 	}
4459 }
4460 
4461 
4462 /*!
4463 	Computes the actual new frame size and recalculates the size of
4464 	the children as well.
4465 	It doesn't contact the server, though - the only case where this
4466 	is called outside of ResizeBy() is as reaction of resizing a view
4467 	in the server (a.k.a. B_WINDOW_RESIZED).
4468 	It also calls the BView's FrameResized() hook.
4469 */
4470 void
4471 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
4472 {
4473 	fBounds.right += deltaWidth;
4474 	fBounds.bottom += deltaHeight;
4475 
4476 	if (Window() == NULL) {
4477 		// we're not supposed to exercise the resizing code in case
4478 		// we haven't been attached to a window yet
4479 		return;
4480 	}
4481 
4482 	// layout the children
4483 	if (fFlags & B_SUPPORTS_LAYOUT) {
4484 		Relayout();
4485 	} else {
4486 		for (BView* child = fFirstChild; child; child = child->fNextSibling)
4487 			child->_ParentResizedBy(deltaWidth, deltaHeight);
4488 	}
4489 
4490 	if (fFlags & B_FRAME_EVENTS) {
4491 		BMessage resized(B_VIEW_RESIZED);
4492 		resized.AddInt64("when", system_time());
4493 		resized.AddFloat("width", fBounds.Width());
4494 		resized.AddFloat("height", fBounds.Height());
4495 
4496 		BMessenger target(this);
4497 		target.SendMessage(&resized);
4498 	}
4499 }
4500 
4501 
4502 /*!
4503 	Relayouts the view according to its resizing mode.
4504 */
4505 void
4506 BView::_ParentResizedBy(int32 x, int32 y)
4507 {
4508 	uint32 resizingMode = fFlags & _RESIZE_MASK_;
4509 	BRect newFrame = Frame();
4510 
4511 	// follow with left side
4512 	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
4513 		newFrame.left += x;
4514 	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
4515 		newFrame.left += x / 2;
4516 
4517 	// follow with right side
4518 	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
4519 		newFrame.right += x;
4520 	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
4521 		newFrame.right += x / 2;
4522 
4523 	// follow with top side
4524 	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
4525 		newFrame.top += y;
4526 	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
4527 		newFrame.top += y / 2;
4528 
4529 	// follow with bottom side
4530 	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
4531 		newFrame.bottom += y;
4532 	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
4533 		newFrame.bottom += y / 2;
4534 
4535 	if (newFrame.LeftTop() != fParentOffset) {
4536 		// move view
4537 		_MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
4538 	}
4539 
4540 	if (newFrame != Frame()) {
4541 		// resize view
4542 		int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
4543 		int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
4544 		_ResizeBy(widthDiff, heightDiff);
4545 	}
4546 }
4547 
4548 
4549 void
4550 BView::_Activate(bool active)
4551 {
4552 	WindowActivated(active);
4553 
4554 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4555 		child->_Activate(active);
4556 	}
4557 }
4558 
4559 
4560 void
4561 BView::_Attach()
4562 {
4563 	AttachedToWindow();
4564 	fAttached = true;
4565 
4566 	// after giving the view a chance to do this itself,
4567 	// check for the B_PULSE_NEEDED flag and make sure the
4568 	// window set's up the pulse messaging
4569 	if (fOwner) {
4570 		if (fFlags & B_PULSE_NEEDED) {
4571 			_CheckLock();
4572 			if (fOwner->fPulseRunner == NULL)
4573 				fOwner->SetPulseRate(fOwner->PulseRate());
4574 		}
4575 
4576 		if (!fOwner->IsHidden())
4577 			Invalidate();
4578 	}
4579 
4580 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) {
4581 		// we need to check for fAttached as new views could have been
4582 		// added in AttachedToWindow() - and those are already attached
4583 		if (!child->fAttached)
4584 			child->_Attach();
4585 	}
4586 
4587 	AllAttached();
4588 }
4589 
4590 
4591 void
4592 BView::_Detach()
4593 {
4594 	DetachedFromWindow();
4595 	fAttached = false;
4596 
4597 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) {
4598 		child->_Detach();
4599 	}
4600 
4601 	AllDetached();
4602 
4603 	if (fOwner) {
4604 		_CheckLock();
4605 
4606 		if (!fOwner->IsHidden())
4607 			Invalidate();
4608 
4609 		// make sure our owner doesn't need us anymore
4610 
4611 		if (fOwner->CurrentFocus() == this) {
4612 			MakeFocus(false);
4613 			// MakeFocus() is virtual and might not be
4614 			// passing through to the BView version,
4615 			// but we need to make sure at this point
4616 			// that we are not the focus view anymore.
4617 			if (fOwner->CurrentFocus() == this)
4618 				fOwner->_SetFocus(NULL, true);
4619 		}
4620 
4621 		if (fOwner->fDefaultButton == this)
4622 			fOwner->SetDefaultButton(NULL);
4623 
4624 		if (fOwner->fKeyMenuBar == this)
4625 			fOwner->fKeyMenuBar = NULL;
4626 
4627 		if (fOwner->fLastMouseMovedView == this)
4628 			fOwner->fLastMouseMovedView = NULL;
4629 
4630 		if (fOwner->fLastViewToken == _get_object_token_(this))
4631 			fOwner->fLastViewToken = B_NULL_TOKEN;
4632 
4633 		_SetOwner(NULL);
4634 	}
4635 }
4636 
4637 
4638 void
4639 BView::_Draw(BRect updateRect)
4640 {
4641 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
4642 		return;
4643 
4644 	// NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
4645 	// -> View is simply not drawn at all
4646 
4647 	_SwitchServerCurrentView();
4648 
4649 	ConvertFromScreen(&updateRect);
4650 	updateRect = Bounds() & updateRect;
4651 
4652 	// TODO: make states robust (the hook implementation could
4653 	// mess things up if it uses non-matching Push- and PopState(),
4654 	// we would not be guaranteed to still have the same state on
4655 	// the stack after having called Draw())
4656 	PushState();
4657 	Draw(updateRect);
4658 	PopState();
4659 	Flush();
4660 }
4661 
4662 void
4663 BView::_DrawAfterChildren(BRect updateRect)
4664 {
4665 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
4666 		|| !(Flags() & B_DRAW_ON_CHILDREN))
4667 		return;
4668 
4669 	_SwitchServerCurrentView();
4670 
4671 	ConvertFromScreen(&updateRect);
4672 	updateRect = Bounds() & updateRect;
4673 
4674 	// TODO: make states robust (see above)
4675 	PushState();
4676 	DrawAfterChildren(updateRect);
4677 	PopState();
4678 	Flush();
4679 }
4680 
4681 
4682 void
4683 BView::_Pulse()
4684 {
4685 	if (Flags() & B_PULSE_NEEDED)
4686 		Pulse();
4687 
4688 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4689 		child->_Pulse();
4690 	}
4691 }
4692 
4693 
4694 void
4695 BView::_UpdateStateForRemove()
4696 {
4697 	// TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
4698 	if (!_CheckOwnerLockAndSwitchCurrent())
4699 		return;
4700 
4701 	fState->UpdateFrom(*fOwner->fLink);
4702 //	if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
4703 //		fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
4704 //
4705 //		status_t code;
4706 //		if (fOwner->fLink->FlushWithReply(code) == B_OK
4707 //			&& code == B_OK) {
4708 //			fOwner->fLink->Read<BPoint>(&fParentOffset);
4709 //			fOwner->fLink->Read<BRect>(&fBounds);
4710 //			fState->valid_flags |= B_VIEW_FRAME_BIT;
4711 //		}
4712 //	}
4713 
4714 	// update children as well
4715 
4716 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4717 		if (child->fOwner)
4718 			child->_UpdateStateForRemove();
4719 	}
4720 }
4721 
4722 
4723 inline void
4724 BView::_UpdatePattern(::pattern pattern)
4725 {
4726 	if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
4727 		return;
4728 
4729 	if (fOwner) {
4730 		_CheckLockAndSwitchCurrent();
4731 
4732 		fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
4733 		fOwner->fLink->Attach< ::pattern>(pattern);
4734 
4735 		fState->valid_flags |= B_VIEW_PATTERN_BIT;
4736 	}
4737 
4738 	fState->pattern = pattern;
4739 }
4740 
4741 
4742 void
4743 BView::_FlushIfNotInTransaction()
4744 {
4745 	if (!fOwner->fInTransaction) {
4746 		fOwner->Flush();
4747 	}
4748 }
4749 
4750 
4751 BShelf *
4752 BView::_Shelf() const
4753 {
4754 	return fShelf;
4755 }
4756 
4757 
4758 void
4759 BView::_SetShelf(BShelf *shelf)
4760 {
4761 	if (fShelf != NULL && fOwner != NULL)
4762 		fOwner->RemoveHandler(fShelf);
4763 
4764 	fShelf = shelf;
4765 
4766 	if (fShelf != NULL && fOwner != NULL)
4767 		fOwner->AddHandler(fShelf);
4768 }
4769 
4770 
4771 status_t
4772 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect,
4773 	BRect dstRect, uint32 followFlags, uint32 options)
4774 {
4775 	if (!_CheckOwnerLockAndSwitchCurrent())
4776 		return B_ERROR;
4777 
4778 	int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
4779 
4780 	fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
4781 	fOwner->fLink->Attach<int32>(serverToken);
4782 	fOwner->fLink->Attach<BRect>(srcRect);
4783 	fOwner->fLink->Attach<BRect>(dstRect);
4784 	fOwner->fLink->Attach<int32>(followFlags);
4785 	fOwner->fLink->Attach<int32>(options);
4786 
4787 	status_t status = B_ERROR;
4788 	fOwner->fLink->FlushWithReply(status);
4789 
4790 	return status;
4791 }
4792 
4793 
4794 bool
4795 BView::_CheckOwnerLockAndSwitchCurrent() const
4796 {
4797 	STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()...", Name()));
4798 
4799 	if (fOwner == NULL) {
4800 		debugger("View method requires owner and doesn't have one.");
4801 		return false;
4802 	}
4803 
4804 	_CheckLockAndSwitchCurrent();
4805 
4806 	return true;
4807 }
4808 
4809 
4810 bool
4811 BView::_CheckOwnerLock() const
4812 {
4813 	if (fOwner) {
4814 		fOwner->check_lock();
4815 		return true;
4816 	} else {
4817 		debugger("View method requires owner and doesn't have one.");
4818 		return false;
4819 	}
4820 }
4821 
4822 
4823 void
4824 BView::_CheckLockAndSwitchCurrent() const
4825 {
4826 	STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()...", Name() ? Name(): "NULL"));
4827 
4828 	if (!fOwner)
4829 		return;
4830 
4831 	fOwner->check_lock();
4832 
4833 	_SwitchServerCurrentView();
4834 }
4835 
4836 
4837 void
4838 BView::_CheckLock() const
4839 {
4840 	if (fOwner)
4841 		fOwner->check_lock();
4842 }
4843 
4844 
4845 void
4846 BView::_SwitchServerCurrentView() const
4847 {
4848 	int32 serverToken = _get_object_token_(this);
4849 
4850 	if (fOwner->fLastViewToken != serverToken) {
4851 		STRACE(("contacting app_server... sending token: %ld\n", serverToken));
4852 		fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
4853 		fOwner->fLink->Attach<int32>(serverToken);
4854 
4855 		fOwner->fLastViewToken = serverToken;
4856 	} else {
4857 		STRACE(("quiet2\n"));
4858 	}
4859 }
4860 
4861 
4862 extern "C" void _ReservedView1__5BView() {}
4863 extern "C" void _ReservedView2__5BView() {}
4864 extern "C" void _ReservedView3__5BView() {}
4865 extern "C" void _ReservedView4__5BView() {}
4866 extern "C" void _ReservedView5__5BView() {}
4867 extern "C" void _ReservedView6__5BView() {}
4868 extern "C" void _ReservedView7__5BView() {}
4869 extern "C" void _ReservedView8__5BView() {}
4870 extern "C" void _ReservedView9__5BView() {}
4871 extern "C" void _ReservedView10__5BView() {}
4872 void BView::_ReservedView11(){}
4873 void BView::_ReservedView12(){}
4874 void BView::_ReservedView13(){}
4875 void BView::_ReservedView14(){}
4876 void BView::_ReservedView15(){}
4877 void BView::_ReservedView16(){}
4878 
4879 
4880 BView::BView(const BView &other)
4881 	: BHandler()
4882 {
4883 	// this is private and not functional, but exported
4884 }
4885 
4886 
4887 BView &
4888 BView::operator=(const BView &other)
4889 {
4890 	// this is private and not functional, but exported
4891 	return *this;
4892 }
4893 
4894 
4895 void
4896 BView::_PrintToStream()
4897 {
4898 	printf("BView::_PrintToStream()\n");
4899 	printf("\tName: %s\n"
4900 		"\tParent: %s\n"
4901 		"\tFirstChild: %s\n"
4902 		"\tNextSibling: %s\n"
4903 		"\tPrevSibling: %s\n"
4904 		"\tOwner(Window): %s\n"
4905 		"\tToken: %ld\n"
4906 		"\tFlags: %ld\n"
4907 		"\tView origin: (%f,%f)\n"
4908 		"\tView Bounds rectangle: (%f,%f,%f,%f)\n"
4909 		"\tShow level: %d\n"
4910 		"\tTopView?: %s\n"
4911 		"\tBPicture: %s\n"
4912 		"\tVertical Scrollbar %s\n"
4913 		"\tHorizontal Scrollbar %s\n"
4914 		"\tIs Printing?: %s\n"
4915 		"\tShelf?: %s\n"
4916 		"\tEventMask: %ld\n"
4917 		"\tEventOptions: %ld\n",
4918 	Name(),
4919 	fParent ? fParent->Name() : "NULL",
4920 	fFirstChild ? fFirstChild->Name() : "NULL",
4921 	fNextSibling ? fNextSibling->Name() : "NULL",
4922 	fPreviousSibling ? fPreviousSibling->Name() : "NULL",
4923 	fOwner ? fOwner->Name() : "NULL",
4924 	_get_object_token_(this),
4925 	fFlags,
4926 	fParentOffset.x, fParentOffset.y,
4927 	fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
4928 	fShowLevel,
4929 	fTopLevelView ? "YES" : "NO",
4930 	cpicture? "YES" : "NULL",
4931 	fVerScroller? "YES" : "NULL",
4932 	fHorScroller? "YES" : "NULL",
4933 	f_is_printing? "YES" : "NO",
4934 	fShelf? "YES" : "NO",
4935 	fEventMask,
4936 	fEventOptions);
4937 
4938 	printf("\tState status:\n"
4939 		"\t\tLocalCoordianteSystem: (%f,%f)\n"
4940 		"\t\tPenLocation: (%f,%f)\n"
4941 		"\t\tPenSize: %f\n"
4942 		"\t\tHighColor: [%d,%d,%d,%d]\n"
4943 		"\t\tLowColor: [%d,%d,%d,%d]\n"
4944 		"\t\tViewColor: [%d,%d,%d,%d]\n"
4945 		"\t\tPattern: %llx\n"
4946 		"\t\tDrawingMode: %d\n"
4947 		"\t\tLineJoinMode: %d\n"
4948 		"\t\tLineCapMode: %d\n"
4949 		"\t\tMiterLimit: %f\n"
4950 		"\t\tAlphaSource: %d\n"
4951 		"\t\tAlphaFuntion: %d\n"
4952 		"\t\tScale: %f\n"
4953 		"\t\t(Print)FontAliasing: %s\n"
4954 		"\t\tFont Info:\n",
4955 	fState->origin.x, fState->origin.y,
4956 	fState->pen_location.x, fState->pen_location.y,
4957 	fState->pen_size,
4958 	fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
4959 	fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
4960 	fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
4961 	*((uint64*)&(fState->pattern)),
4962 	fState->drawing_mode,
4963 	fState->line_join,
4964 	fState->line_cap,
4965 	fState->miter_limit,
4966 	fState->alpha_source_mode,
4967 	fState->alpha_function_mode,
4968 	fState->scale,
4969 	fState->font_aliasing? "YES" : "NO");
4970 
4971 	fState->font.PrintToStream();
4972 
4973 	// TODO: also print the line array.
4974 }
4975 
4976 
4977 void
4978 BView::_PrintTree()
4979 {
4980 	int32 spaces = 2;
4981 	BView *c = fFirstChild; //c = short for: current
4982 	printf( "'%s'\n", Name() );
4983 	if (c != NULL) {
4984 		while(true) {
4985 			// action block
4986 			{
4987 				for (int i = 0; i < spaces; i++)
4988 					printf(" ");
4989 
4990 				printf( "'%s'\n", c->Name() );
4991 			}
4992 
4993 			// go deep
4994 			if (c->fFirstChild) {
4995 				c = c->fFirstChild;
4996 				spaces += 2;
4997 			} else {
4998 				// go right
4999 				if (c->fNextSibling) {
5000 					c = c->fNextSibling;
5001 				} else {
5002 					// go up
5003 					while (!c->fParent->fNextSibling && c->fParent != this) {
5004 						c = c->fParent;
5005 						spaces -= 2;
5006 					}
5007 
5008 					// that enough! We've reached this view.
5009 					if (c->fParent == this)
5010 						break;
5011 
5012 					c = c->fParent->fNextSibling;
5013 					spaces -= 2;
5014 				}
5015 			}
5016 		}
5017 	}
5018 }
5019 
5020 
5021