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