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