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