xref: /haiku/src/kits/interface/View.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 	STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name()));
1136 }
1137 
1138 
1139 void
1140 BView::FrameMoved(BPoint newPosition)
1141 {
1142 	// Hook function
1143 	STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name()));
1144 }
1145 
1146 
1147 void
1148 BView::FrameResized(float newWidth, float newHeight)
1149 {
1150 	// Hook function
1151 	STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name()));
1152 }
1153 
1154 
1155 void
1156 BView::GetPreferredSize(float* _width, float* _height)
1157 {
1158 	STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name()));
1159 
1160 	*_width = fBounds.Width();
1161 	*_height = fBounds.Height();
1162 }
1163 
1164 
1165 void
1166 BView::ResizeToPreferred()
1167 {
1168 	STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name()));
1169 
1170 	float width;
1171 	float height;
1172 	GetPreferredSize(&width, &height);
1173 
1174 	ResizeTo(width, height);
1175 }
1176 
1177 
1178 void
1179 BView::KeyDown(const char* bytes, int32 numBytes)
1180 {
1181 	// Hook function
1182 	STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name()));
1183 
1184 	if (Window())
1185 		Window()->_KeyboardNavigation();
1186 }
1187 
1188 
1189 void
1190 BView::KeyUp(const char* bytes, int32 numBytes)
1191 {
1192 	// Hook function
1193 	STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name()));
1194 }
1195 
1196 
1197 void
1198 BView::MouseDown(BPoint where)
1199 {
1200 	// Hook function
1201 	STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name()));
1202 }
1203 
1204 
1205 void
1206 BView::MouseUp(BPoint where)
1207 {
1208 	// Hook function
1209 	STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name()));
1210 }
1211 
1212 
1213 void
1214 BView::MouseMoved(BPoint where, uint32 code, const BMessage* a_message)
1215 {
1216 	// Hook function
1217 	STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name()));
1218 }
1219 
1220 
1221 void
1222 BView::Pulse()
1223 {
1224 	// Hook function
1225 	STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name()));
1226 }
1227 
1228 
1229 void
1230 BView::TargetedByScrollView(BScrollView* scroll_view)
1231 {
1232 	// Hook function
1233 	STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name()));
1234 }
1235 
1236 
1237 void
1238 BView::WindowActivated(bool state)
1239 {
1240 	// Hook function
1241 	STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name()));
1242 }
1243 
1244 
1245 //	#pragma mark -
1246 //	Input Functions
1247 
1248 
1249 void
1250 BView::BeginRectTracking(BRect startRect, uint32 style)
1251 {
1252 	if (do_owner_check()) {
1253 		fOwner->fLink->StartMessage(AS_LAYER_BEGIN_RECT_TRACK);
1254 		fOwner->fLink->Attach<BRect>(startRect);
1255 		fOwner->fLink->Attach<int32>(style);
1256 	}
1257 }
1258 
1259 
1260 void
1261 BView::EndRectTracking()
1262 {
1263 	if (do_owner_check())
1264 		fOwner->fLink->StartMessage(AS_LAYER_END_RECT_TRACK);
1265 }
1266 
1267 
1268 void
1269 BView::DragMessage(BMessage *message, BRect dragRect, BHandler *replyTo)
1270 {
1271 	if (!message)
1272 		return;
1273 
1274 	do_owner_check_no_pick();
1275 
1276 	// calculate the offset
1277 	BPoint offset;
1278 	uint32 buttons;
1279 	BMessage *current = fOwner->CurrentMessage();
1280 	if (!current || current->FindPoint("be:view_where", &offset) != B_OK)
1281 		GetMouse(&offset, &buttons, false);
1282 	offset -= dragRect.LeftTop();
1283 
1284 	if (!dragRect.IsValid()) {
1285 		DragMessage(message, NULL, B_OP_BLEND, offset, replyTo);
1286 		return;
1287 	}
1288 
1289 	// TODO: that's not really what should happen - the app_server should take the chance
1290 	//	*NOT* to need to drag a whole bitmap around but just a frame.
1291 
1292 	// create a drag bitmap for the rect
1293 	BBitmap *bitmap = new BBitmap(dragRect, B_RGBA32);
1294 	uint32 *bits = (uint32*)bitmap->Bits();
1295 	uint32 bytesPerRow = bitmap->BytesPerRow();
1296 	uint32 width = dragRect.IntegerWidth() + 1;
1297 	uint32 height = dragRect.IntegerHeight() + 1;
1298 	uint32 lastRow = (height - 1) * width;
1299 
1300 	memset(bits, 0x00, height * bytesPerRow);
1301 
1302 	// top
1303 	for (uint32 i = 0; i < width; i += 2)
1304 		bits[i] = 0xff000000;
1305 
1306 	// bottom
1307 	for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2)
1308 		bits[lastRow + i] = 0xff000000;
1309 
1310 	// left
1311 	for (uint32 i = 0; i < lastRow; i += width * 2)
1312 		bits[i] = 0xff000000;
1313 
1314 	// right
1315 	for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2)
1316 		bits[width - 1 + i] = 0xff000000;
1317 
1318 	DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo);
1319 }
1320 
1321 
1322 void
1323 BView::DragMessage(BMessage *message, BBitmap *image, BPoint offset,
1324 	BHandler *replyTo)
1325 {
1326 	DragMessage(message, image, B_OP_COPY, offset, replyTo);
1327 }
1328 
1329 
1330 void
1331 BView::DragMessage(BMessage *message, BBitmap *image,
1332 	drawing_mode dragMode, BPoint offset, BHandler *replyTo)
1333 {
1334 	if (message == NULL)
1335 		return;
1336 
1337 	if (image == NULL) {
1338 		// TODO: workaround for drags without a bitmap - should not be necessary if
1339 		//	we move the rectangle dragging into the app_server
1340 		image = new (nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32);
1341 		if (image == NULL)
1342 			return;
1343 	}
1344 
1345 	if (replyTo == NULL)
1346 		replyTo = this;
1347 
1348 	if (replyTo->Looper() == NULL)
1349 		debugger("DragMessage: warning - the Handler needs a looper");
1350 
1351 	do_owner_check_no_pick();
1352 
1353 	if (!message->HasInt32("buttons")) {
1354 		BMessage *msg = fOwner->CurrentMessage();
1355 		uint32 buttons;
1356 
1357 		if (msg == NULL || msg->FindInt32("buttons", (int32 *)&buttons) != B_OK) {
1358 			BPoint point;
1359 			GetMouse(&point, &buttons, false);
1360 		}
1361 
1362 		message->AddInt32("buttons", buttons);
1363 	}
1364 
1365 	BMessage::Private privateMessage(message);
1366 	privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper()));
1367 
1368 	// TODO: create area and flatten message into that area!
1369 	// send area info over port, not the actual message!
1370 	int32 bufferSize = privateMessage.NativeFlattenedSize();
1371 	char* buffer = new (nothrow) char[bufferSize];
1372 	if (buffer) {
1373 		privateMessage.NativeFlatten(buffer, bufferSize);
1374 
1375 		fOwner->fLink->StartMessage(AS_LAYER_DRAG_IMAGE);
1376 		fOwner->fLink->Attach<int32>(image->_ServerToken());
1377 		fOwner->fLink->Attach<int32>((int32)dragMode);
1378 		fOwner->fLink->Attach<BPoint>(offset);
1379 		fOwner->fLink->Attach<int32>(bufferSize);
1380 		fOwner->fLink->Attach(buffer, bufferSize);
1381 
1382 		// we need to wait for the server
1383 		// to actually process this message
1384 		// before we can delete the bitmap
1385 		int32 code;
1386 		fOwner->fLink->FlushWithReply(code);
1387 
1388 		delete [] buffer;
1389 	} else {
1390 		fprintf(stderr, "BView::DragMessage() - no memory to flatten drag message\n");
1391 	}
1392 
1393 	delete image;
1394 }
1395 
1396 
1397 void
1398 BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue)
1399 {
1400 	do_owner_check();
1401 
1402 	if (checkMessageQueue) {
1403 		Window()->UpdateIfNeeded();
1404 		BMessageQueue *queue = Window()->MessageQueue();
1405 		queue->Lock();
1406 
1407 		// Look out for mouse update messages
1408 
1409 		BMessage *message;
1410 		for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) {
1411 			switch (message->what) {
1412 				case B_MOUSE_MOVED:
1413 				case B_MOUSE_UP:
1414 				case B_MOUSE_DOWN:
1415 					bool deleteMessage;
1416 					if (!Window()->_StealMouseMessage(message, deleteMessage))
1417 						continue;
1418 
1419 					message->FindPoint("screen_where", location);
1420 					message->FindInt32("buttons", (int32 *)buttons);
1421 					queue->Unlock();
1422 						// we need to hold the queue lock until here, because
1423 						// the message might still be used for something else
1424 
1425 					ConvertFromScreen(location);
1426 
1427 					if (deleteMessage)
1428 						delete message;
1429 
1430 					return;
1431 			}
1432 		}
1433 		queue->Unlock();
1434 	}
1435 
1436 	// If no mouse update message has been found in the message queue,
1437 	// we get the current mouse location and buttons from the app_server
1438 
1439 	fOwner->fLink->StartMessage(AS_GET_MOUSE);
1440 
1441 	int32 code;
1442 	if (fOwner->fLink->FlushWithReply(code) == B_OK
1443 		&& code == B_OK) {
1444 		fOwner->fLink->Read<BPoint>(location);
1445 		fOwner->fLink->Read<uint32>(buttons);
1446 			// TODO: ServerWindow replies with an int32 here
1447 
1448 		ConvertFromScreen(location);
1449 			// TODO: in beos R5, location is already converted to the view local coordinate system,
1450 			// so if an app checks the window message queue by itself, it might not find what it expects.
1451 	} else
1452 		*buttons = 0;
1453 }
1454 
1455 
1456 void
1457 BView::MakeFocus(bool focusState)
1458 {
1459 	if (fOwner) {
1460 		// TODO: If this view has focus and focusState==false,
1461 		// will there really be no other view with focus? No
1462 		// cycling to the next one?
1463 		BView *focus = fOwner->CurrentFocus();
1464 		if (focusState) {
1465 			// Unfocus a previous focus view
1466 			if (focus && focus != this)
1467 				focus->MakeFocus(false);
1468 			// if we want to make this view the current focus view
1469 			fOwner->_SetFocus(this, true);
1470 		} else {
1471 			// we want to unfocus this view, but only if it actually has focus
1472 			if (focus == this) {
1473 				fOwner->_SetFocus(NULL, true);
1474 			}
1475 		}
1476 	}
1477 }
1478 
1479 
1480 BScrollBar *
1481 BView::ScrollBar(orientation posture) const
1482 {
1483 	switch (posture) {
1484 		case B_VERTICAL:
1485 			return fVerScroller;
1486 
1487 		case B_HORIZONTAL:
1488 			return fHorScroller;
1489 
1490 		default:
1491 			return NULL;
1492 	}
1493 }
1494 
1495 
1496 void
1497 BView::ScrollBy(float dh, float dv)
1498 {
1499 	// scrolling by fractional values is not supported, is it?
1500 	dh = roundf(dh);
1501 	dv = roundf(dv);
1502 
1503 	// no reason to process this further if no scroll is intended.
1504 	if (dh == 0 && dv == 0)
1505 		return;
1506 
1507 	check_lock();
1508 
1509 	// if we're attached to a window tell app_server about this change
1510 	if (fOwner) {
1511 		fOwner->fLink->StartMessage(AS_LAYER_SCROLL);
1512 		fOwner->fLink->Attach<float>(dh);
1513 		fOwner->fLink->Attach<float>(dv);
1514 
1515 		fOwner->fLink->Flush();
1516 
1517 		fState->valid_flags &= ~(B_VIEW_FRAME_BIT | B_VIEW_ORIGIN_BIT);
1518 	}
1519 
1520 	// we modify our bounds rectangle by dh/dv coord units hor/ver.
1521 	fBounds.OffsetBy(dh, dv);
1522 
1523 	// then set the new values of the scrollbars
1524 	if (fHorScroller)
1525 		fHorScroller->SetValue(fBounds.left);
1526 	if (fVerScroller)
1527 		fVerScroller->SetValue(fBounds.top);
1528 }
1529 
1530 
1531 void
1532 BView::ScrollTo(BPoint where)
1533 {
1534 	ScrollBy(where.x - fBounds.left, where.y - fBounds.top);
1535 }
1536 
1537 
1538 status_t
1539 BView::SetEventMask(uint32 mask, uint32 options)
1540 {
1541 	if (fEventMask == mask && fEventOptions == options)
1542 		return B_OK;
1543 
1544 	fEventMask = mask | (fEventMask & 0xFFFF0000);
1545 	fEventOptions = options;
1546 
1547 	fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT;
1548 
1549 	if (fOwner) {
1550 		check_lock();
1551 
1552 		fOwner->fLink->StartMessage(AS_LAYER_SET_EVENT_MASK);
1553 		fOwner->fLink->Attach<uint32>(mask);
1554 		fOwner->fLink->Attach<uint32>(options);
1555 	}
1556 
1557 	return B_OK;
1558 }
1559 
1560 
1561 uint32
1562 BView::EventMask()
1563 {
1564 	return fEventMask;
1565 }
1566 
1567 
1568 status_t
1569 BView::SetMouseEventMask(uint32 mask, uint32 options)
1570 {
1571 	// Just don't do anything if the view is not yet attached
1572 	// or we were called outside of BView::MouseDown()
1573 	if (fOwner != NULL
1574 		&& fOwner->CurrentMessage() != NULL
1575 		&& fOwner->CurrentMessage()->what == B_MOUSE_DOWN) {
1576 		check_lock();
1577 		fOwner->fLink->StartMessage(AS_LAYER_SET_MOUSE_EVENT_MASK);
1578 		fOwner->fLink->Attach<uint32>(mask);
1579 		fOwner->fLink->Attach<uint32>(options);
1580 
1581 		return B_OK;
1582 	}
1583 
1584 	return B_ERROR;
1585 }
1586 
1587 
1588 //	#pragma mark -
1589 //	Graphic State Functions
1590 
1591 
1592 void
1593 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit)
1594 {
1595 	if (fState->IsValid(B_VIEW_LINE_MODES_BIT)
1596 		&& lineCap == fState->line_cap && lineJoin == fState->line_join
1597 		&& miterLimit == fState->miter_limit)
1598 		return;
1599 
1600 	if (fOwner) {
1601 		check_lock();
1602 
1603 		fOwner->fLink->StartMessage(AS_LAYER_SET_LINE_MODE);
1604 		fOwner->fLink->Attach<int8>((int8)lineCap);
1605 		fOwner->fLink->Attach<int8>((int8)lineJoin);
1606 		fOwner->fLink->Attach<float>(miterLimit);
1607 
1608 		fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
1609 	}
1610 
1611 	fState->line_cap = lineCap;
1612 	fState->line_join = lineJoin;
1613 	fState->miter_limit = miterLimit;
1614 
1615 	fState->archiving_flags |= B_VIEW_LINE_MODES_BIT;
1616 }
1617 
1618 
1619 join_mode
1620 BView::LineJoinMode() const
1621 {
1622 	// This will update the current state, if necessary
1623 	if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
1624 		LineMiterLimit();
1625 
1626 	return fState->line_join;
1627 }
1628 
1629 
1630 cap_mode
1631 BView::LineCapMode() const
1632 {
1633 	// This will update the current state, if necessary
1634 	if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
1635 		LineMiterLimit();
1636 
1637 	return fState->line_cap;
1638 }
1639 
1640 
1641 float
1642 BView::LineMiterLimit() const
1643 {
1644 	if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) {
1645 		check_lock();
1646 
1647 		fOwner->fLink->StartMessage(AS_LAYER_GET_LINE_MODE);
1648 
1649 		int32 code;
1650 		if (fOwner->fLink->FlushWithReply(code) == B_OK
1651 			&& code == B_OK) {
1652 			int8 cap, join;
1653 			fOwner->fLink->Read<int8>((int8 *)&cap);
1654 			fOwner->fLink->Read<int8>((int8 *)&join);
1655 			fOwner->fLink->Read<float>(&fState->miter_limit);
1656 
1657 			fState->line_cap = (cap_mode)cap;
1658 			fState->line_join = (join_mode)join;
1659 		}
1660 
1661 		fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
1662 	}
1663 
1664 	return fState->miter_limit;
1665 }
1666 
1667 
1668 void
1669 BView::PushState()
1670 {
1671 	do_owner_check();
1672 
1673 	fOwner->fLink->StartMessage(AS_LAYER_PUSH_STATE);
1674 
1675 	// initialize origin and scale
1676 	fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT;
1677 	fState->scale = 1.0f;
1678 	fState->origin.Set(0, 0);
1679 }
1680 
1681 
1682 void
1683 BView::PopState()
1684 {
1685 	do_owner_check();
1686 
1687 	fOwner->fLink->StartMessage(AS_LAYER_POP_STATE);
1688 
1689 	// invalidate all flags (except those that are not part of pop/push)
1690 	fState->valid_flags = B_VIEW_VIEW_COLOR_BIT;
1691 }
1692 
1693 
1694 void
1695 BView::SetScale(float scale) const
1696 {
1697 	if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale)
1698 		return;
1699 
1700 	if (fOwner) {
1701 		check_lock();
1702 
1703 		fOwner->fLink->StartMessage(AS_LAYER_SET_SCALE);
1704 		fOwner->fLink->Attach<float>(scale);
1705 
1706 		fState->valid_flags |= B_VIEW_SCALE_BIT;
1707 	}
1708 
1709 	fState->scale = scale;
1710 	fState->archiving_flags |= B_VIEW_SCALE_BIT;
1711 }
1712 
1713 
1714 float
1715 BView::Scale() const
1716 {
1717 	if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) {
1718 		check_lock();
1719 
1720 		fOwner->fLink->StartMessage(AS_LAYER_GET_SCALE);
1721 
1722  		int32 code;
1723 		if (fOwner->fLink->FlushWithReply(code) == B_OK
1724 			&& code == B_OK)
1725 			fOwner->fLink->Read<float>(&fState->scale);
1726 
1727 		fState->valid_flags |= B_VIEW_SCALE_BIT;
1728 	}
1729 
1730 	return fState->scale;
1731 }
1732 
1733 
1734 void
1735 BView::SetDrawingMode(drawing_mode mode)
1736 {
1737 	if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT)
1738 		&& mode == fState->drawing_mode)
1739 		return;
1740 
1741 	if (fOwner) {
1742 		check_lock();
1743 
1744 		fOwner->fLink->StartMessage(AS_LAYER_SET_DRAWING_MODE);
1745 		fOwner->fLink->Attach<int8>((int8)mode);
1746 
1747 		fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
1748 	}
1749 
1750 	fState->drawing_mode = mode;
1751 	fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT;
1752 }
1753 
1754 
1755 drawing_mode
1756 BView::DrawingMode() const
1757 {
1758 	if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) {
1759 		check_lock();
1760 
1761 		fOwner->fLink->StartMessage(AS_LAYER_GET_DRAWING_MODE);
1762 
1763 		int32 code;
1764 		if (fOwner->fLink->FlushWithReply(code) == B_OK
1765 			&& code == B_OK) {
1766 			int8 drawingMode;
1767 			fOwner->fLink->Read<int8>(&drawingMode);
1768 
1769 			fState->drawing_mode = (drawing_mode)drawingMode;
1770 			fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
1771 		}
1772 	}
1773 
1774 	return fState->drawing_mode;
1775 }
1776 
1777 
1778 void
1779 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction)
1780 {
1781 	if (fState->IsValid(B_VIEW_BLENDING_BIT)
1782 		&& sourceAlpha == fState->alpha_source_mode
1783 		&& alphaFunction == fState->alpha_function_mode)
1784 		return;
1785 
1786 	if (fOwner) {
1787 		check_lock();
1788 
1789 		fOwner->fLink->StartMessage(AS_LAYER_SET_BLENDING_MODE);
1790 		fOwner->fLink->Attach<int8>((int8)sourceAlpha);
1791 		fOwner->fLink->Attach<int8>((int8)alphaFunction);
1792 
1793 		fState->valid_flags |= B_VIEW_BLENDING_BIT;
1794 	}
1795 
1796 	fState->alpha_source_mode = sourceAlpha;
1797 	fState->alpha_function_mode = alphaFunction;
1798 
1799 	fState->archiving_flags |= B_VIEW_BLENDING_BIT;
1800 }
1801 
1802 
1803 void
1804 BView::GetBlendingMode(source_alpha *_sourceAlpha,
1805 	alpha_function *_alphaFunction) const
1806 {
1807 	if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) {
1808 		check_lock();
1809 
1810 		fOwner->fLink->StartMessage(AS_LAYER_GET_BLENDING_MODE);
1811 
1812 		int32 code;
1813  		if (fOwner->fLink->FlushWithReply(code) == B_OK
1814  			&& code == B_OK) {
1815 			int8 alphaSourceMode, alphaFunctionMode;
1816 			fOwner->fLink->Read<int8>(&alphaSourceMode);
1817 			fOwner->fLink->Read<int8>(&alphaFunctionMode);
1818 
1819 			fState->alpha_source_mode = (source_alpha)alphaSourceMode;
1820 			fState->alpha_function_mode = (alpha_function)alphaFunctionMode;
1821 
1822 			fState->valid_flags |= B_VIEW_BLENDING_BIT;
1823 		}
1824 	}
1825 
1826 	if (_sourceAlpha)
1827 		*_sourceAlpha = fState->alpha_source_mode;
1828 
1829 	if (_alphaFunction)
1830 		*_alphaFunction = fState->alpha_function_mode;
1831 }
1832 
1833 
1834 void
1835 BView::MovePenTo(BPoint point)
1836 {
1837 	MovePenTo(point.x, point.y);
1838 }
1839 
1840 
1841 void
1842 BView::MovePenTo(float x, float y)
1843 {
1844 	if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT)
1845 		&& x == fState->pen_location.x && y == fState->pen_location.y)
1846 		return;
1847 
1848 	if (fOwner) {
1849 		check_lock();
1850 
1851 		fOwner->fLink->StartMessage(AS_LAYER_SET_PEN_LOC);
1852 		fOwner->fLink->Attach<float>(x);
1853 		fOwner->fLink->Attach<float>(y);
1854 
1855 		fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
1856 	}
1857 
1858 	fState->pen_location.x = x;
1859 	fState->pen_location.y = y;
1860 
1861 	fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT;
1862 }
1863 
1864 
1865 void
1866 BView::MovePenBy(float x, float y)
1867 {
1868 	// this will update the pen location if necessary
1869 	if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT))
1870 		PenLocation();
1871 
1872 	MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y);
1873 }
1874 
1875 
1876 BPoint
1877 BView::PenLocation() const
1878 {
1879 	if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) {
1880 		check_lock();
1881 
1882 		fOwner->fLink->StartMessage(AS_LAYER_GET_PEN_LOC);
1883 
1884 		int32 code;
1885 		if (fOwner->fLink->FlushWithReply(code) == B_OK
1886 			&& code == B_OK) {
1887 			fOwner->fLink->Read<BPoint>(&fState->pen_location);
1888 
1889 			fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
1890 		}
1891 	}
1892 
1893 	return fState->pen_location;
1894 }
1895 
1896 
1897 void
1898 BView::SetPenSize(float size)
1899 {
1900 	if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size)
1901 		return;
1902 
1903 	if (fOwner) {
1904 		check_lock();
1905 
1906 		fOwner->fLink->StartMessage(AS_LAYER_SET_PEN_SIZE);
1907 		fOwner->fLink->Attach<float>(size);
1908 
1909 		fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
1910 	}
1911 
1912 	fState->pen_size = size;
1913 	fState->archiving_flags	|= B_VIEW_PEN_SIZE_BIT;
1914 }
1915 
1916 
1917 float
1918 BView::PenSize() const
1919 {
1920 	if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) {
1921 		check_lock();
1922 
1923 		fOwner->fLink->StartMessage(AS_LAYER_GET_PEN_SIZE);
1924 
1925 		int32 code;
1926 		if (fOwner->fLink->FlushWithReply(code) == B_OK
1927 			&& code == B_OK) {
1928 			fOwner->fLink->Read<float>(&fState->pen_size);
1929 
1930 			fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
1931 		}
1932 	}
1933 
1934 	return fState->pen_size;
1935 }
1936 
1937 
1938 void
1939 BView::SetHighColor(rgb_color color)
1940 {
1941 	// are we up-to-date already?
1942 	if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT)
1943 		&& fState->high_color == color)
1944 		return;
1945 
1946 	if (fOwner) {
1947 		check_lock();
1948 
1949 		fOwner->fLink->StartMessage(AS_LAYER_SET_HIGH_COLOR);
1950 		fOwner->fLink->Attach<rgb_color>(color);
1951 
1952 		fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
1953 	}
1954 
1955 	fState->high_color = color;
1956 
1957 	fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT;
1958 }
1959 
1960 
1961 rgb_color
1962 BView::HighColor() const
1963 {
1964 	if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) {
1965 		check_lock();
1966 
1967 		fOwner->fLink->StartMessage(AS_LAYER_GET_HIGH_COLOR);
1968 
1969 		int32 code;
1970 		if (fOwner->fLink->FlushWithReply(code) == B_OK
1971 			&& code == B_OK) {
1972 			fOwner->fLink->Read<rgb_color>(&fState->high_color);
1973 
1974 			fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
1975 		}
1976 	}
1977 
1978 	return fState->high_color;
1979 }
1980 
1981 
1982 void
1983 BView::SetLowColor(rgb_color color)
1984 {
1985 	if (fState->IsValid(B_VIEW_LOW_COLOR_BIT)
1986 		&& fState->low_color == color)
1987 		return;
1988 
1989 	if (fOwner) {
1990 		check_lock();
1991 
1992 		fOwner->fLink->StartMessage(AS_LAYER_SET_LOW_COLOR);
1993 		fOwner->fLink->Attach<rgb_color>(color);
1994 
1995 		fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
1996 	}
1997 
1998 	fState->low_color = color;
1999 
2000 	fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT;
2001 }
2002 
2003 
2004 rgb_color
2005 BView::LowColor() const
2006 {
2007 	if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) {
2008 		check_lock();
2009 
2010 		fOwner->fLink->StartMessage(AS_LAYER_GET_LOW_COLOR);
2011 
2012 		int32 code;
2013 		if (fOwner->fLink->FlushWithReply(code) == B_OK
2014 			&& code == B_OK) {
2015 			fOwner->fLink->Read<rgb_color>(&fState->low_color);
2016 
2017 			fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2018 		}
2019 	}
2020 
2021 	return fState->low_color;
2022 }
2023 
2024 
2025 void
2026 BView::SetViewColor(rgb_color color)
2027 {
2028 	if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color)
2029 		return;
2030 
2031 	if (fOwner) {
2032 		check_lock();
2033 
2034 		fOwner->fLink->StartMessage(AS_LAYER_SET_VIEW_COLOR);
2035 		fOwner->fLink->Attach<rgb_color>(color);
2036 
2037 		fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2038 	}
2039 
2040 	fState->view_color = color;
2041 
2042 	fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT;
2043 }
2044 
2045 
2046 rgb_color
2047 BView::ViewColor() const
2048 {
2049 	if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) {
2050 		check_lock();
2051 
2052 		fOwner->fLink->StartMessage(AS_LAYER_GET_VIEW_COLOR);
2053 
2054 		int32 code;
2055 		if (fOwner->fLink->FlushWithReply(code) == B_OK
2056 			&& code == B_OK) {
2057 			fOwner->fLink->Read<rgb_color>(&fState->view_color);
2058 
2059 			fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2060 		}
2061 	}
2062 
2063 	return fState->view_color;
2064 }
2065 
2066 
2067 void
2068 BView::ForceFontAliasing(bool enable)
2069 {
2070 	if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) && enable == fState->font_aliasing)
2071 		return;
2072 
2073 	if (fOwner) {
2074 		check_lock();
2075 
2076 		fOwner->fLink->StartMessage(AS_LAYER_PRINT_ALIASING);
2077 		fOwner->fLink->Attach<bool>(enable);
2078 
2079 		fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT;
2080 	}
2081 
2082 	fState->font_aliasing = enable;
2083 	fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT;
2084 }
2085 
2086 
2087 void
2088 BView::SetFont(const BFont* font, uint32 mask)
2089 {
2090 	if (!font || mask == 0)
2091 		return;
2092 
2093 	if (mask == B_FONT_ALL) {
2094 		fState->font = *font;
2095 	} else {
2096 		// ToDo: move this into a BFont method
2097 		if (mask & B_FONT_FAMILY_AND_STYLE)
2098 			fState->font.SetFamilyAndStyle(font->FamilyAndStyle());
2099 
2100 		if (mask & B_FONT_SIZE)
2101 			fState->font.SetSize(font->Size());
2102 
2103 		if (mask & B_FONT_SHEAR)
2104 			fState->font.SetShear(font->Shear());
2105 
2106 		if (mask & B_FONT_ROTATION)
2107 			fState->font.SetRotation(font->Rotation());
2108 
2109 		if (mask & B_FONT_FALSE_BOLD_WIDTH)
2110 			fState->font.SetFalseBoldWidth(font->FalseBoldWidth());
2111 
2112 		if (mask & B_FONT_SPACING)
2113 			fState->font.SetSpacing(font->Spacing());
2114 
2115 		if (mask & B_FONT_ENCODING)
2116 			fState->font.SetEncoding(font->Encoding());
2117 
2118 		if (mask & B_FONT_FACE)
2119 			fState->font.SetFace(font->Face());
2120 
2121 		if (mask & B_FONT_FLAGS)
2122 			fState->font.SetFlags(font->Flags());
2123 	}
2124 
2125 	fState->font_flags |= mask;
2126 
2127 	if (fOwner) {
2128 		check_lock();
2129 		do_owner_check();
2130 
2131 		fState->UpdateServerFontState(*fOwner->fLink);
2132 	}
2133 }
2134 
2135 
2136 #if !_PR3_COMPATIBLE_
2137 void
2138 BView::GetFont(BFont *font) const
2139 #else
2140 void
2141 BView:GetFont(BFont *font)
2142 #endif
2143 {
2144 	*font = fState->font;
2145 }
2146 
2147 
2148 void
2149 BView::GetFontHeight(font_height *height) const
2150 {
2151 	fState->font.GetHeight(height);
2152 }
2153 
2154 
2155 void
2156 BView::SetFontSize(float size)
2157 {
2158 	BFont font;
2159 	font.SetSize(size);
2160 
2161 	SetFont(&font, B_FONT_SIZE);
2162 }
2163 
2164 
2165 float
2166 BView::StringWidth(const char *string) const
2167 {
2168 	return fState->font.StringWidth(string);
2169 }
2170 
2171 
2172 float
2173 BView::StringWidth(const char* string, int32 length) const
2174 {
2175 	return fState->font.StringWidth(string, length);
2176 }
2177 
2178 
2179 void
2180 BView::GetStringWidths(char *stringArray[],int32 lengthArray[],
2181 	int32 numStrings, float widthArray[]) const
2182 {
2183 	fState->font.GetStringWidths(const_cast<const char **>(stringArray),
2184 		const_cast<const int32 *>(lengthArray), numStrings, widthArray);
2185 }
2186 
2187 
2188 void
2189 BView::TruncateString(BString *in_out, uint32 mode, float width) const
2190 {
2191 	fState->font.TruncateString(in_out, mode, width);
2192 }
2193 
2194 
2195 void
2196 BView::ClipToPicture(BPicture *picture, BPoint where, bool sync)
2197 {
2198 	DoPictureClip(picture, where, false, sync);
2199 }
2200 
2201 
2202 void
2203 BView::ClipToInversePicture(BPicture *picture,
2204 	BPoint where, bool sync)
2205 {
2206 	DoPictureClip(picture, where, true, sync);
2207 }
2208 
2209 
2210 void
2211 BView::GetClippingRegion(BRegion* region) const
2212 {
2213 	if (!region)
2214 		return;
2215 
2216 	// NOTE: the client has no idea when the clipping in the server
2217 	// changed, so it is always read from the serber
2218 	region->MakeEmpty();
2219 
2220 	if (fOwner && do_owner_check()) {
2221 		fOwner->fLink->StartMessage(AS_LAYER_GET_CLIP_REGION);
2222 
2223  		int32 code;
2224  		if (fOwner->fLink->FlushWithReply(code) == B_OK
2225  			&& code == B_OK) {
2226 			int32 count;
2227 			fOwner->fLink->Read<int32>(&count);
2228 
2229 			for (int32 i = 0; i < count; i++) {
2230 				BRect rect;
2231 				fOwner->fLink->Read<BRect>(&rect);
2232 
2233 				region->Include(rect);
2234 			}
2235 			fState->valid_flags |= B_VIEW_CLIP_REGION_BIT;
2236 		}
2237 	}
2238 }
2239 
2240 
2241 void
2242 BView::ConstrainClippingRegion(BRegion* region)
2243 {
2244 	if (do_owner_check()) {
2245 
2246 		fOwner->fLink->StartMessage(AS_LAYER_SET_CLIP_REGION);
2247 
2248 		if (region) {
2249 			int32 count = region->CountRects();
2250 			fOwner->fLink->Attach<int32>(count);
2251 			for (int32 i = 0; i < count; i++)
2252 				fOwner->fLink->Attach<clipping_rect>(region->RectAtInt(i));
2253 		} else {
2254 			fOwner->fLink->Attach<int32>(-1);
2255 			// '-1' means that in the app_server, there won't be any 'local'
2256 			// clipping region (it will be NULL)
2257 		}
2258 
2259 		// we flush here because app_server waits for all the rects
2260 		fOwner->fLink->Flush();
2261 
2262 		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
2263 		fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
2264 	}
2265 }
2266 
2267 
2268 //	#pragma mark - Drawing Functions
2269 //---------------------------------------------------------------------------
2270 
2271 
2272 void
2273 BView::DrawBitmapAsync(const BBitmap *bitmap, BRect srcRect, BRect dstRect)
2274 {
2275 	if (!bitmap || !srcRect.IsValid() || !dstRect.IsValid())
2276 		return;
2277 
2278 	if (fOwner) {
2279 		check_lock();
2280 
2281 		fOwner->fLink->StartMessage(AS_LAYER_DRAW_BITMAP);
2282 		fOwner->fLink->Attach<int32>(bitmap->_ServerToken());
2283 		fOwner->fLink->Attach<BRect>(dstRect);
2284 		fOwner->fLink->Attach<BRect>(srcRect);
2285 
2286 		_FlushIfNotInTransaction();
2287 	}
2288 }
2289 
2290 
2291 void
2292 BView::DrawBitmapAsync(const BBitmap *bitmap, BRect dstRect)
2293 {
2294 	DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), dstRect);
2295 }
2296 
2297 
2298 void
2299 BView::DrawBitmapAsync(const BBitmap *bitmap)
2300 {
2301 	DrawBitmapAsync(bitmap, PenLocation());
2302 }
2303 
2304 
2305 void
2306 BView::DrawBitmapAsync(const BBitmap *bitmap, BPoint where)
2307 {
2308 	if (bitmap == NULL)
2309 		return;
2310 
2311 	if (fOwner) {
2312 		check_lock();
2313 
2314 		fOwner->fLink->StartMessage(AS_LAYER_DRAW_BITMAP);
2315 		fOwner->fLink->Attach<int32>(bitmap->_ServerToken());
2316 		BRect src = bitmap->Bounds().OffsetToCopy(B_ORIGIN);
2317 		BRect dst = src.OffsetToCopy(where);
2318 		fOwner->fLink->Attach<BRect>(dst);
2319 		fOwner->fLink->Attach<BRect>(src);
2320 
2321 		_FlushIfNotInTransaction();
2322 	}
2323 }
2324 
2325 
2326 void
2327 BView::DrawBitmap(const BBitmap *bitmap)
2328 {
2329 	DrawBitmap(bitmap, PenLocation());
2330 }
2331 
2332 
2333 void
2334 BView::DrawBitmap(const BBitmap *bitmap, BPoint where)
2335 {
2336 	if (fOwner) {
2337 		DrawBitmapAsync(bitmap, where);
2338 		Sync();
2339 	}
2340 }
2341 
2342 
2343 void
2344 BView::DrawBitmap(const BBitmap *bitmap, BRect dstRect)
2345 {
2346 	DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), dstRect);
2347 }
2348 
2349 
2350 void
2351 BView::DrawBitmap(const BBitmap *bitmap, BRect srcRect, BRect dstRect)
2352 {
2353 	if (fOwner) {
2354 		DrawBitmapAsync(bitmap, srcRect, dstRect);
2355 		Sync();
2356 	}
2357 }
2358 
2359 
2360 void
2361 BView::DrawChar(char c)
2362 {
2363 	DrawString(&c, 1, PenLocation());
2364 }
2365 
2366 
2367 void
2368 BView::DrawChar(char c, BPoint location)
2369 {
2370 	DrawString(&c, 1, location);
2371 }
2372 
2373 
2374 void
2375 BView::DrawString(const char *string, escapement_delta *delta)
2376 {
2377 	if (string == NULL)
2378 		return;
2379 
2380 	DrawString(string, strlen(string), PenLocation(), delta);
2381 }
2382 
2383 
2384 void
2385 BView::DrawString(const char *string, BPoint location, escapement_delta *delta)
2386 {
2387 	if (string == NULL)
2388 		return;
2389 
2390 	DrawString(string, strlen(string), location, delta);
2391 }
2392 
2393 
2394 void
2395 BView::DrawString(const char *string, int32 length, escapement_delta *delta)
2396 {
2397 	DrawString(string, length, PenLocation(), delta);
2398 }
2399 
2400 
2401 void
2402 BView::DrawString(const char *string, int32 length, BPoint location,
2403 	escapement_delta *delta)
2404 {
2405 	if (string == NULL || length < 1)
2406 		return;
2407 
2408 	if (fOwner) {
2409 		check_lock();
2410 
2411 		fOwner->fLink->StartMessage(AS_DRAW_STRING);
2412 		fOwner->fLink->Attach<int32>(length);
2413 		fOwner->fLink->Attach<BPoint>(location);
2414 
2415 		// Quite often delta will be NULL, so we have to accomodate this.
2416 		if (delta)
2417 			fOwner->fLink->Attach<escapement_delta>(*delta);
2418 		else {
2419 			escapement_delta tdelta;
2420 			tdelta.space = 0;
2421 			tdelta.nonspace = 0;
2422 
2423 			fOwner->fLink->Attach<escapement_delta>(tdelta);
2424 		}
2425 
2426 		fOwner->fLink->AttachString(string, length);
2427 
2428 		_FlushIfNotInTransaction();
2429 
2430 		// this modifies our pen location, so we invalidate the flag.
2431 		fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
2432 	}
2433 }
2434 
2435 
2436 void
2437 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius,
2438 	pattern p)
2439 {
2440 	StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2441 		center.y + yRadius), p);
2442 }
2443 
2444 
2445 void
2446 BView::StrokeEllipse(BRect rect, ::pattern pattern)
2447 {
2448 	if (fOwner == NULL)
2449 		return;
2450 
2451 	check_lock();
2452 	_UpdatePattern(pattern);
2453 
2454 	fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE);
2455 	fOwner->fLink->Attach<BRect>(rect);
2456 
2457 	_FlushIfNotInTransaction();
2458 }
2459 
2460 
2461 void
2462 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
2463 	::pattern pattern)
2464 {
2465 	FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
2466 		center.x + xRadius, center.y + yRadius), pattern);
2467 }
2468 
2469 
2470 void
2471 BView::FillEllipse(BRect rect, ::pattern pattern)
2472 {
2473 	if (fOwner == NULL)
2474 		return;
2475 
2476 	check_lock();
2477 	_UpdatePattern(pattern);
2478 
2479 	fOwner->fLink->StartMessage(AS_FILL_ELLIPSE);
2480 	fOwner->fLink->Attach<BRect>(rect);
2481 
2482 	_FlushIfNotInTransaction();
2483 }
2484 
2485 
2486 void
2487 BView::StrokeArc(BPoint center, float xRadius, float yRadius,
2488 	float startAngle, float arcAngle, pattern p)
2489 {
2490 	StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2491 		center.y + yRadius), startAngle, arcAngle, p);
2492 }
2493 
2494 
2495 void
2496 BView::StrokeArc(BRect rect, float startAngle, float arcAngle,
2497 	::pattern pattern)
2498 {
2499 	if (fOwner == NULL)
2500 		return;
2501 
2502 	check_lock();
2503 	_UpdatePattern(pattern);
2504 
2505 	fOwner->fLink->StartMessage(AS_STROKE_ARC);
2506 	fOwner->fLink->Attach<BRect>(rect);
2507 	fOwner->fLink->Attach<float>(startAngle);
2508 	fOwner->fLink->Attach<float>(arcAngle);
2509 
2510 	_FlushIfNotInTransaction();
2511 }
2512 
2513 
2514 void
2515 BView::FillArc(BPoint center,float xRadius, float yRadius,
2516 	float startAngle, float arcAngle, ::pattern pattern)
2517 {
2518 	FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2519 		center.y + yRadius), startAngle, arcAngle, pattern);
2520 }
2521 
2522 
2523 void
2524 BView::FillArc(BRect rect, float startAngle, float arcAngle,
2525 	::pattern pattern)
2526 {
2527 	if (fOwner == NULL)
2528 		return;
2529 
2530 	check_lock();
2531 	_UpdatePattern(pattern);
2532 
2533 	fOwner->fLink->StartMessage(AS_FILL_ARC);
2534 	fOwner->fLink->Attach<BRect>(rect);
2535 	fOwner->fLink->Attach<float>(startAngle);
2536 	fOwner->fLink->Attach<float>(arcAngle);
2537 
2538 	_FlushIfNotInTransaction();
2539 }
2540 
2541 
2542 void
2543 BView::StrokeBezier(BPoint *controlPoints, ::pattern pattern)
2544 {
2545 	if (fOwner == NULL)
2546 		return;
2547 
2548 	check_lock();
2549 	_UpdatePattern(pattern);
2550 
2551 	fOwner->fLink->StartMessage(AS_STROKE_BEZIER);
2552 	fOwner->fLink->Attach<BPoint>(controlPoints[0]);
2553 	fOwner->fLink->Attach<BPoint>(controlPoints[1]);
2554 	fOwner->fLink->Attach<BPoint>(controlPoints[2]);
2555 	fOwner->fLink->Attach<BPoint>(controlPoints[3]);
2556 
2557 	_FlushIfNotInTransaction();
2558 }
2559 
2560 
2561 void
2562 BView::FillBezier(BPoint *controlPoints, ::pattern pattern)
2563 {
2564 	if (fOwner == NULL)
2565 		return;
2566 
2567 	check_lock();
2568 	_UpdatePattern(pattern);
2569 
2570 	fOwner->fLink->StartMessage(AS_FILL_BEZIER);
2571 	fOwner->fLink->Attach<BPoint>(controlPoints[0]);
2572 	fOwner->fLink->Attach<BPoint>(controlPoints[1]);
2573 	fOwner->fLink->Attach<BPoint>(controlPoints[2]);
2574 	fOwner->fLink->Attach<BPoint>(controlPoints[3]);
2575 
2576 	_FlushIfNotInTransaction();
2577 }
2578 
2579 
2580 void
2581 BView::StrokePolygon(const BPolygon *polygon, bool closed, pattern p)
2582 {
2583 	if (!polygon)
2584 		return;
2585 
2586 	StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, p);
2587 }
2588 
2589 
2590 void
2591 BView::StrokePolygon(const BPoint *ptArray, int32 numPoints, bool closed, pattern p)
2592 {
2593 	BPolygon polygon(ptArray, numPoints);
2594 
2595 	StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, p);
2596 }
2597 
2598 
2599 void
2600 BView::StrokePolygon(const BPoint *ptArray, int32 numPoints, BRect bounds,
2601 	bool closed, ::pattern pattern)
2602 {
2603 	if (!ptArray
2604 		|| numPoints <= 1
2605 		|| fOwner == NULL)
2606 		return;
2607 
2608 	check_lock();
2609 	_UpdatePattern(pattern);
2610 
2611 	BPolygon polygon(ptArray, numPoints);
2612 	polygon.MapTo(polygon.Frame(), bounds);
2613 
2614 	if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON,
2615 			polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) + sizeof(int32))
2616 				== B_OK) {
2617 		fOwner->fLink->Attach<BRect>(polygon.Frame());
2618 		fOwner->fLink->Attach<bool>(closed);
2619 		fOwner->fLink->Attach<int32>(polygon.fCount);
2620 		fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint));
2621 
2622 		_FlushIfNotInTransaction();
2623 	} else {
2624 		// TODO: send via an area
2625 		fprintf(stderr, "ERROR: polygon to big for BPortLink!\n");
2626 	}
2627 }
2628 
2629 
2630 void
2631 BView::FillPolygon(const BPolygon *polygon, ::pattern pattern)
2632 {
2633 	if (polygon == NULL
2634 		|| polygon->fCount <= 2
2635 		|| fOwner == NULL)
2636 		return;
2637 
2638 	check_lock();
2639 	_UpdatePattern(pattern);
2640 
2641 	if (fOwner->fLink->StartMessage(AS_FILL_POLYGON,
2642 			polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) == B_OK) {
2643 		fOwner->fLink->Attach<BRect>(polygon->Frame());
2644 		fOwner->fLink->Attach<int32>(polygon->fCount);
2645 		fOwner->fLink->Attach(polygon->fPoints, polygon->fCount * sizeof(BPoint));
2646 
2647 		_FlushIfNotInTransaction();
2648 	} else {
2649 		// TODO: send via an area
2650 		fprintf(stderr, "ERROR: polygon to big for BPortLink!\n");
2651 	}
2652 }
2653 
2654 
2655 void
2656 BView::FillPolygon(const BPoint *ptArray, int32 numPts, ::pattern pattern)
2657 {
2658 	if (!ptArray)
2659 		return;
2660 
2661 	BPolygon polygon(ptArray, numPts);
2662 	FillPolygon(&polygon, pattern);
2663 }
2664 
2665 
2666 void
2667 BView::FillPolygon(const BPoint *ptArray, int32 numPts, BRect bounds,
2668 	pattern p)
2669 {
2670 	if (!ptArray)
2671 		return;
2672 
2673 	BPolygon polygon(ptArray, numPts);
2674 
2675 	polygon.MapTo(polygon.Frame(), bounds);
2676 	FillPolygon(&polygon, p);
2677 }
2678 
2679 
2680 void
2681 BView::StrokeRect(BRect rect, ::pattern pattern)
2682 {
2683 	if (fOwner == NULL)
2684 		return;
2685 
2686 	check_lock();
2687 	_UpdatePattern(pattern);
2688 
2689 	fOwner->fLink->StartMessage(AS_STROKE_RECT);
2690 	fOwner->fLink->Attach<BRect>(rect);
2691 
2692 	_FlushIfNotInTransaction();
2693 }
2694 
2695 
2696 void
2697 BView::FillRect(BRect rect, ::pattern pattern)
2698 {
2699 	if (fOwner == NULL)
2700 		return;
2701 
2702 	// NOTE: ensuring compatibility with R5,
2703 	// invalid rects are not filled, they are stroked though!
2704 	if (!rect.IsValid())
2705 		return;
2706 
2707 	check_lock();
2708 	_UpdatePattern(pattern);
2709 
2710 	fOwner->fLink->StartMessage(AS_FILL_RECT);
2711 	fOwner->fLink->Attach<BRect>(rect);
2712 
2713 	_FlushIfNotInTransaction();
2714 }
2715 
2716 
2717 void
2718 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius,
2719 	::pattern pattern)
2720 {
2721 	if (fOwner == NULL)
2722 		return;
2723 
2724 	check_lock();
2725 	_UpdatePattern(pattern);
2726 
2727 	fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT);
2728 	fOwner->fLink->Attach<BRect>(rect);
2729 	fOwner->fLink->Attach<float>(xRadius);
2730 	fOwner->fLink->Attach<float>(yRadius);
2731 
2732 	_FlushIfNotInTransaction();
2733 }
2734 
2735 
2736 void
2737 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
2738 	::pattern pattern)
2739 {
2740 	if (fOwner == NULL)
2741 		return;
2742 
2743 	check_lock();
2744 
2745 	_UpdatePattern(pattern);
2746 
2747 	fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT);
2748 	fOwner->fLink->Attach<BRect>(rect);
2749 	fOwner->fLink->Attach<float>(xRadius);
2750 	fOwner->fLink->Attach<float>(yRadius);
2751 
2752 	_FlushIfNotInTransaction();
2753 }
2754 
2755 
2756 void
2757 BView::FillRegion(BRegion *region, ::pattern pattern)
2758 {
2759 	if (region == NULL || fOwner == NULL)
2760 		return;
2761 
2762 	check_lock();
2763 
2764 	_UpdatePattern(pattern);
2765 
2766 	fOwner->fLink->StartMessage(AS_FILL_REGION);
2767 	fOwner->fLink->AttachRegion(*region);
2768 		// TODO: make this automatically chose
2769 		// to send over area or handle failure here?
2770 
2771 	_FlushIfNotInTransaction();
2772 }
2773 
2774 
2775 void
2776 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
2777 	BRect bounds, ::pattern pattern)
2778 {
2779 	if (fOwner == NULL)
2780 		return;
2781 
2782 	check_lock();
2783 
2784 	_UpdatePattern(pattern);
2785 
2786 	fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE);
2787 	fOwner->fLink->Attach<BPoint>(pt1);
2788 	fOwner->fLink->Attach<BPoint>(pt2);
2789 	fOwner->fLink->Attach<BPoint>(pt3);
2790 	fOwner->fLink->Attach<BRect>(bounds);
2791 
2792 	_FlushIfNotInTransaction();
2793 }
2794 
2795 
2796 void
2797 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p)
2798 {
2799 	if (fOwner) {
2800 		// we construct the smallest rectangle that contains the 3 points
2801 		// for the 1st point
2802 		BRect bounds(pt1, pt1);
2803 
2804 		// for the 2nd point
2805 		if (pt2.x < bounds.left)
2806 			bounds.left = pt2.x;
2807 
2808 		if (pt2.y < bounds.top)
2809 			bounds.top = pt2.y;
2810 
2811 		if (pt2.x > bounds.right)
2812 			bounds.right = pt2.x;
2813 
2814 		if (pt2.y > bounds.bottom)
2815 			bounds.bottom = pt2.y;
2816 
2817 		// for the 3rd point
2818 		if (pt3.x < bounds.left)
2819 			bounds.left = pt3.x;
2820 
2821 		if (pt3.y < bounds.top)
2822 			bounds.top = pt3.y;
2823 
2824 		if (pt3.x > bounds.right)
2825 			bounds.right = pt3.x;
2826 
2827 		if (pt3.y > bounds.bottom)
2828 			bounds.bottom = pt3.y;
2829 
2830 		StrokeTriangle(pt1, pt2, pt3, bounds, p);
2831 	}
2832 }
2833 
2834 
2835 void
2836 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p)
2837 {
2838 	if (fOwner) {
2839 		// we construct the smallest rectangle that contains the 3 points
2840 		// for the 1st point
2841 		BRect bounds(pt1, pt1);
2842 
2843 		// for the 2nd point
2844 		if (pt2.x < bounds.left)
2845 			bounds.left = pt2.x;
2846 
2847 		if (pt2.y < bounds.top)
2848 			bounds.top = pt2.y;
2849 
2850 		if (pt2.x > bounds.right)
2851 			bounds.right = pt2.x;
2852 
2853 		if (pt2.y > bounds.bottom)
2854 			bounds.bottom = pt2.y;
2855 
2856 		// for the 3rd point
2857 		if (pt3.x < bounds.left)
2858 			bounds.left = pt3.x;
2859 
2860 		if (pt3.y < bounds.top)
2861 			bounds.top = pt3.y;
2862 
2863 		if (pt3.x > bounds.right)
2864 			bounds.right = pt3.x;
2865 
2866 		if (pt3.y > bounds.bottom)
2867 			bounds.bottom = pt3.y;
2868 
2869 		FillTriangle(pt1, pt2, pt3, bounds, p);
2870 	}
2871 }
2872 
2873 
2874 void
2875 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
2876 	BRect bounds, ::pattern pattern)
2877 {
2878 	if (fOwner == NULL)
2879 		return;
2880 
2881 	check_lock();
2882 	_UpdatePattern(pattern);
2883 
2884 	fOwner->fLink->StartMessage(AS_FILL_TRIANGLE);
2885 	fOwner->fLink->Attach<BPoint>(pt1);
2886 	fOwner->fLink->Attach<BPoint>(pt2);
2887 	fOwner->fLink->Attach<BPoint>(pt3);
2888 	fOwner->fLink->Attach<BRect>(bounds);
2889 
2890 	_FlushIfNotInTransaction();
2891 }
2892 
2893 
2894 void
2895 BView::StrokeLine(BPoint toPt, pattern p)
2896 {
2897 	StrokeLine(PenLocation(), toPt, p);
2898 }
2899 
2900 
2901 void
2902 BView::StrokeLine(BPoint pt0, BPoint pt1, ::pattern pattern)
2903 {
2904 	if (fOwner == NULL)
2905 		return;
2906 
2907 	check_lock();
2908 	_UpdatePattern(pattern);
2909 
2910 	fOwner->fLink->StartMessage(AS_STROKE_LINE);
2911 	fOwner->fLink->Attach<BPoint>(pt0);
2912 	fOwner->fLink->Attach<BPoint>(pt1);
2913 
2914 	_FlushIfNotInTransaction();
2915 
2916 	// this modifies our pen location, so we invalidate the flag.
2917 	fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
2918 }
2919 
2920 
2921 void
2922 BView::StrokeShape(BShape *shape, ::pattern pattern)
2923 {
2924 	if (shape == NULL || fOwner == NULL)
2925 		return;
2926 
2927 	shape_data *sd = (shape_data *)shape->fPrivateData;
2928 	if (sd->opCount == 0 || sd->ptCount == 0)
2929 		return;
2930 
2931 	check_lock();
2932 	_UpdatePattern(pattern);
2933 
2934 	if ((sd->opCount * sizeof(uint32)) + (sd->ptCount * sizeof(BPoint)) < MAX_ATTACHMENT_SIZE) {
2935 		fOwner->fLink->StartMessage(AS_STROKE_SHAPE);
2936 		fOwner->fLink->Attach<BRect>(shape->Bounds());
2937 		fOwner->fLink->Attach<int32>(sd->opCount);
2938 		fOwner->fLink->Attach<int32>(sd->ptCount);
2939 		fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
2940 		fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
2941 
2942 		_FlushIfNotInTransaction();
2943 	} else {
2944 		// TODO: send via an area
2945 	}
2946 }
2947 
2948 
2949 void
2950 BView::FillShape(BShape *shape, ::pattern pattern)
2951 {
2952 	if (shape == NULL || fOwner == NULL)
2953 		return;
2954 
2955 	shape_data *sd = (shape_data *)(shape->fPrivateData);
2956 	if (sd->opCount == 0 || sd->ptCount == 0)
2957 		return;
2958 
2959 	check_lock();
2960 	_UpdatePattern(pattern);
2961 
2962 	if ((sd->opCount * sizeof(uint32)) + (sd->ptCount * sizeof(BPoint)) < MAX_ATTACHMENT_SIZE) {
2963 		fOwner->fLink->StartMessage(AS_FILL_SHAPE);
2964 		fOwner->fLink->Attach<BRect>(shape->Bounds());
2965 		fOwner->fLink->Attach<int32>(sd->opCount);
2966 		fOwner->fLink->Attach<int32>(sd->ptCount);
2967 		fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
2968 		fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
2969 
2970 		_FlushIfNotInTransaction();
2971 	} else {
2972 		// TODO: send via an area
2973 		// BTW, in a perfect world, the fLink API would take care of that -- axeld.
2974 	}
2975 }
2976 
2977 
2978 void
2979 BView::BeginLineArray(int32 count)
2980 {
2981 	if (fOwner == NULL)
2982 		return;
2983 
2984 	if (count <= 0)
2985 		debugger("Calling BeginLineArray with a count <= 0");
2986 
2987 	check_lock_no_pick();
2988 
2989 	if (comm) {
2990 		debugger("Can't nest BeginLineArray calls");
2991 			// not fatal, but it helps during
2992 			// development of your app and is in
2993 			// line with R5...
2994 		delete [] comm->array;
2995 		delete comm;
2996 	}
2997 
2998 	comm = new _array_data_;
2999 
3000 	comm->maxCount = count;
3001 	comm->count = 0;
3002 	comm->array = new _array_hdr_[count];
3003 }
3004 
3005 
3006 void
3007 BView::AddLine(BPoint pt0, BPoint pt1, rgb_color col)
3008 {
3009 	if (fOwner == NULL)
3010 		return;
3011 
3012 	if (!comm)
3013 		debugger("BeginLineArray must be called before using AddLine");
3014 
3015 	check_lock_no_pick();
3016 
3017 	if (comm->count < comm->maxCount) {
3018 		comm->array[comm->count].startX = pt0.x;
3019 		comm->array[comm->count].startY = pt0.y;
3020 		comm->array[comm->count].endX = pt1.x;
3021 		comm->array[comm->count].endY = pt1.y;
3022 		comm->array[comm->count].color = col;
3023 
3024 		comm->count++;
3025 	}
3026 }
3027 
3028 
3029 void
3030 BView::EndLineArray()
3031 {
3032 	if (fOwner == NULL)
3033 		return;
3034 
3035 	if (!comm)
3036 		debugger("Can't call EndLineArray before BeginLineArray");
3037 
3038 	check_lock();
3039 
3040 	fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY);
3041 	fOwner->fLink->Attach<int32>(comm->count);
3042 	fOwner->fLink->Attach(comm->array, comm->count * sizeof(_array_hdr_));
3043 
3044 	_FlushIfNotInTransaction();
3045 
3046 	removeCommArray();
3047 }
3048 
3049 
3050 void
3051 BView::BeginPicture(BPicture *picture)
3052 {
3053 	if (do_owner_check() && picture && picture->usurped == NULL) {
3054 		picture->usurp(cpicture);
3055 		cpicture = picture;
3056 
3057 		fOwner->fLink->StartMessage(AS_LAYER_BEGIN_PICTURE);
3058 	}
3059 }
3060 
3061 
3062 void
3063 BView::AppendToPicture(BPicture *picture)
3064 {
3065 	check_lock();
3066 
3067 	if (picture && picture->usurped == NULL) {
3068 		int32 token = picture->token;
3069 
3070 		if (token == -1) {
3071 			BeginPicture(picture);
3072 		} else {
3073 			picture->usurped = cpicture;
3074 			picture->set_token(-1);
3075 			fOwner->fLink->StartMessage(AS_LAYER_APPEND_TO_PICTURE);
3076 			fOwner->fLink->Attach<int32>(token);
3077 		}
3078 	}
3079 }
3080 
3081 
3082 BPicture *
3083 BView::EndPicture()
3084 {
3085 	if (do_owner_check() && cpicture) {
3086 		int32 token;
3087 
3088 		fOwner->fLink->StartMessage(AS_LAYER_END_PICTURE);
3089 
3090 		int32 code;
3091 		if (fOwner->fLink->FlushWithReply(code) == B_OK
3092 			&& code == B_OK
3093 			&& fOwner->fLink->Read<int32>(&token) == B_OK) {
3094 			BPicture *picture = cpicture;
3095 			cpicture = picture->step_down();
3096 			picture->set_token(token);
3097 
3098 			return picture;
3099 		}
3100 	}
3101 
3102 	return NULL;
3103 }
3104 
3105 
3106 void
3107 BView::SetViewBitmap(const BBitmap *bitmap, BRect srcRect, BRect dstRect,
3108 	uint32 followFlags, uint32 options)
3109 {
3110 	_SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options);
3111 }
3112 
3113 
3114 void
3115 BView::SetViewBitmap(const BBitmap *bitmap, uint32 followFlags, uint32 options)
3116 {
3117 	BRect rect;
3118  	if (bitmap)
3119 		rect = bitmap->Bounds();
3120 
3121  	rect.OffsetTo(B_ORIGIN);
3122 
3123 	_SetViewBitmap(bitmap, rect, rect, followFlags, options);
3124 }
3125 
3126 
3127 void
3128 BView::ClearViewBitmap()
3129 {
3130 	_SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3131 }
3132 
3133 
3134 status_t
3135 BView::SetViewOverlay(const BBitmap *overlay, BRect srcRect, BRect dstRect,
3136 	rgb_color *colorKey, uint32 followFlags, uint32 options)
3137 {
3138 	if ((overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0)
3139 		return B_BAD_VALUE;
3140 
3141 	status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags,
3142 		options | AS_REQUEST_COLOR_KEY);
3143 	if (status == B_OK) {
3144 		// read the color that will be treated as transparent
3145 		fOwner->fLink->Read<rgb_color>(colorKey);
3146 	}
3147 
3148 	return status;
3149 }
3150 
3151 
3152 status_t
3153 BView::SetViewOverlay(const BBitmap *overlay, rgb_color *colorKey,
3154 	uint32 followFlags, uint32 options)
3155 {
3156 	BRect rect;
3157  	if (overlay != NULL) {
3158 		rect = overlay->Bounds();
3159 	 	rect.OffsetTo(B_ORIGIN);
3160  	}
3161 
3162 	return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options);
3163 }
3164 
3165 
3166 void
3167 BView::ClearViewOverlay()
3168 {
3169 	_SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3170 }
3171 
3172 
3173 void
3174 BView::CopyBits(BRect src, BRect dst)
3175 {
3176 	if (!src.IsValid() || !dst.IsValid())
3177 		return;
3178 
3179 	if (do_owner_check()) {
3180 		fOwner->fLink->StartMessage(AS_LAYER_COPY_BITS);
3181 		fOwner->fLink->Attach<BRect>(src);
3182 		fOwner->fLink->Attach<BRect>(dst);
3183 
3184 		_FlushIfNotInTransaction();
3185 	}
3186 }
3187 
3188 
3189 void
3190 BView::DrawPicture(const BPicture *picture)
3191 {
3192 	if (picture == NULL)
3193 		return;
3194 
3195 	DrawPictureAsync(picture, PenLocation());
3196 	Sync();
3197 }
3198 
3199 
3200 void
3201 BView::DrawPicture(const BPicture *picture, BPoint where)
3202 {
3203 	if (picture == NULL)
3204 		return;
3205 
3206 	DrawPictureAsync(picture, where);
3207 	Sync();
3208 }
3209 
3210 
3211 void
3212 BView::DrawPicture(const char *filename, long offset, BPoint where)
3213 {
3214 	if (!filename)
3215 		return;
3216 
3217 	DrawPictureAsync(filename, offset, where);
3218 	Sync();
3219 }
3220 
3221 
3222 void
3223 BView::DrawPictureAsync(const BPicture *picture)
3224 {
3225 	if (picture == NULL)
3226 		return;
3227 
3228 	DrawPictureAsync(picture, PenLocation());
3229 }
3230 
3231 
3232 void
3233 BView::DrawPictureAsync(const BPicture *picture, BPoint where)
3234 {
3235 	if (picture == NULL)
3236 		return;
3237 
3238 	if (do_owner_check() && picture->token > 0) {
3239 		fOwner->fLink->StartMessage(AS_LAYER_DRAW_PICTURE);
3240 		fOwner->fLink->Attach<int32>(picture->token);
3241 		fOwner->fLink->Attach<BPoint>(where);
3242 
3243 		_FlushIfNotInTransaction();
3244 	}
3245 }
3246 
3247 
3248 void
3249 BView::DrawPictureAsync(const char *filename, long offset, BPoint where)
3250 {
3251 	if (!filename)
3252 		return;
3253 
3254 	// TODO: Test
3255 	BFile file(filename, B_READ_ONLY);
3256 	if (file.InitCheck() < B_OK)
3257 		return;
3258 
3259 	file.Seek(offset, SEEK_SET);
3260 
3261 	BPicture picture;
3262 	if (picture.Unflatten(&file) < B_OK)
3263 		return;
3264 
3265 	DrawPictureAsync(&picture, where);
3266 }
3267 
3268 
3269 void
3270 BView::Invalidate(BRect invalRect)
3271 {
3272 	if (!invalRect.IsValid() || fOwner == NULL)
3273 		return;
3274 
3275 	check_lock();
3276 
3277 	fOwner->fLink->StartMessage(AS_LAYER_INVALIDATE_RECT);
3278 	fOwner->fLink->Attach<BRect>(invalRect);
3279 	fOwner->fLink->Flush();
3280 }
3281 
3282 
3283 void
3284 BView::Invalidate(const BRegion *invalRegion)
3285 {
3286 	if (invalRegion == NULL || fOwner == NULL)
3287 		return;
3288 
3289 	check_lock();
3290 
3291 	int32 count = 0;
3292 	count = const_cast<BRegion*>(invalRegion)->CountRects();
3293 
3294 	fOwner->fLink->StartMessage(AS_LAYER_INVALIDATE_REGION);
3295 	fOwner->fLink->Attach<int32>(count);
3296 
3297 	for (int32 i = 0; i < count; i++)
3298 		fOwner->fLink->Attach<BRect>( const_cast<BRegion *>(invalRegion)->RectAt(i));
3299 
3300 	fOwner->fLink->Flush();
3301 }
3302 
3303 
3304 void
3305 BView::Invalidate()
3306 {
3307 	Invalidate(Bounds());
3308 }
3309 
3310 
3311 void
3312 BView::InvertRect(BRect rect)
3313 {
3314 	if (fOwner) {
3315 		check_lock();
3316 
3317 		fOwner->fLink->StartMessage(AS_LAYER_INVERT_RECT);
3318 		fOwner->fLink->Attach<BRect>(rect);
3319 
3320 		_FlushIfNotInTransaction();
3321 	}
3322 }
3323 
3324 
3325 //	#pragma mark -
3326 //	View Hierarchy Functions
3327 
3328 
3329 void
3330 BView::AddChild(BView *child, BView *before)
3331 {
3332 	STRACE(("BView(%s)::AddChild(child='%s' before='%s')\n",
3333  		this->Name() ? this->Name(): "NULL",
3334  		child && child->Name() ? child->Name(): "NULL",
3335  		before && before->Name() ? before->Name(): "NULL"));
3336 
3337 	if (!_AddChild(child, before))
3338 		return;
3339 
3340 	if (fLayoutData->fLayout)
3341 		fLayoutData->fLayout->AddView(child);
3342 }
3343 
3344 
3345 bool
3346 BView::AddChild(BLayoutItem* child)
3347 {
3348 	if (!fLayoutData->fLayout)
3349 		return false;
3350 	return fLayoutData->fLayout->AddItem(child);
3351 }
3352 
3353 
3354 bool
3355 BView::_AddChild(BView *child, BView *before)
3356 {
3357 	if (!child)
3358 		return false;
3359 
3360 	if (child->fParent != NULL) {
3361 printf("BView::_AddChild(): child %p already has parent %p\n", child , child->fParent);
3362 		debugger("AddChild failed - the view already has a parent.");
3363 		return false;
3364 	}
3365 
3366 	bool lockedOwner = false;
3367 	if (fOwner && !fOwner->IsLocked()) {
3368 		fOwner->Lock();
3369 		lockedOwner = true;
3370 	}
3371 
3372 	if (!_AddChildToList(child, before)) {
3373 		debugger("AddChild failed!");
3374 		if (lockedOwner)
3375 			fOwner->Unlock();
3376 		return false;
3377 	}
3378 
3379 	if (fOwner) {
3380 		check_lock();
3381 
3382 		child->_SetOwner(fOwner);
3383 		child->_CreateSelf();
3384 		child->_Attach();
3385 
3386 		if (lockedOwner)
3387 			fOwner->Unlock();
3388 	}
3389 
3390 	InvalidateLayout();
3391 
3392 	return true;
3393 }
3394 
3395 
3396 bool
3397 BView::RemoveChild(BView *child)
3398 {
3399 	STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
3400 
3401 	if (!child)
3402 		return false;
3403 
3404 	return child->RemoveSelf();
3405 }
3406 
3407 int32
3408 BView::CountChildren() const
3409 {
3410 	check_lock_no_pick();
3411 
3412 	uint32 count = 0;
3413 	BView *child = fFirstChild;
3414 
3415 	while (child != NULL) {
3416 		count++;
3417 		child = child->fNextSibling;
3418 	}
3419 
3420 	return count;
3421 }
3422 
3423 
3424 BView *
3425 BView::ChildAt(int32 index) const
3426 {
3427 	check_lock_no_pick();
3428 
3429 	BView *child = fFirstChild;
3430 	while (child != NULL && index-- > 0) {
3431 		child = child->fNextSibling;
3432 	}
3433 
3434 	return child;
3435 }
3436 
3437 
3438 BView *
3439 BView::NextSibling() const
3440 {
3441 	return fNextSibling;
3442 }
3443 
3444 
3445 BView *
3446 BView::PreviousSibling() const
3447 {
3448 	return fPreviousSibling;
3449 }
3450 
3451 
3452 bool
3453 BView::RemoveSelf()
3454 {
3455 	if (fParent && fParent->fLayoutData->fLayout)
3456 		return fParent->fLayoutData->fLayout->RemoveView(this);
3457 	else
3458 		return _RemoveSelf();
3459 }
3460 
3461 
3462 bool
3463 BView::_RemoveSelf()
3464 {
3465 	STRACE(("BView(%s)::RemoveSelf()...\n", Name()));
3466 
3467 	// Remove this child from its parent
3468 
3469 	BWindow* owner = fOwner;
3470 	check_lock_no_pick();
3471 
3472 	if (owner != NULL) {
3473 		_UpdateStateForRemove();
3474 		_Detach();
3475 	}
3476 
3477 	BView* parent = fParent;
3478 	if (!parent || !parent->_RemoveChildFromList(this))
3479 		return false;
3480 
3481 	if (owner != NULL && !fTopLevelView) {
3482 		// the top level view is deleted by the app_server automatically
3483 		owner->fLink->StartMessage(AS_LAYER_DELETE);
3484 		owner->fLink->Attach<int32>(_get_object_token_(this));
3485 	}
3486 
3487 	parent->InvalidateLayout();
3488 
3489 	STRACE(("DONE: BView(%s)::RemoveSelf()\n", Name()));
3490 
3491 	return true;
3492 }
3493 
3494 
3495 BView *
3496 BView::Parent() const
3497 {
3498 	if (fParent && fParent->fTopLevelView)
3499 		return NULL;
3500 
3501 	return fParent;
3502 }
3503 
3504 
3505 BView *
3506 BView::FindView(const char *name) const
3507 {
3508 	if (name == NULL)
3509 		return NULL;
3510 
3511 	if (Name() != NULL && !strcmp(Name(), name))
3512 		return const_cast<BView *>(this);
3513 
3514 	BView *child = fFirstChild;
3515 	while (child != NULL) {
3516 		BView *view = child->FindView(name);
3517 		if (view != NULL)
3518 			return view;
3519 
3520 		child = child->fNextSibling;
3521 	}
3522 
3523 	return NULL;
3524 }
3525 
3526 
3527 void
3528 BView::MoveBy(float deltaX, float deltaY)
3529 {
3530 	MoveTo(fParentOffset.x + deltaX, fParentOffset.y + deltaY);
3531 }
3532 
3533 
3534 void
3535 BView::MoveTo(BPoint where)
3536 {
3537 	MoveTo(where.x, where.y);
3538 }
3539 
3540 
3541 void
3542 BView::MoveTo(float x, float y)
3543 {
3544 	if (x == fParentOffset.x && y == fParentOffset.y)
3545 		return;
3546 
3547 	// BeBook says we should do this. And it makes sense.
3548 	x = roundf(x);
3549 	y = roundf(y);
3550 
3551 	if (fOwner) {
3552 		check_lock();
3553 		fOwner->fLink->StartMessage(AS_LAYER_MOVE_TO);
3554 		fOwner->fLink->Attach<float>(x);
3555 		fOwner->fLink->Attach<float>(y);
3556 
3557 		fState->valid_flags |= B_VIEW_FRAME_BIT;
3558 
3559 		_FlushIfNotInTransaction();
3560 	}
3561 
3562 	_MoveTo((int32)x, (int32)y);
3563 }
3564 
3565 
3566 void
3567 BView::ResizeBy(float deltaWidth, float deltaHeight)
3568 {
3569 	// TODO: this doesn't look like it would work correctly with scrolled views
3570 
3571 	// NOTE: I think this check makes sense, but I didn't
3572 	// test what R5 does.
3573 	if (fBounds.right + deltaWidth < 0)
3574 		deltaWidth = -fBounds.right;
3575 	if (fBounds.bottom + deltaHeight < 0)
3576 		deltaHeight = -fBounds.bottom;
3577 
3578 	// BeBook says we should do this. And it makes sense.
3579 	deltaWidth = roundf(deltaWidth);
3580 	deltaHeight = roundf(deltaHeight);
3581 
3582 	if (deltaWidth == 0 && deltaHeight == 0)
3583 		return;
3584 
3585 	if (fOwner) {
3586 		check_lock();
3587 		fOwner->fLink->StartMessage(AS_LAYER_RESIZE_TO);
3588 
3589 		fOwner->fLink->Attach<float>(fBounds.right + deltaWidth);
3590 		fOwner->fLink->Attach<float>(fBounds.bottom + deltaHeight);
3591 
3592 		fState->valid_flags |= B_VIEW_FRAME_BIT;
3593 
3594 		_FlushIfNotInTransaction();
3595 	}
3596 
3597 	_ResizeBy((int32)deltaWidth, (int32)deltaHeight);
3598 }
3599 
3600 
3601 void
3602 BView::ResizeTo(float width, float height)
3603 {
3604 	ResizeBy(width - fBounds.Width(), height - fBounds.Height());
3605 }
3606 
3607 
3608 //	#pragma mark -
3609 //	Inherited Methods (from BHandler)
3610 
3611 
3612 status_t
3613 BView::GetSupportedSuites(BMessage *data)
3614 {
3615 	if (data == NULL)
3616 		return B_BAD_VALUE;
3617 
3618 	status_t status = data->AddString("suites", "suite/vnd.Be-view");
3619 	BPropertyInfo propertyInfo(sViewPropInfo);
3620 	if (status == B_OK)
3621 		status = data->AddFlat("messages", &propertyInfo);
3622 	if (status == B_OK)
3623 		return BHandler::GetSupportedSuites(data);
3624 	return status;
3625 }
3626 
3627 
3628 BHandler *
3629 BView::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier,
3630 	int32 what,	const char *property)
3631 {
3632 	if (msg->what == B_WINDOW_MOVE_BY
3633 		|| msg->what == B_WINDOW_MOVE_TO)
3634 		return this;
3635 
3636 	BPropertyInfo propertyInfo(sViewPropInfo);
3637 	status_t err = B_BAD_SCRIPT_SYNTAX;
3638 	BMessage replyMsg(B_REPLY);
3639 
3640 	switch (propertyInfo.FindMatch(msg, index, specifier, what, property)) {
3641 		case 0:
3642 		case 1:
3643 		case 2:
3644 		case 3:
3645 		case 5:
3646 			return this;
3647 
3648 		case 4:
3649 			if (fShelf) {
3650 				msg->PopSpecifier();
3651 				return fShelf;
3652 			}
3653 
3654 			err = B_NAME_NOT_FOUND;
3655 			replyMsg.AddString("message", "This window doesn't have a shelf");
3656 			break;
3657 
3658 		case 6: {
3659 			if (!fFirstChild) {
3660 				err = B_NAME_NOT_FOUND;
3661 				replyMsg.AddString("message", "This window doesn't have children.");
3662 				break;
3663 			}
3664 			BView *child = NULL;
3665 			switch (what) {
3666 				case B_INDEX_SPECIFIER:	{
3667 					int32 index;
3668 					err = specifier->FindInt32("index", &index);
3669 					if (err == B_OK)
3670 						child = ChildAt(index);
3671 					break;
3672 				}
3673 				case B_REVERSE_INDEX_SPECIFIER: {
3674 					int32 rindex;
3675 					err = specifier->FindInt32("index", &rindex);
3676 					if (err == B_OK)
3677 						child = ChildAt(CountChildren() - rindex);
3678 					break;
3679 				}
3680 				case B_NAME_SPECIFIER: {
3681 					const char *name;
3682 					err = specifier->FindString("name", &name);
3683 					if (err == B_OK)
3684 						child = FindView(name);
3685 					break;
3686 				}
3687 			}
3688 
3689 			if (child != NULL) {
3690 				msg->PopSpecifier();
3691 				return child;
3692 			}
3693 
3694 			if (err == B_OK)
3695 				err = B_BAD_INDEX;
3696 			replyMsg.AddString("message", "Cannot find view at/with specified index/name.");
3697 			break;
3698 		}
3699 		default:
3700 			return BHandler::ResolveSpecifier(msg, index, specifier, what, property);
3701 	}
3702 
3703 	if (err < B_OK) {
3704 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
3705 
3706 		if (err == B_BAD_SCRIPT_SYNTAX)
3707 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
3708 		else
3709 			replyMsg.AddString("message", strerror(err));
3710 	}
3711 
3712 	replyMsg.AddInt32("error", err);
3713 	msg->SendReply(&replyMsg);
3714 	return NULL;
3715 }
3716 
3717 
3718 void
3719 BView::MessageReceived(BMessage *msg)
3720 {
3721 	if (!msg->HasSpecifiers()) {
3722 		switch (msg->what) {
3723 			case B_VIEW_RESIZED:
3724 				// By the time the message arrives, the bounds may have
3725 				// changed already, that's why we don't use the values
3726 				// in the message itself.
3727 				FrameResized(fBounds.Width(), fBounds.Height());
3728 				break;
3729 
3730 			case B_VIEW_MOVED:
3731 				FrameMoved(fParentOffset);
3732 				break;
3733 
3734 			case B_MOUSE_WHEEL_CHANGED:
3735 			{
3736 				float deltaX = 0.0f, deltaY = 0.0f;
3737 
3738 				BScrollBar *horizontal = ScrollBar(B_HORIZONTAL);
3739 				if (horizontal != NULL)
3740 					msg->FindFloat("be:wheel_delta_x", &deltaX);
3741 
3742 				BScrollBar *vertical = ScrollBar(B_VERTICAL);
3743 				if (vertical != NULL)
3744 					msg->FindFloat("be:wheel_delta_y", &deltaY);
3745 
3746 				if (deltaX == 0.0f && deltaY == 0.0f)
3747 					return;
3748 
3749 				float smallStep, largeStep;
3750 				if (horizontal != NULL) {
3751 					horizontal->GetSteps(&smallStep, &largeStep);
3752 
3753 					// pressing the option key scrolls faster
3754 					if (modifiers() & B_OPTION_KEY)
3755 						deltaX *= largeStep;
3756 					else
3757 						deltaX *= smallStep * 3;
3758 
3759 					horizontal->SetValue(horizontal->Value() + deltaX);
3760 				}
3761 
3762 				if (vertical != NULL) {
3763 					vertical->GetSteps(&smallStep, &largeStep);
3764 
3765 					// pressing the option key scrolls faster
3766 					if (modifiers() & B_OPTION_KEY)
3767 						deltaY *= largeStep;
3768 					else
3769 						deltaY *= smallStep * 3;
3770 
3771 					vertical->SetValue(vertical->Value() + deltaY);
3772 				}
3773 				break;
3774 			}
3775 
3776 			default:
3777 				return BHandler::MessageReceived(msg);
3778 		}
3779 
3780 		return;
3781 	}
3782 
3783 	// Scripting message
3784 
3785 	BMessage replyMsg(B_REPLY);
3786 	status_t err = B_BAD_SCRIPT_SYNTAX;
3787 	int32 index;
3788 	BMessage specifier;
3789 	int32 what;
3790 	const char *prop;
3791 
3792 	if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK)
3793 		return BHandler::MessageReceived(msg);
3794 
3795 	BPropertyInfo propertyInfo(sViewPropInfo);
3796 	switch (propertyInfo.FindMatch(msg, index, &specifier, what, prop)) {
3797 		case 0:
3798 			err = replyMsg.AddRect("result", Frame());
3799 			break;
3800 		case 1: {
3801 			BRect newFrame;
3802 			err = msg->FindRect("data", &newFrame);
3803 			if (err == B_OK) {
3804 				MoveTo(newFrame.LeftTop());
3805 				ResizeTo(newFrame.right, newFrame.bottom);
3806 			}
3807 			break;
3808 		}
3809 		case 2:
3810 			err = replyMsg.AddBool( "result", IsHidden());
3811 			break;
3812 		case 3: {
3813 			bool newHiddenState;
3814 			err = msg->FindBool("data", &newHiddenState);
3815 			if (err == B_OK) {
3816 				if (!IsHidden() && newHiddenState == true)
3817 					Hide();
3818 				else if (IsHidden() && newHiddenState == false)
3819 					Show();
3820 			}
3821 		}
3822 		case 5:
3823 			err = replyMsg.AddInt32("result", CountChildren());
3824 			break;
3825 		default:
3826 			return BHandler::MessageReceived(msg);
3827 	}
3828 
3829 	if (err < B_OK) {
3830 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
3831 
3832 		if (err == B_BAD_SCRIPT_SYNTAX)
3833 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
3834 		else
3835 			replyMsg.AddString("message", strerror(err));
3836 	}
3837 
3838 	replyMsg.AddInt32("error", err);
3839 	msg->SendReply(&replyMsg);
3840 }
3841 
3842 
3843 status_t
3844 BView::Perform(perform_code d, void* arg)
3845 {
3846 	return B_BAD_VALUE;
3847 }
3848 
3849 
3850 // #pragma mark - Layout Functions
3851 
3852 
3853 BSize
3854 BView::MinSize()
3855 {
3856 	// TODO: make sure this works correctly when some methods are overridden
3857 	float width, height;
3858 	GetPreferredSize(&width, &height);
3859 
3860 	return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
3861 		(fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
3862 			: BSize(width, height)));
3863 }
3864 
3865 
3866 BSize
3867 BView::MaxSize()
3868 {
3869 	return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
3870 		(fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
3871 			: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
3872 }
3873 
3874 
3875 BSize
3876 BView::PreferredSize()
3877 {
3878 	// TODO: make sure this works correctly when some methods are overridden
3879 	float width, height;
3880 	GetPreferredSize(&width, &height);
3881 
3882 	return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
3883 		(fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
3884 			: BSize(width, height)));
3885 }
3886 
3887 
3888 BAlignment
3889 BView::Alignment()
3890 {
3891 	return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
3892 		(fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
3893 			: BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
3894 }
3895 
3896 
3897 void
3898 BView::SetExplicitMinSize(BSize size)
3899 {
3900 	fLayoutData->fMinSize = size;
3901 	InvalidateLayout();
3902 }
3903 
3904 
3905 void
3906 BView::SetExplicitMaxSize(BSize size)
3907 {
3908 	fLayoutData->fMaxSize = size;
3909 	InvalidateLayout();
3910 }
3911 
3912 
3913 void
3914 BView::SetExplicitPreferredSize(BSize size)
3915 {
3916 	fLayoutData->fPreferredSize = size;
3917 	InvalidateLayout();
3918 }
3919 
3920 
3921 void
3922 BView::SetExplicitAlignment(BAlignment alignment)
3923 {
3924 	fLayoutData->fAlignment = alignment;
3925 	InvalidateLayout();
3926 }
3927 
3928 
3929 BSize
3930 BView::ExplicitMinSize() const
3931 {
3932 	return fLayoutData->fMinSize;
3933 }
3934 
3935 
3936 BSize
3937 BView::ExplicitMaxSize() const
3938 {
3939 	return fLayoutData->fMaxSize;
3940 }
3941 
3942 
3943 BSize
3944 BView::ExplicitPreferredSize() const
3945 {
3946 	return fLayoutData->fPreferredSize;
3947 }
3948 
3949 
3950 BAlignment
3951 BView::ExplicitAlignment() const
3952 {
3953 	return fLayoutData->fAlignment;
3954 }
3955 
3956 
3957 bool
3958 BView::HasHeightForWidth()
3959 {
3960 	return (fLayoutData->fLayout
3961 		? fLayoutData->fLayout->HasHeightForWidth() : false);
3962 }
3963 
3964 
3965 void
3966 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
3967 {
3968 	if (fLayoutData->fLayout)
3969 		fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
3970 }
3971 
3972 
3973 void
3974 BView::SetLayout(BLayout* layout)
3975 {
3976 	if (layout == fLayoutData->fLayout)
3977 		return;
3978 
3979 	fFlags |= B_SUPPORTS_LAYOUT;
3980 
3981 	// unset and delete the old layout
3982 	if (fLayoutData->fLayout) {
3983 		fLayoutData->fLayout->SetView(NULL);
3984 		delete fLayoutData->fLayout;
3985 	}
3986 
3987 	fLayoutData->fLayout = layout;
3988 
3989 	if (fLayoutData->fLayout) {
3990 		fLayoutData->fLayout->SetView(this);
3991 
3992 		// add all children
3993 		int count = CountChildren();
3994 		for (int i = 0; i < count; i++)
3995 			fLayoutData->fLayout->AddView(ChildAt(i));
3996 	}
3997 
3998 	InvalidateLayout();
3999 }
4000 
4001 
4002 BLayout*
4003 BView::GetLayout() const
4004 {
4005 	return fLayoutData->fLayout;
4006 }
4007 
4008 
4009 void
4010 BView::InvalidateLayout(bool descendants)
4011 {
4012 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress
4013 		&& fLayoutData->fLayoutInvalidationDisabled == 0) {
4014 		if (fParent && fParent->fLayoutData->fLayoutValid)
4015 			fParent->InvalidateLayout(false);
4016 
4017 		fLayoutData->fLayoutValid = false;
4018 
4019 		if (fLayoutData->fLayout)
4020 			fLayoutData->fLayout->InvalidateLayout();
4021 
4022 		if (descendants) {
4023 			int count = CountChildren();
4024 			for (int i = 0; i < count; i++)
4025 				ChildAt(i)->InvalidateLayout(descendants);
4026 		}
4027 
4028 		if (fTopLevelView) {
4029 			// trigger layout process
4030 			if (fOwner)
4031 				fOwner->PostMessage(B_LAYOUT_WINDOW);
4032 		}
4033 	}
4034 }
4035 
4036 
4037 void
4038 BView::EnableLayoutInvalidation()
4039 {
4040 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
4041 		fLayoutData->fLayoutInvalidationDisabled--;
4042 }
4043 
4044 
4045 void
4046 BView::DisableLayoutInvalidation()
4047 {
4048 	fLayoutData->fLayoutInvalidationDisabled++;
4049 }
4050 
4051 
4052 BLayoutContext*
4053 BView::LayoutContext() const
4054 {
4055 	return fLayoutData->fLayoutContext;
4056 }
4057 
4058 
4059 void
4060 BView::Layout(bool force)
4061 {
4062 	BLayoutContext context;
4063 	_Layout(force, &context);
4064 }
4065 
4066 
4067 void
4068 BView::Relayout()
4069 {
4070 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
4071 		fLayoutData->fNeedsRelayout = true;
4072 
4073 		// Layout() is recursive, that is if the parent view is currently laid
4074 		// out, we don't call layout() on this view, but wait for the parent's
4075 		// Layout() to do that for us.
4076 		if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
4077 			Layout(false);
4078 	}
4079 }
4080 
4081 
4082 void
4083 BView::DoLayout()
4084 {
4085 	if (fLayoutData->fLayout)
4086 		fLayoutData->fLayout->LayoutView();
4087 }
4088 
4089 
4090 void
4091 BView::_Layout(bool force, BLayoutContext* context)
4092 {
4093 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
4094 //printf("  fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
4095 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, fLayoutData->fLayoutInProgress);
4096 	if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
4097 		fLayoutData->fLayoutValid = false;
4098 
4099 		if (fLayoutData->fLayoutInProgress)
4100 			return;
4101 
4102 		BLayoutContext* oldContext = fLayoutData->fLayoutContext;
4103 		fLayoutData->fLayoutContext = context;
4104 
4105 		fLayoutData->fLayoutInProgress = true;
4106 		DoLayout();
4107 		fLayoutData->fLayoutInProgress = false;
4108 
4109 		fLayoutData->fLayoutValid = true;
4110 		fLayoutData->fNeedsRelayout = false;
4111 
4112 		// layout children
4113 		int32 childCount = CountChildren();
4114 		for (int32 i = 0; i < childCount; i++) {
4115 			BView* child = ChildAt(i);
4116 			if (!child->IsHidden(child))
4117 				child->_Layout(force, context);
4118 		}
4119 
4120 		fLayoutData->fLayoutContext = oldContext;
4121 
4122 		// invalidate the drawn content, if requested
4123 		if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
4124 			Invalidate();
4125 	}
4126 }
4127 
4128 
4129 //	#pragma mark -
4130 //	Private Functions
4131 
4132 
4133 void
4134 BView::_InitData(BRect frame, const char *name, uint32 resizingMode, uint32 flags)
4135 {
4136 	// Info: The name of the view is set by BHandler constructor
4137 
4138 	STRACE(("BView::InitData: enter\n"));
4139 
4140 	// initialize members
4141 	fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
4142 
4143 	// handle rounding
4144 	frame.left = roundf(frame.left);
4145 	frame.top = roundf(frame.top);
4146 	frame.right = roundf(frame.right);
4147 	frame.bottom = roundf(frame.bottom);
4148 
4149 	fParentOffset.Set(frame.left, frame.top);
4150 
4151 	fOwner = NULL;
4152 	fParent = NULL;
4153 	fNextSibling = NULL;
4154 	fPreviousSibling = NULL;
4155 	fFirstChild = NULL;
4156 
4157 	fShowLevel = 0;
4158 	fTopLevelView = false;
4159 
4160 	cpicture = NULL;
4161 	comm = NULL;
4162 
4163 	fVerScroller = NULL;
4164 	fHorScroller = NULL;
4165 
4166 	f_is_printing = false;
4167 	fAttached = false;
4168 
4169 	fState = new BPrivate::ViewState;
4170 
4171 	fBounds = frame.OffsetToCopy(B_ORIGIN);
4172 	fShelf = NULL;
4173 
4174 	fEventMask = 0;
4175 	fEventOptions = 0;
4176 
4177 	fLayoutData = new LayoutData;
4178 }
4179 
4180 
4181 void
4182 BView::removeCommArray()
4183 {
4184 	if (comm) {
4185 		delete [] comm->array;
4186 		delete comm;
4187 		comm = NULL;
4188 	}
4189 }
4190 
4191 
4192 void
4193 BView::_SetOwner(BWindow *newOwner)
4194 {
4195 	if (!newOwner)
4196 		removeCommArray();
4197 
4198 	if (fOwner != newOwner && fOwner) {
4199 		if (fOwner->fFocus == this)
4200 			MakeFocus(false);
4201 
4202 		if (fOwner->fLastMouseMovedView == this)
4203 			fOwner->fLastMouseMovedView = NULL;
4204 
4205 		fOwner->RemoveHandler(this);
4206 		if (fShelf)
4207 			fOwner->RemoveHandler(fShelf);
4208 	}
4209 
4210 	if (newOwner && newOwner != fOwner) {
4211 		newOwner->AddHandler(this);
4212 		if (fShelf)
4213 			newOwner->AddHandler(fShelf);
4214 
4215 		if (fTopLevelView)
4216 			SetNextHandler(newOwner);
4217 		else
4218 			SetNextHandler(fParent);
4219 	}
4220 
4221 	fOwner = newOwner;
4222 
4223 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling)
4224 		child->_SetOwner(newOwner);
4225 }
4226 
4227 
4228 void
4229 BView::DoPictureClip(BPicture *picture, BPoint where,
4230 	bool invert, bool sync)
4231 {
4232 	if (!picture)
4233 		return;
4234 
4235 	if (do_owner_check()) {
4236 		fOwner->fLink->StartMessage(AS_LAYER_CLIP_TO_PICTURE);
4237 		fOwner->fLink->Attach<int32>(picture->token);
4238 		fOwner->fLink->Attach<BPoint>(where);
4239 		fOwner->fLink->Attach<bool>(invert);
4240 
4241 		// TODO: I think that "sync" means another thing here:
4242 		// the bebook, at least, says so.
4243 		if (sync)
4244 			fOwner->fLink->Flush();
4245 
4246 		fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
4247 	}
4248 
4249 	fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
4250 }
4251 
4252 
4253 bool
4254 BView::_RemoveChildFromList(BView* child)
4255 {
4256 	if (child->fParent != this)
4257 		return false;
4258 
4259 	if (fFirstChild == child) {
4260 		// it's the first view in the list
4261 		fFirstChild = child->fNextSibling;
4262 	} else {
4263 		// there must be a previous sibling
4264 		child->fPreviousSibling->fNextSibling = child->fNextSibling;
4265 	}
4266 
4267 	if (child->fNextSibling)
4268 		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
4269 
4270 	child->fParent = NULL;
4271 	child->fNextSibling = NULL;
4272 	child->fPreviousSibling = NULL;
4273 
4274 	return true;
4275 }
4276 
4277 
4278 bool
4279 BView::_AddChildToList(BView* child, BView* before)
4280 {
4281 	if (!child)
4282 		return false;
4283 	if (child->fParent != NULL) {
4284 		debugger("View already belongs to someone else");
4285 		return false;
4286 	}
4287 	if (before != NULL && before->fParent != this) {
4288 		debugger("Invalid before view");
4289 		return false;
4290 	}
4291 
4292 	if (before != NULL) {
4293 		// add view before this one
4294 		child->fNextSibling = before;
4295 		child->fPreviousSibling = before->fPreviousSibling;
4296 		if (child->fPreviousSibling != NULL)
4297 			child->fPreviousSibling->fNextSibling = child;
4298 
4299 		before->fPreviousSibling = child;
4300 		if (fFirstChild == before)
4301 			fFirstChild = child;
4302 	} else {
4303 		// add view to the end of the list
4304 		BView *last = fFirstChild;
4305 		while (last != NULL && last->fNextSibling != NULL) {
4306 			last = last->fNextSibling;
4307 		}
4308 
4309 		if (last != NULL) {
4310 			last->fNextSibling = child;
4311 			child->fPreviousSibling = last;
4312 		} else {
4313 			fFirstChild = child;
4314 			child->fPreviousSibling = NULL;
4315 		}
4316 
4317 		child->fNextSibling = NULL;
4318 	}
4319 
4320 	child->fParent = this;
4321 	return true;
4322 }
4323 
4324 
4325 /*!	\brief Creates the server counterpart of this view.
4326 	This is only done for views that are part of the view hierarchy, ie. when
4327 	they are attached to a window.
4328 	RemoveSelf() deletes the server object again.
4329 */
4330 bool
4331 BView::_CreateSelf()
4332 {
4333 	// AS_LAYER_CREATE & AS_LAYER_CREATE_ROOT do not use the
4334 	// current view mechanism via check_lock() - the token
4335 	// of the view and its parent are both send to the server.
4336 
4337 	if (fTopLevelView)
4338 		fOwner->fLink->StartMessage(AS_LAYER_CREATE_ROOT);
4339 	else
4340  		fOwner->fLink->StartMessage(AS_LAYER_CREATE);
4341 
4342 	fOwner->fLink->Attach<int32>(_get_object_token_(this));
4343 	fOwner->fLink->AttachString(Name());
4344 	fOwner->fLink->Attach<BRect>(Frame());
4345 	fOwner->fLink->Attach<BPoint>(LeftTop());
4346 	fOwner->fLink->Attach<uint32>(ResizingMode());
4347 	fOwner->fLink->Attach<uint32>(fEventMask);
4348 	fOwner->fLink->Attach<uint32>(fEventOptions);
4349 	fOwner->fLink->Attach<uint32>(Flags());
4350 	fOwner->fLink->Attach<bool>(IsHidden(this));
4351 	fOwner->fLink->Attach<rgb_color>(fState->view_color);
4352 	if (fTopLevelView)
4353 		fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
4354 	else
4355 		fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
4356 	fOwner->fLink->Flush();
4357 
4358 	do_owner_check();
4359 	fState->UpdateServerState(*fOwner->fLink);
4360 
4361 	// we create all its children, too
4362 
4363 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4364 		child->_CreateSelf();
4365 	}
4366 
4367 	fOwner->fLink->Flush();
4368 	return true;
4369 }
4370 
4371 
4372 /*!
4373 	Sets the new view position.
4374 	It doesn't contact the server, though - the only case where this
4375 	is called outside of MoveTo() is as reaction of moving a view
4376 	in the server (a.k.a. B_WINDOW_RESIZED).
4377 	It also calls the BView's FrameMoved() hook.
4378 */
4379 void
4380 BView::_MoveTo(int32 x, int32 y)
4381 {
4382 	fParentOffset.Set(x, y);
4383 
4384 	if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
4385 		BMessage moved(B_VIEW_MOVED);
4386 		moved.AddInt64("when", system_time());
4387 		moved.AddPoint("where", BPoint(x, y));
4388 
4389 		BMessenger target(this);
4390 		target.SendMessage(&moved);
4391 	}
4392 }
4393 
4394 
4395 /*!
4396 	Computes the actual new frame size and recalculates the size of
4397 	the children as well.
4398 	It doesn't contact the server, though - the only case where this
4399 	is called outside of ResizeBy() is as reaction of resizing a view
4400 	in the server (a.k.a. B_WINDOW_RESIZED).
4401 	It also calls the BView's FrameResized() hook.
4402 */
4403 void
4404 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
4405 {
4406 	fBounds.right += deltaWidth;
4407 	fBounds.bottom += deltaHeight;
4408 
4409 	if (Window() == NULL) {
4410 		// we're not supposed to exercise the resizing code in case
4411 		// we haven't been attached to a window yet
4412 		return;
4413 	}
4414 
4415 	// layout the children
4416 	if (fFlags & B_SUPPORTS_LAYOUT) {
4417 		Relayout();
4418 	} else {
4419 		for (BView* child = fFirstChild; child; child = child->fNextSibling)
4420 			child->_ParentResizedBy(deltaWidth, deltaHeight);
4421 	}
4422 
4423 	if (fFlags & B_FRAME_EVENTS) {
4424 		BMessage resized(B_VIEW_RESIZED);
4425 		resized.AddInt64("when", system_time());
4426 		resized.AddFloat("width", fBounds.Width());
4427 		resized.AddFloat("height", fBounds.Height());
4428 
4429 		BMessenger target(this);
4430 		target.SendMessage(&resized);
4431 	}
4432 }
4433 
4434 
4435 /*!
4436 	Relayouts the view according to its resizing mode.
4437 */
4438 void
4439 BView::_ParentResizedBy(int32 x, int32 y)
4440 {
4441 	uint32 resizingMode = fFlags & _RESIZE_MASK_;
4442 	BRect newFrame = Frame();
4443 
4444 	// follow with left side
4445 	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
4446 		newFrame.left += x;
4447 	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
4448 		newFrame.left += x / 2;
4449 
4450 	// follow with right side
4451 	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
4452 		newFrame.right += x;
4453 	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
4454 		newFrame.right += x / 2;
4455 
4456 	// follow with top side
4457 	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
4458 		newFrame.top += y;
4459 	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
4460 		newFrame.top += y / 2;
4461 
4462 	// follow with bottom side
4463 	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
4464 		newFrame.bottom += y;
4465 	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
4466 		newFrame.bottom += y / 2;
4467 
4468 	if (newFrame.LeftTop() != fParentOffset) {
4469 		// move view
4470 		_MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
4471 	}
4472 
4473 	if (newFrame != Frame()) {
4474 		// resize view
4475 		int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
4476 		int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
4477 		_ResizeBy(widthDiff, heightDiff);
4478 	}
4479 }
4480 
4481 
4482 void
4483 BView::_Activate(bool active)
4484 {
4485 	WindowActivated(active);
4486 
4487 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4488 		child->_Activate(active);
4489 	}
4490 }
4491 
4492 
4493 void
4494 BView::_Attach()
4495 {
4496 	AttachedToWindow();
4497 	fAttached = true;
4498 
4499 	// after giving the view a chance to do this itself,
4500 	// check for the B_PULSE_NEEDED flag and make sure the
4501 	// window set's up the pulse messaging
4502 	if (fOwner) {
4503 		if (fFlags & B_PULSE_NEEDED) {
4504 			check_lock_no_pick();
4505 			if (fOwner->fPulseRunner == NULL)
4506 				fOwner->SetPulseRate(fOwner->PulseRate());
4507 		}
4508 
4509 		if (!fOwner->IsHidden())
4510 			Invalidate();
4511 	}
4512 
4513 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) {
4514 		// we need to check for fAttached as new views could have been
4515 		// added in AttachedToWindow() - and those are already attached
4516 		if (!child->fAttached)
4517 			child->_Attach();
4518 	}
4519 
4520 	AllAttached();
4521 }
4522 
4523 
4524 void
4525 BView::_Detach()
4526 {
4527 	DetachedFromWindow();
4528 	fAttached = false;
4529 
4530 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) {
4531 		child->_Detach();
4532 	}
4533 
4534 	AllDetached();
4535 
4536 	if (fOwner) {
4537 		check_lock_no_pick();
4538 
4539 		if (!fOwner->IsHidden())
4540 			Invalidate();
4541 
4542 		// make sure our owner doesn't need us anymore
4543 
4544 		if (fOwner->CurrentFocus() == this)
4545 			MakeFocus(false);
4546 
4547 		if (fOwner->fDefaultButton == this)
4548 			fOwner->SetDefaultButton(NULL);
4549 
4550 		if (fOwner->fKeyMenuBar == this)
4551 			fOwner->fKeyMenuBar = NULL;
4552 
4553 		if (fOwner->fLastMouseMovedView == this)
4554 			fOwner->fLastMouseMovedView = NULL;
4555 
4556 		if (fOwner->fLastViewToken == _get_object_token_(this))
4557 			fOwner->fLastViewToken = B_NULL_TOKEN;
4558 
4559 		_SetOwner(NULL);
4560 	}
4561 }
4562 
4563 
4564 void
4565 BView::_Draw(BRect updateRectScreen)
4566 {
4567 	if (IsHidden(this))
4568 		return;
4569 
4570 	check_lock();
4571 
4572 	ConvertFromScreen(&updateRectScreen);
4573 	BRect updateRect = Bounds() & updateRectScreen;
4574 
4575 	if (Flags() & B_WILL_DRAW) {
4576 		// TODO: make states robust
4577 		PushState();
4578 		Draw(updateRect);
4579 		PopState();
4580 		Flush();
4581 //	} else {
4582 		// ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
4583 		// -> View is simply not drawn at all
4584 	}
4585 
4586 //	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4587 //		BRect rect = child->Frame();
4588 //		if (!updateRect.Intersects(rect))
4589 //			continue;
4590 //
4591 //		// get new update rect in child coordinates
4592 //		rect = updateRect & rect;
4593 //		child->ConvertFromParent(&rect);
4594 //
4595 //		child->_Draw(rect);
4596 //	}
4597 //
4598 //	if (Flags() & B_DRAW_ON_CHILDREN) {
4599 //		// TODO: Since we have hard clipping in the app_server,
4600 //		// a view can never draw "on top of it's child views" as
4601 //		// the BeBook describes.
4602 //		// (TODO: Test if this is really possible in BeOS.)
4603 //		PushState();
4604 //		DrawAfterChildren(updateRect);
4605 //		PopState();
4606 //		Flush();
4607 //	}
4608 }
4609 
4610 
4611 void
4612 BView::_Pulse()
4613 {
4614 	if (Flags() & B_PULSE_NEEDED)
4615 		Pulse();
4616 
4617 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4618 		child->_Pulse();
4619 	}
4620 }
4621 
4622 
4623 void
4624 BView::_UpdateStateForRemove()
4625 {
4626 	if (!do_owner_check())
4627 		return;
4628 
4629 	fState->UpdateFrom(*fOwner->fLink);
4630 	if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
4631 		fOwner->fLink->StartMessage(AS_LAYER_GET_COORD);
4632 
4633 		status_t code;
4634 		if (fOwner->fLink->FlushWithReply(code) == B_OK
4635 			&& code == B_OK) {
4636 			fOwner->fLink->Read<BPoint>(&fParentOffset);
4637 			fOwner->fLink->Read<BRect>(&fBounds);
4638 			fState->valid_flags |= B_VIEW_FRAME_BIT;
4639 		}
4640 	}
4641 
4642 	// update children as well
4643 
4644 	for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) {
4645 		if (child->fOwner)
4646 			child->_UpdateStateForRemove();
4647 	}
4648 }
4649 
4650 
4651 inline void
4652 BView::_UpdatePattern(::pattern pattern)
4653 {
4654 	if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
4655 		return;
4656 
4657 	if (fOwner) {
4658 		check_lock();
4659 
4660 		fOwner->fLink->StartMessage(AS_LAYER_SET_PATTERN);
4661 		fOwner->fLink->Attach< ::pattern>(pattern);
4662 
4663 		fState->valid_flags |= B_VIEW_PATTERN_BIT;
4664 	}
4665 
4666 	fState->pattern = pattern;
4667 }
4668 
4669 
4670 void
4671 BView::_FlushIfNotInTransaction()
4672 {
4673 	if (!fOwner->fInTransaction) {
4674 		fOwner->Flush();
4675 	}
4676 }
4677 
4678 
4679 BShelf *
4680 BView::_Shelf() const
4681 {
4682 	return fShelf;
4683 }
4684 
4685 
4686 void
4687 BView::_SetShelf(BShelf *shelf)
4688 {
4689 	if (fShelf != NULL && fOwner != NULL)
4690 		fOwner->RemoveHandler(fShelf);
4691 
4692 	fShelf = shelf;
4693 
4694 	if (fShelf != NULL && fOwner != NULL)
4695 		fOwner->AddHandler(fShelf);
4696 }
4697 
4698 
4699 status_t
4700 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect,
4701 	BRect dstRect, uint32 followFlags, uint32 options)
4702 {
4703 	if (!do_owner_check())
4704 		return B_ERROR;
4705 
4706 	int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
4707 
4708 	fOwner->fLink->StartMessage(AS_LAYER_SET_VIEW_BITMAP);
4709 	fOwner->fLink->Attach<int32>(serverToken);
4710 	fOwner->fLink->Attach<BRect>(srcRect);
4711 	fOwner->fLink->Attach<BRect>(dstRect);
4712 	fOwner->fLink->Attach<int32>(followFlags);
4713 	fOwner->fLink->Attach<int32>(options);
4714 
4715 	status_t status = B_ERROR;
4716 	fOwner->fLink->FlushWithReply(status);
4717 
4718 	return status;
4719 }
4720 
4721 
4722 bool
4723 BView::do_owner_check() const
4724 {
4725 	STRACE(("BView(%s)::do_owner_check()...", Name()));
4726 
4727 	int32 serverToken = _get_object_token_(this);
4728 
4729 	if (fOwner == NULL) {
4730 		debugger("View method requires owner and doesn't have one.");
4731 		return false;
4732 	}
4733 
4734 	fOwner->check_lock();
4735 
4736 	if (fOwner->fLastViewToken != serverToken) {
4737 		STRACE(("contacting app_server... sending token: %ld\n", serverToken));
4738 		fOwner->fLink->StartMessage(AS_SET_CURRENT_LAYER);
4739 		fOwner->fLink->Attach<int32>(serverToken);
4740 
4741 		fOwner->fLastViewToken = serverToken;
4742 	} else
4743 		STRACE(("this is the lastViewToken\n"));
4744 
4745 	return true;
4746 }
4747 
4748 
4749 void
4750 BView::check_lock() const
4751 {
4752 	STRACE(("BView(%s)::check_lock()...", Name() ? Name(): "NULL"));
4753 
4754 	if (!fOwner)
4755 		return;
4756 
4757 	fOwner->check_lock();
4758 
4759 	int32 serverToken = _get_object_token_(this);
4760 
4761 	if (fOwner->fLastViewToken != serverToken) {
4762 		STRACE(("contacting app_server... sending token: %ld\n", serverToken));
4763 		fOwner->fLink->StartMessage(AS_SET_CURRENT_LAYER);
4764 		fOwner->fLink->Attach<int32>(serverToken);
4765 
4766 		fOwner->fLastViewToken = serverToken;
4767 	} else {
4768 		STRACE(("quiet2\n"));
4769 	}
4770 }
4771 
4772 
4773 void
4774 BView::check_lock_no_pick() const
4775 {
4776 	if (fOwner)
4777 		fOwner->check_lock();
4778 }
4779 
4780 
4781 bool
4782 BView::do_owner_check_no_pick() const
4783 {
4784 	if (fOwner) {
4785 		fOwner->check_lock();
4786 		return true;
4787 	} else {
4788 		debugger("View method requires owner and doesn't have one.");
4789 		return false;
4790 	}
4791 }
4792 
4793 extern "C" void _ReservedView1__5BView() {}
4794 extern "C" void _ReservedView2__5BView() {}
4795 extern "C" void _ReservedView3__5BView() {}
4796 extern "C" void _ReservedView4__5BView() {}
4797 extern "C" void _ReservedView5__5BView() {}
4798 extern "C" void _ReservedView6__5BView() {}
4799 extern "C" void _ReservedView7__5BView() {}
4800 extern "C" void _ReservedView8__5BView() {}
4801 extern "C" void _ReservedView9__5BView() {}
4802 void BView::_ReservedView10(){}
4803 void BView::_ReservedView11(){}
4804 void BView::_ReservedView12(){}
4805 void BView::_ReservedView13(){}
4806 void BView::_ReservedView14(){}
4807 void BView::_ReservedView15(){}
4808 void BView::_ReservedView16(){}
4809 
4810 
4811 BView::BView(const BView &other)
4812 	: BHandler()
4813 {
4814 	// this is private and not functional, but exported
4815 }
4816 
4817 
4818 BView &
4819 BView::operator=(const BView &other)
4820 {
4821 	// this is private and not functional, but exported
4822 	return *this;
4823 }
4824 
4825 
4826 void
4827 BView::PrintToStream()
4828 {
4829 	printf("BView::PrintToStream()\n");
4830 	printf("\tName: %s\
4831 \tParent: %s\
4832 \tFirstChild: %s\
4833 \tNextSibling: %s\
4834 \tPrevSibling: %s\
4835 \tOwner(Window): %s\
4836 \tToken: %ld\
4837 \tFlags: %ld\
4838 \tView origin: (%f,%f)\
4839 \tView Bounds rectangle: (%f,%f,%f,%f)\
4840 \tShow level: %d\
4841 \tTopView?: %s\
4842 \tBPicture: %s\
4843 \tVertical Scrollbar %s\
4844 \tHorizontal Scrollbar %s\
4845 \tIs Printing?: %s\
4846 \tShelf?: %s\
4847 \tEventMask: %ld\
4848 \tEventOptions: %ld\n",
4849 	Name(),
4850 	fParent ? fParent->Name() : "NULL",
4851 	fFirstChild ? fFirstChild->Name() : "NULL",
4852 	fNextSibling ? fNextSibling->Name() : "NULL",
4853 	fPreviousSibling ? fPreviousSibling->Name() : "NULL",
4854 	fOwner ? fOwner->Name() : "NULL",
4855 	_get_object_token_(this),
4856 	fFlags,
4857 	fParentOffset.x, fParentOffset.y,
4858 	fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
4859 	fShowLevel,
4860 	fTopLevelView ? "YES" : "NO",
4861 	cpicture? "YES" : "NULL",
4862 	fVerScroller? "YES" : "NULL",
4863 	fHorScroller? "YES" : "NULL",
4864 	f_is_printing? "YES" : "NO",
4865 	fShelf? "YES" : "NO",
4866 	fEventMask,
4867 	fEventOptions);
4868 
4869 	printf("\tState status:\
4870 \t\tLocalCoordianteSystem: (%f,%f)\
4871 \t\tPenLocation: (%f,%f)\
4872 \t\tPenSize: %f\
4873 \t\tHighColor: [%d,%d,%d,%d]\
4874 \t\tLowColor: [%d,%d,%d,%d]\
4875 \t\tViewColor: [%d,%d,%d,%d]\
4876 \t\tPattern: %llx\
4877 \t\tDrawingMode: %d\
4878 \t\tLineJoinMode: %d\
4879 \t\tLineCapMode: %d\
4880 \t\tMiterLimit: %f\
4881 \t\tAlphaSource: %d\
4882 \t\tAlphaFuntion: %d\
4883 \t\tScale: %f\
4884 \t\t(Print)FontAliasing: %s\
4885 \t\tFont Info:\n",
4886 	fState->origin.x, fState->origin.y,
4887 	fState->pen_location.x, fState->pen_location.y,
4888 	fState->pen_size,
4889 	fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
4890 	fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
4891 	fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
4892 	*((uint64*)&(fState->pattern)),
4893 	fState->drawing_mode,
4894 	fState->line_join,
4895 	fState->line_cap,
4896 	fState->miter_limit,
4897 	fState->alpha_source_mode,
4898 	fState->alpha_function_mode,
4899 	fState->scale,
4900 	fState->font_aliasing? "YES" : "NO");
4901 
4902 	fState->font.PrintToStream();
4903 
4904 	// TODO: also print the line array.
4905 }
4906 
4907 
4908 void
4909 BView::PrintTree()
4910 {
4911 	int32 spaces = 2;
4912 	BView *c = fFirstChild; //c = short for: current
4913 	printf( "'%s'\n", Name() );
4914 	if (c != NULL) {
4915 		while(true) {
4916 			// action block
4917 			{
4918 				for (int i = 0; i < spaces; i++)
4919 					printf(" ");
4920 
4921 				printf( "'%s'\n", c->Name() );
4922 			}
4923 
4924 			// go deep
4925 			if (c->fFirstChild) {
4926 				c = c->fFirstChild;
4927 				spaces += 2;
4928 			} else {
4929 				// go right
4930 				if (c->fNextSibling) {
4931 					c = c->fNextSibling;
4932 				} else {
4933 					// go up
4934 					while (!c->fParent->fNextSibling && c->fParent != this) {
4935 						c = c->fParent;
4936 						spaces -= 2;
4937 					}
4938 
4939 					// that enough! We've reached this view.
4940 					if (c->fParent == this)
4941 						break;
4942 
4943 					c = c->fParent->fNextSibling;
4944 					spaces -= 2;
4945 				}
4946 			}
4947 		}
4948 	}
4949 }
4950 
4951 
4952 /* TODO:
4953  	-implement SetDiskMode(). What's with this method? What does it do? test!
4954  		does it has something to do with DrawPictureAsync( filename* .. )?
4955 	-implement DrawAfterChildren()
4956 */
4957