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