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