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