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