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