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