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