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