xref: /haiku/src/kits/interface/View.cpp (revision 06b79f550944f3a88a70d9fa17ddfe804721253a)
1 /*
2  * Copyright 2001-2017 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 }
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, -1, -1), 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 				FrameResized(message->GetInt32("width", 0),
4898 					message->GetInt32("height", 0));
4899 				break;
4900 
4901 			case B_VIEW_MOVED:
4902 				FrameMoved(fParentOffset);
4903 				break;
4904 
4905 			case B_MOUSE_IDLE:
4906 			{
4907 				BPoint where;
4908 				if (message->FindPoint("be:view_where", &where) != B_OK)
4909 					break;
4910 
4911 				BToolTip* tip;
4912 				if (GetToolTipAt(where, &tip))
4913 					ShowToolTip(tip);
4914 				else
4915 					BHandler::MessageReceived(message);
4916 				break;
4917 			}
4918 
4919 			case B_MOUSE_WHEEL_CHANGED:
4920 			{
4921 				BScrollBar* horizontal = ScrollBar(B_HORIZONTAL);
4922 				BScrollBar* vertical = ScrollBar(B_VERTICAL);
4923 				if (horizontal == NULL && vertical == NULL) {
4924 					// Pass the message to the next handler
4925 					BHandler::MessageReceived(message);
4926 					break;
4927 				}
4928 
4929 				float deltaX = 0.0f;
4930 				float deltaY = 0.0f;
4931 
4932 				if (horizontal != NULL)
4933 					message->FindFloat("be:wheel_delta_x", &deltaX);
4934 
4935 				if (vertical != NULL)
4936 					message->FindFloat("be:wheel_delta_y", &deltaY);
4937 
4938 				if (deltaX == 0.0f && deltaY == 0.0f)
4939 					break;
4940 
4941 				if ((modifiers() & B_CONTROL_KEY) != 0)
4942 					std::swap(horizontal, vertical);
4943 
4944 				if (horizontal != NULL && deltaX != 0.0f)
4945 					ScrollWithMouseWheelDelta(horizontal, deltaX);
4946 
4947 				if (vertical != NULL && deltaY != 0.0f)
4948 					ScrollWithMouseWheelDelta(vertical, deltaY);
4949 
4950 				break;
4951 			}
4952 
4953 			// prevent message repeats
4954 			case B_COLORS_UPDATED:
4955 			case B_FONTS_UPDATED:
4956 				break;
4957 
4958 			case B_SCREEN_CHANGED:
4959 			{
4960 				// propegate message to child views
4961 				int32 childCount = CountChildren();
4962 				for (int32 i = 0; i < childCount; i++) {
4963 					BView* view = ChildAt(i);
4964 					if (view != NULL)
4965 						view->MessageReceived(message);
4966 				}
4967 				break;
4968 			}
4969 
4970 			default:
4971 				BHandler::MessageReceived(message);
4972 				break;
4973 		}
4974 
4975 		return;
4976 	}
4977 
4978 	// Scripting message
4979 
4980 	BMessage replyMsg(B_REPLY);
4981 	status_t err = B_BAD_SCRIPT_SYNTAX;
4982 	int32 index;
4983 	BMessage specifier;
4984 	int32 what;
4985 	const char* property;
4986 
4987 	if (message->GetCurrentSpecifier(&index, &specifier, &what, &property)
4988 			!= B_OK) {
4989 		return BHandler::MessageReceived(message);
4990 	}
4991 
4992 	BPropertyInfo propertyInfo(sViewPropInfo);
4993 	switch (propertyInfo.FindMatch(message, index, &specifier, what,
4994 			property)) {
4995 		case 0:
4996 			if (message->what == B_GET_PROPERTY) {
4997 				err = replyMsg.AddRect("result", Frame());
4998 			} else if (message->what == B_SET_PROPERTY) {
4999 				BRect newFrame;
5000 				err = message->FindRect("data", &newFrame);
5001 				if (err == B_OK) {
5002 					MoveTo(newFrame.LeftTop());
5003 					ResizeTo(newFrame.Width(), newFrame.Height());
5004 				}
5005 			}
5006 			break;
5007 		case 1:
5008 			if (message->what == B_GET_PROPERTY) {
5009 				err = replyMsg.AddBool("result", IsHidden());
5010 			} else if (message->what == B_SET_PROPERTY) {
5011 				bool newHiddenState;
5012 				err = message->FindBool("data", &newHiddenState);
5013 				if (err == B_OK) {
5014 					if (newHiddenState == true)
5015 						Hide();
5016 					else
5017 						Show();
5018 				}
5019 			}
5020 			break;
5021 		case 3:
5022 			err = replyMsg.AddInt32("result", CountChildren());
5023 			break;
5024 		default:
5025 			return BHandler::MessageReceived(message);
5026 	}
5027 
5028 	if (err != B_OK) {
5029 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
5030 
5031 		if (err == B_BAD_SCRIPT_SYNTAX)
5032 			replyMsg.AddString("message", "Didn't understand the specifier(s)");
5033 		else
5034 			replyMsg.AddString("message", strerror(err));
5035 
5036 		replyMsg.AddInt32("error", err);
5037 	}
5038 
5039 	message->SendReply(&replyMsg);
5040 }
5041 
5042 
5043 status_t
5044 BView::Perform(perform_code code, void* _data)
5045 {
5046 	switch (code) {
5047 		case PERFORM_CODE_MIN_SIZE:
5048 			((perform_data_min_size*)_data)->return_value
5049 				= BView::MinSize();
5050 			return B_OK;
5051 		case PERFORM_CODE_MAX_SIZE:
5052 			((perform_data_max_size*)_data)->return_value
5053 				= BView::MaxSize();
5054 			return B_OK;
5055 		case PERFORM_CODE_PREFERRED_SIZE:
5056 			((perform_data_preferred_size*)_data)->return_value
5057 				= BView::PreferredSize();
5058 			return B_OK;
5059 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
5060 			((perform_data_layout_alignment*)_data)->return_value
5061 				= BView::LayoutAlignment();
5062 			return B_OK;
5063 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
5064 			((perform_data_has_height_for_width*)_data)->return_value
5065 				= BView::HasHeightForWidth();
5066 			return B_OK;
5067 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
5068 		{
5069 			perform_data_get_height_for_width* data
5070 				= (perform_data_get_height_for_width*)_data;
5071 			BView::GetHeightForWidth(data->width, &data->min, &data->max,
5072 				&data->preferred);
5073 			return B_OK;
5074 		}
5075 		case PERFORM_CODE_SET_LAYOUT:
5076 		{
5077 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
5078 			BView::SetLayout(data->layout);
5079 			return B_OK;
5080 		}
5081 		case PERFORM_CODE_LAYOUT_INVALIDATED:
5082 		{
5083 			perform_data_layout_invalidated* data
5084 				= (perform_data_layout_invalidated*)_data;
5085 			BView::LayoutInvalidated(data->descendants);
5086 			return B_OK;
5087 		}
5088 		case PERFORM_CODE_DO_LAYOUT:
5089 		{
5090 			BView::DoLayout();
5091 			return B_OK;
5092 		}
5093 		case PERFORM_CODE_LAYOUT_CHANGED:
5094 		{
5095 			BView::LayoutChanged();
5096 			return B_OK;
5097 		}
5098 		case PERFORM_CODE_GET_TOOL_TIP_AT:
5099 		{
5100 			perform_data_get_tool_tip_at* data
5101 				= (perform_data_get_tool_tip_at*)_data;
5102 			data->return_value
5103 				= BView::GetToolTipAt(data->point, data->tool_tip);
5104 			return B_OK;
5105 		}
5106 		case PERFORM_CODE_ALL_UNARCHIVED:
5107 		{
5108 			perform_data_all_unarchived* data =
5109 				(perform_data_all_unarchived*)_data;
5110 
5111 			data->return_value = BView::AllUnarchived(data->archive);
5112 			return B_OK;
5113 		}
5114 		case PERFORM_CODE_ALL_ARCHIVED:
5115 		{
5116 			perform_data_all_archived* data =
5117 				(perform_data_all_archived*)_data;
5118 
5119 			data->return_value = BView::AllArchived(data->archive);
5120 			return B_OK;
5121 		}
5122 	}
5123 
5124 	return BHandler::Perform(code, _data);
5125 }
5126 
5127 
5128 // #pragma mark - Layout Functions
5129 
5130 
5131 BSize
5132 BView::MinSize()
5133 {
5134 	// TODO: make sure this works correctly when some methods are overridden
5135 	float width, height;
5136 	GetPreferredSize(&width, &height);
5137 
5138 	return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
5139 		(fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
5140 			: BSize(width, height)));
5141 }
5142 
5143 
5144 BSize
5145 BView::MaxSize()
5146 {
5147 	return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
5148 		(fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
5149 			: BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
5150 }
5151 
5152 
5153 BSize
5154 BView::PreferredSize()
5155 {
5156 	// TODO: make sure this works correctly when some methods are overridden
5157 	float width, height;
5158 	GetPreferredSize(&width, &height);
5159 
5160 	return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
5161 		(fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
5162 			: BSize(width, height)));
5163 }
5164 
5165 
5166 BAlignment
5167 BView::LayoutAlignment()
5168 {
5169 	return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
5170 		(fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
5171 			: BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
5172 }
5173 
5174 
5175 void
5176 BView::SetExplicitMinSize(BSize size)
5177 {
5178 	fLayoutData->fMinSize = size;
5179 	InvalidateLayout();
5180 }
5181 
5182 
5183 void
5184 BView::SetExplicitMaxSize(BSize size)
5185 {
5186 	fLayoutData->fMaxSize = size;
5187 	InvalidateLayout();
5188 }
5189 
5190 
5191 void
5192 BView::SetExplicitPreferredSize(BSize size)
5193 {
5194 	fLayoutData->fPreferredSize = size;
5195 	InvalidateLayout();
5196 }
5197 
5198 
5199 void
5200 BView::SetExplicitSize(BSize size)
5201 {
5202 	fLayoutData->fMinSize = size;
5203 	fLayoutData->fMaxSize = size;
5204 	fLayoutData->fPreferredSize = size;
5205 	InvalidateLayout();
5206 }
5207 
5208 
5209 void
5210 BView::SetExplicitAlignment(BAlignment alignment)
5211 {
5212 	fLayoutData->fAlignment = alignment;
5213 	InvalidateLayout();
5214 }
5215 
5216 
5217 BSize
5218 BView::ExplicitMinSize() const
5219 {
5220 	return fLayoutData->fMinSize;
5221 }
5222 
5223 
5224 BSize
5225 BView::ExplicitMaxSize() const
5226 {
5227 	return fLayoutData->fMaxSize;
5228 }
5229 
5230 
5231 BSize
5232 BView::ExplicitPreferredSize() const
5233 {
5234 	return fLayoutData->fPreferredSize;
5235 }
5236 
5237 
5238 BAlignment
5239 BView::ExplicitAlignment() const
5240 {
5241 	return fLayoutData->fAlignment;
5242 }
5243 
5244 
5245 bool
5246 BView::HasHeightForWidth()
5247 {
5248 	return (fLayoutData->fLayout
5249 		? fLayoutData->fLayout->HasHeightForWidth() : false);
5250 }
5251 
5252 
5253 void
5254 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
5255 {
5256 	if (fLayoutData->fLayout)
5257 		fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
5258 }
5259 
5260 
5261 void
5262 BView::SetLayout(BLayout* layout)
5263 {
5264 	if (layout == fLayoutData->fLayout)
5265 		return;
5266 
5267 	if (layout && layout->Layout())
5268 		debugger("BView::SetLayout() failed, layout is already in use.");
5269 
5270 	fFlags |= B_SUPPORTS_LAYOUT;
5271 
5272 	// unset and delete the old layout
5273 	if (fLayoutData->fLayout) {
5274 		fLayoutData->fLayout->RemoveSelf();
5275 		fLayoutData->fLayout->SetOwner(NULL);
5276 		delete fLayoutData->fLayout;
5277 	}
5278 
5279 	fLayoutData->fLayout = layout;
5280 
5281 	if (fLayoutData->fLayout) {
5282 		fLayoutData->fLayout->SetOwner(this);
5283 
5284 		// add all children
5285 		int count = CountChildren();
5286 		for (int i = 0; i < count; i++)
5287 			fLayoutData->fLayout->AddView(ChildAt(i));
5288 	}
5289 
5290 	InvalidateLayout();
5291 }
5292 
5293 
5294 BLayout*
5295 BView::GetLayout() const
5296 {
5297 	return fLayoutData->fLayout;
5298 }
5299 
5300 
5301 void
5302 BView::InvalidateLayout(bool descendants)
5303 {
5304 	// printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
5305 	//	this, descendants, fLayoutData->fLayoutValid,
5306 	//	fLayoutData->fLayoutInProgress);
5307 
5308 	if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
5309  			|| fLayoutData->fLayoutInvalidationDisabled > 0) {
5310 		return;
5311 	}
5312 	fLayoutData->fLayoutValid = false;
5313 	fLayoutData->fMinMaxValid = false;
5314 	LayoutInvalidated(descendants);
5315 
5316 	if (descendants) {
5317 		for (BView* child = fFirstChild;
5318 			child; child = child->fNextSibling) {
5319 			child->InvalidateLayout(descendants);
5320 		}
5321 	}
5322 
5323 	if (fLayoutData->fLayout)
5324 		fLayoutData->fLayout->InvalidateLayout(descendants);
5325 	else
5326 		_InvalidateParentLayout();
5327 
5328 	if (fTopLevelView
5329 		&& fOwner != NULL)
5330 		fOwner->PostMessage(B_LAYOUT_WINDOW);
5331 }
5332 
5333 
5334 void
5335 BView::EnableLayoutInvalidation()
5336 {
5337 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
5338 		fLayoutData->fLayoutInvalidationDisabled--;
5339 }
5340 
5341 
5342 void
5343 BView::DisableLayoutInvalidation()
5344 {
5345 	fLayoutData->fLayoutInvalidationDisabled++;
5346 }
5347 
5348 
5349 bool
5350 BView::IsLayoutInvalidationDisabled()
5351 {
5352 	if (fLayoutData->fLayoutInvalidationDisabled > 0)
5353 		return true;
5354 	return false;
5355 }
5356 
5357 
5358 bool
5359 BView::IsLayoutValid() const
5360 {
5361 	return fLayoutData->fLayoutValid;
5362 }
5363 
5364 
5365 void
5366 BView::ResetLayoutInvalidation()
5367 {
5368 	fLayoutData->fMinMaxValid = true;
5369 }
5370 
5371 
5372 BLayoutContext*
5373 BView::LayoutContext() const
5374 {
5375 	return fLayoutData->fLayoutContext;
5376 }
5377 
5378 
5379 void
5380 BView::Layout(bool force)
5381 {
5382 	BLayoutContext context;
5383 	_Layout(force, &context);
5384 }
5385 
5386 
5387 void
5388 BView::Relayout()
5389 {
5390 	if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
5391 		fLayoutData->fNeedsRelayout = true;
5392 		if (fLayoutData->fLayout)
5393 			fLayoutData->fLayout->RequireLayout();
5394 
5395 		// Layout() is recursive, that is if the parent view is currently laid
5396 		// out, we don't call layout() on this view, but wait for the parent's
5397 		// Layout() to do that for us.
5398 		if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
5399 			Layout(false);
5400 	}
5401 }
5402 
5403 
5404 void
5405 BView::LayoutInvalidated(bool descendants)
5406 {
5407 	// hook method
5408 }
5409 
5410 
5411 void
5412 BView::DoLayout()
5413 {
5414 	if (fLayoutData->fLayout)
5415 		fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
5416 }
5417 
5418 
5419 void
5420 BView::SetToolTip(const char* text)
5421 {
5422 	if (text == NULL || text[0] == '\0') {
5423 		SetToolTip((BToolTip*)NULL);
5424 		return;
5425 	}
5426 
5427 	if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
5428 		tip->SetText(text);
5429 	else
5430 		SetToolTip(new BTextToolTip(text));
5431 }
5432 
5433 
5434 void
5435 BView::SetToolTip(BToolTip* tip)
5436 {
5437 	if (fToolTip == tip)
5438 		return;
5439 	else if (tip == NULL)
5440 		HideToolTip();
5441 
5442 	if (fToolTip != NULL)
5443 		fToolTip->ReleaseReference();
5444 
5445 	fToolTip = tip;
5446 
5447 	if (fToolTip != NULL)
5448 		fToolTip->AcquireReference();
5449 }
5450 
5451 
5452 BToolTip*
5453 BView::ToolTip() const
5454 {
5455 	return fToolTip;
5456 }
5457 
5458 
5459 void
5460 BView::ShowToolTip(BToolTip* tip)
5461 {
5462 	if (tip == NULL)
5463 		return;
5464 
5465 	BPoint where;
5466 	GetMouse(&where, NULL, false);
5467 
5468 	BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
5469 }
5470 
5471 
5472 void
5473 BView::HideToolTip()
5474 {
5475 	BToolTipManager::Manager()->HideTip();
5476 }
5477 
5478 
5479 bool
5480 BView::GetToolTipAt(BPoint point, BToolTip** _tip)
5481 {
5482 	if (fToolTip != NULL) {
5483 		*_tip = fToolTip;
5484 		return true;
5485 	}
5486 
5487 	*_tip = NULL;
5488 	return false;
5489 }
5490 
5491 
5492 void
5493 BView::LayoutChanged()
5494 {
5495 	// hook method
5496 }
5497 
5498 
5499 void
5500 BView::_Layout(bool force, BLayoutContext* context)
5501 {
5502 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
5503 //printf("  fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
5504 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
5505 //fLayoutData->fLayoutInProgress);
5506 	if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
5507 		fLayoutData->fLayoutValid = false;
5508 
5509 		if (fLayoutData->fLayoutInProgress)
5510 			return;
5511 
5512 		BLayoutContext* oldContext = fLayoutData->fLayoutContext;
5513 		fLayoutData->fLayoutContext = context;
5514 
5515 		fLayoutData->fLayoutInProgress = true;
5516 		DoLayout();
5517 		fLayoutData->fLayoutInProgress = false;
5518 
5519 		fLayoutData->fLayoutValid = true;
5520 		fLayoutData->fMinMaxValid = true;
5521 		fLayoutData->fNeedsRelayout = false;
5522 
5523 		// layout children
5524 		for(BView* child = fFirstChild; child; child = child->fNextSibling) {
5525 			if (!child->IsHidden(child))
5526 				child->_Layout(force, context);
5527 		}
5528 
5529 		LayoutChanged();
5530 
5531 		fLayoutData->fLayoutContext = oldContext;
5532 
5533 		// invalidate the drawn content, if requested
5534 		if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
5535 			Invalidate();
5536 	}
5537 }
5538 
5539 
5540 void
5541 BView::_LayoutLeft(BLayout* deleted)
5542 {
5543 	// If our layout is added to another layout (via BLayout::AddItem())
5544 	// then we share ownership of our layout. In the event that our layout gets
5545 	// deleted by the layout it has been added to, this method is called so
5546 	// that we don't double-delete our layout.
5547 	if (fLayoutData->fLayout == deleted)
5548 		fLayoutData->fLayout = NULL;
5549 	InvalidateLayout();
5550 }
5551 
5552 
5553 void
5554 BView::_InvalidateParentLayout()
5555 {
5556 	if (!fParent)
5557 		return;
5558 
5559 	BLayout* layout = fLayoutData->fLayout;
5560 	BLayout* layoutParent = layout ? layout->Layout() : NULL;
5561 	if (layoutParent) {
5562 		layoutParent->InvalidateLayout();
5563 	} else if (fLayoutData->fLayoutItems.CountItems() > 0) {
5564 		int32 count = fLayoutData->fLayoutItems.CountItems();
5565 		for (int32 i = 0; i < count; i++) {
5566 			fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
5567 		}
5568 	} else {
5569 		fParent->InvalidateLayout();
5570 	}
5571 }
5572 
5573 
5574 //	#pragma mark - Private Functions
5575 
5576 
5577 void
5578 BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
5579 	uint32 flags)
5580 {
5581 	// Info: The name of the view is set by BHandler constructor
5582 
5583 	STRACE(("BView::_InitData: enter\n"));
5584 
5585 	// initialize members
5586 	if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
5587 		printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
5588 
5589 	// There are applications that swap the resize mask and the flags in the
5590 	// BView constructor. This does not cause problems under BeOS as it just
5591 	// ors the two fields to one 32bit flag.
5592 	// For now we do the same but print the above warning message.
5593 	// TODO: this should be removed at some point and the original
5594 	// version restored:
5595 	// fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
5596 	fFlags = resizingMode | flags;
5597 
5598 	// handle rounding
5599 	frame.left = roundf(frame.left);
5600 	frame.top = roundf(frame.top);
5601 	frame.right = roundf(frame.right);
5602 	frame.bottom = roundf(frame.bottom);
5603 
5604 	fParentOffset.Set(frame.left, frame.top);
5605 
5606 	fOwner = NULL;
5607 	fParent = NULL;
5608 	fNextSibling = NULL;
5609 	fPreviousSibling = NULL;
5610 	fFirstChild = NULL;
5611 
5612 	fShowLevel = 0;
5613 	fTopLevelView = false;
5614 
5615 	fCurrentPicture = NULL;
5616 	fCommArray = NULL;
5617 
5618 	fVerScroller = NULL;
5619 	fHorScroller = NULL;
5620 
5621 	fIsPrinting = false;
5622 	fAttached = false;
5623 
5624 	// TODO: Since we cannot communicate failure, we don't use std::nothrow here
5625 	// TODO: Maybe we could auto-delete those views on AddChild() instead?
5626 	fState = new BPrivate::ViewState;
5627 
5628 	fBounds = frame.OffsetToCopy(B_ORIGIN);
5629 	fShelf = NULL;
5630 
5631 	fEventMask = 0;
5632 	fEventOptions = 0;
5633 	fMouseEventOptions = 0;
5634 
5635 	fLayoutData = new LayoutData;
5636 
5637 	fToolTip = NULL;
5638 
5639 	if ((flags & B_SUPPORTS_LAYOUT) != 0) {
5640 		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
5641 		SetLowUIColor(ViewUIColor());
5642 		SetHighUIColor(B_PANEL_TEXT_COLOR);
5643 	}
5644 }
5645 
5646 
5647 void
5648 BView::_RemoveCommArray()
5649 {
5650 	if (fCommArray) {
5651 		delete [] fCommArray->array;
5652 		delete fCommArray;
5653 		fCommArray = NULL;
5654 	}
5655 }
5656 
5657 
5658 void
5659 BView::_SetOwner(BWindow* newOwner)
5660 {
5661 	if (!newOwner)
5662 		_RemoveCommArray();
5663 
5664 	if (fOwner != newOwner && fOwner) {
5665 		if (fOwner->fFocus == this)
5666 			MakeFocus(false);
5667 
5668 		if (fOwner->fLastMouseMovedView == this)
5669 			fOwner->fLastMouseMovedView = NULL;
5670 
5671 		fOwner->RemoveHandler(this);
5672 		if (fShelf)
5673 			fOwner->RemoveHandler(fShelf);
5674 	}
5675 
5676 	if (newOwner && newOwner != fOwner) {
5677 		newOwner->AddHandler(this);
5678 		if (fShelf)
5679 			newOwner->AddHandler(fShelf);
5680 
5681 		if (fTopLevelView)
5682 			SetNextHandler(newOwner);
5683 		else
5684 			SetNextHandler(fParent);
5685 	}
5686 
5687 	fOwner = newOwner;
5688 
5689 	for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5690 		child->_SetOwner(newOwner);
5691 }
5692 
5693 
5694 void
5695 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5696 {
5697 	if (!_CheckOwnerLockAndSwitchCurrent())
5698 		return;
5699 
5700 	if (picture == NULL) {
5701 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5702 		fOwner->fLink->Attach<int32>(-1);
5703 
5704 		// NOTE: No need to sync here, since the -1 token cannot
5705 		// become invalid on the server.
5706 	} else {
5707 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5708 		fOwner->fLink->Attach<int32>(picture->Token());
5709 		fOwner->fLink->Attach<BPoint>(where);
5710 		fOwner->fLink->Attach<bool>(invert);
5711 
5712 		// NOTE: "sync" defaults to true in public methods. If you know what
5713 		// you are doing, i.e. if you know your BPicture stays valid, you
5714 		// can avoid the performance impact of syncing. In a use-case where
5715 		// the client creates BPictures on the stack, these BPictures may
5716 		// have issued a AS_DELETE_PICTURE command to the ServerApp when Draw()
5717 		// goes out of scope, and the command is processed earlier in the
5718 		// ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the
5719 		// ServerWindow thread, which will then have the result that no
5720 		// ServerPicture is found of the token.
5721 		if (sync)
5722 			Sync();
5723 	}
5724 }
5725 
5726 
5727 void
5728 BView::_ClipToRect(BRect rect, bool inverse)
5729 {
5730 	if (_CheckOwnerLockAndSwitchCurrent()) {
5731 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_RECT);
5732 		fOwner->fLink->Attach<bool>(inverse);
5733 		fOwner->fLink->Attach<BRect>(rect);
5734 		_FlushIfNotInTransaction();
5735 	}
5736 }
5737 
5738 
5739 void
5740 BView::_ClipToShape(BShape* shape, bool inverse)
5741 {
5742 	if (shape == NULL)
5743 		return;
5744 
5745 	shape_data* sd = (shape_data*)shape->fPrivateData;
5746 	if (sd->opCount == 0 || sd->ptCount == 0)
5747 		return;
5748 
5749 	if (_CheckOwnerLockAndSwitchCurrent()) {
5750 		fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_SHAPE);
5751 		fOwner->fLink->Attach<bool>(inverse);
5752 		fOwner->fLink->Attach<int32>(sd->opCount);
5753 		fOwner->fLink->Attach<int32>(sd->ptCount);
5754 		fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
5755 		fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
5756 		_FlushIfNotInTransaction();
5757 	}
5758 }
5759 
5760 
5761 bool
5762 BView::_RemoveChildFromList(BView* child)
5763 {
5764 	if (child->fParent != this)
5765 		return false;
5766 
5767 	if (fFirstChild == child) {
5768 		// it's the first view in the list
5769 		fFirstChild = child->fNextSibling;
5770 	} else {
5771 		// there must be a previous sibling
5772 		child->fPreviousSibling->fNextSibling = child->fNextSibling;
5773 	}
5774 
5775 	if (child->fNextSibling)
5776 		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
5777 
5778 	child->fParent = NULL;
5779 	child->fNextSibling = NULL;
5780 	child->fPreviousSibling = NULL;
5781 
5782 	return true;
5783 }
5784 
5785 
5786 bool
5787 BView::_AddChildToList(BView* child, BView* before)
5788 {
5789 	if (!child)
5790 		return false;
5791 	if (child->fParent != NULL) {
5792 		debugger("View already belongs to someone else");
5793 		return false;
5794 	}
5795 	if (before != NULL && before->fParent != this) {
5796 		debugger("Invalid before view");
5797 		return false;
5798 	}
5799 
5800 	if (before != NULL) {
5801 		// add view before this one
5802 		child->fNextSibling = before;
5803 		child->fPreviousSibling = before->fPreviousSibling;
5804 		if (child->fPreviousSibling != NULL)
5805 			child->fPreviousSibling->fNextSibling = child;
5806 
5807 		before->fPreviousSibling = child;
5808 		if (fFirstChild == before)
5809 			fFirstChild = child;
5810 	} else {
5811 		// add view to the end of the list
5812 		BView* last = fFirstChild;
5813 		while (last != NULL && last->fNextSibling != NULL) {
5814 			last = last->fNextSibling;
5815 		}
5816 
5817 		if (last != NULL) {
5818 			last->fNextSibling = child;
5819 			child->fPreviousSibling = last;
5820 		} else {
5821 			fFirstChild = child;
5822 			child->fPreviousSibling = NULL;
5823 		}
5824 
5825 		child->fNextSibling = NULL;
5826 	}
5827 
5828 	child->fParent = this;
5829 	return true;
5830 }
5831 
5832 
5833 /*!	\brief Creates the server counterpart of this view.
5834 	This is only done for views that are part of the view hierarchy, ie. when
5835 	they are attached to a window.
5836 	RemoveSelf() deletes the server object again.
5837 */
5838 bool
5839 BView::_CreateSelf()
5840 {
5841 	// AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
5842 	// current view mechanism via _CheckLockAndSwitchCurrent() - the token
5843 	// of the view and its parent are both send to the server.
5844 
5845 	if (fTopLevelView)
5846 		fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
5847 	else
5848  		fOwner->fLink->StartMessage(AS_VIEW_CREATE);
5849 
5850 	fOwner->fLink->Attach<int32>(_get_object_token_(this));
5851 	fOwner->fLink->AttachString(Name());
5852 	fOwner->fLink->Attach<BRect>(Frame());
5853 	fOwner->fLink->Attach<BPoint>(LeftTop());
5854 	fOwner->fLink->Attach<uint32>(ResizingMode());
5855 	fOwner->fLink->Attach<uint32>(fEventMask);
5856 	fOwner->fLink->Attach<uint32>(fEventOptions);
5857 	fOwner->fLink->Attach<uint32>(Flags());
5858 	fOwner->fLink->Attach<bool>(IsHidden(this));
5859 	fOwner->fLink->Attach<rgb_color>(fState->view_color);
5860 	if (fTopLevelView)
5861 		fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
5862 	else
5863 		fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
5864 	fOwner->fLink->Flush();
5865 
5866 	_CheckOwnerLockAndSwitchCurrent();
5867 	fState->UpdateServerState(*fOwner->fLink);
5868 
5869 	// we create all its children, too
5870 
5871 	for (BView* child = fFirstChild; child != NULL;
5872 			child = child->fNextSibling) {
5873 		child->_CreateSelf();
5874 	}
5875 
5876 	fOwner->fLink->Flush();
5877 	return true;
5878 }
5879 
5880 
5881 /*!	Sets the new view position.
5882 	It doesn't contact the server, though - the only case where this
5883 	is called outside of MoveTo() is as reaction of moving a view
5884 	in the server (a.k.a. B_WINDOW_RESIZED).
5885 	It also calls the BView's FrameMoved() hook.
5886 */
5887 void
5888 BView::_MoveTo(int32 x, int32 y)
5889 {
5890 	fParentOffset.Set(x, y);
5891 
5892 	if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
5893 		BMessage moved(B_VIEW_MOVED);
5894 		moved.AddInt64("when", system_time());
5895 		moved.AddPoint("where", BPoint(x, y));
5896 
5897 		BMessenger target(this);
5898 		target.SendMessage(&moved);
5899 	}
5900 }
5901 
5902 
5903 /*!	Computes the actual new frame size and recalculates the size of
5904 	the children as well.
5905 	It doesn't contact the server, though - the only case where this
5906 	is called outside of ResizeBy() is as reaction of resizing a view
5907 	in the server (a.k.a. B_WINDOW_RESIZED).
5908 	It also calls the BView's FrameResized() hook.
5909 */
5910 void
5911 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
5912 {
5913 	fBounds.right += deltaWidth;
5914 	fBounds.bottom += deltaHeight;
5915 
5916 	if (Window() == NULL) {
5917 		// we're not supposed to exercise the resizing code in case
5918 		// we haven't been attached to a window yet
5919 		return;
5920 	}
5921 
5922 	// layout the children
5923 	if ((fFlags & B_SUPPORTS_LAYOUT) != 0) {
5924 		Relayout();
5925 	} else {
5926 		for (BView* child = fFirstChild; child; child = child->fNextSibling)
5927 			child->_ParentResizedBy(deltaWidth, deltaHeight);
5928 	}
5929 
5930 	if (fFlags & B_FRAME_EVENTS) {
5931 		BMessage resized(B_VIEW_RESIZED);
5932 		resized.AddInt64("when", system_time());
5933 		resized.AddInt32("width", fBounds.IntegerWidth());
5934 		resized.AddInt32("height", fBounds.IntegerHeight());
5935 
5936 		BMessenger target(this);
5937 		target.SendMessage(&resized);
5938 	}
5939 }
5940 
5941 
5942 /*!	Relayouts the view according to its resizing mode. */
5943 void
5944 BView::_ParentResizedBy(int32 x, int32 y)
5945 {
5946 	uint32 resizingMode = fFlags & _RESIZE_MASK_;
5947 	BRect newFrame = Frame();
5948 
5949 	// follow with left side
5950 	if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
5951 		newFrame.left += x;
5952 	else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
5953 		newFrame.left += x / 2;
5954 
5955 	// follow with right side
5956 	if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
5957 		newFrame.right += x;
5958 	else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
5959 		newFrame.right += x / 2;
5960 
5961 	// follow with top side
5962 	if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
5963 		newFrame.top += y;
5964 	else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
5965 		newFrame.top += y / 2;
5966 
5967 	// follow with bottom side
5968 	if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
5969 		newFrame.bottom += y;
5970 	else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
5971 		newFrame.bottom += y / 2;
5972 
5973 	if (newFrame.LeftTop() != fParentOffset) {
5974 		// move view
5975 		_MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
5976 	}
5977 
5978 	if (newFrame != Frame()) {
5979 		// resize view
5980 		int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
5981 		int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
5982 		_ResizeBy(widthDiff, heightDiff);
5983 	}
5984 }
5985 
5986 
5987 void
5988 BView::_Activate(bool active)
5989 {
5990 	WindowActivated(active);
5991 
5992 	for (BView* child = fFirstChild; child != NULL;
5993 			child = child->fNextSibling) {
5994 		child->_Activate(active);
5995 	}
5996 }
5997 
5998 
5999 void
6000 BView::_Attach()
6001 {
6002 	if (fOwner != NULL) {
6003 		// unmask state flags to force [re]syncing with the app_server
6004 		fState->valid_flags &= ~(B_VIEW_WHICH_VIEW_COLOR_BIT
6005 			| B_VIEW_WHICH_LOW_COLOR_BIT | B_VIEW_WHICH_HIGH_COLOR_BIT);
6006 
6007 		if (fState->which_view_color != B_NO_COLOR)
6008 			SetViewUIColor(fState->which_view_color,
6009 				fState->which_view_color_tint);
6010 
6011 		if (fState->which_high_color != B_NO_COLOR)
6012 			SetHighUIColor(fState->which_high_color,
6013 				fState->which_high_color_tint);
6014 
6015 		if (fState->which_low_color != B_NO_COLOR)
6016 			SetLowUIColor(fState->which_low_color,
6017 				fState->which_low_color_tint);
6018 	}
6019 
6020 	AttachedToWindow();
6021 
6022 	fAttached = true;
6023 
6024 	// after giving the view a chance to do this itself,
6025 	// check for the B_PULSE_NEEDED flag and make sure the
6026 	// window set's up the pulse messaging
6027 	if (fOwner) {
6028 		if (fFlags & B_PULSE_NEEDED) {
6029 			_CheckLock();
6030 			if (fOwner->fPulseRunner == NULL)
6031 				fOwner->SetPulseRate(fOwner->PulseRate());
6032 		}
6033 
6034 		if (!fOwner->IsHidden())
6035 			Invalidate();
6036 	}
6037 
6038 	for (BView* child = fFirstChild; child != NULL;
6039 			child = child->fNextSibling) {
6040 		// we need to check for fAttached as new views could have been
6041 		// added in AttachedToWindow() - and those are already attached
6042 		if (!child->fAttached)
6043 			child->_Attach();
6044 	}
6045 
6046 	AllAttached();
6047 }
6048 
6049 
6050 void
6051 BView::_ColorsUpdated(BMessage* message)
6052 {
6053 	if (fTopLevelView
6054 		&& fLayoutData->fLayout != NULL
6055 		&& !fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)) {
6056 		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
6057 		SetHighUIColor(B_PANEL_TEXT_COLOR);
6058 	}
6059 
6060 	rgb_color color;
6061 
6062 	const char* colorName = ui_color_name(fState->which_view_color);
6063 	if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6064 		fState->view_color = tint_color(color, fState->which_view_color_tint);
6065 		fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
6066 	}
6067 
6068 	colorName = ui_color_name(fState->which_low_color);
6069 	if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6070 		fState->low_color = tint_color(color, fState->which_low_color_tint);
6071 		fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
6072 	}
6073 
6074 	colorName = ui_color_name(fState->which_high_color);
6075 	if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6076 		fState->high_color = tint_color(color, fState->which_high_color_tint);
6077 		fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
6078 	}
6079 
6080 	MessageReceived(message);
6081 
6082 	for (BView* child = fFirstChild; child != NULL;
6083 			child = child->fNextSibling)
6084 		child->_ColorsUpdated(message);
6085 
6086 	Invalidate();
6087 }
6088 
6089 
6090 void
6091 BView::_Detach()
6092 {
6093 	DetachedFromWindow();
6094 	fAttached = false;
6095 
6096 	for (BView* child = fFirstChild; child != NULL;
6097 			child = child->fNextSibling) {
6098 		child->_Detach();
6099 	}
6100 
6101 	AllDetached();
6102 
6103 	if (fOwner) {
6104 		_CheckLock();
6105 
6106 		if (!fOwner->IsHidden())
6107 			Invalidate();
6108 
6109 		// make sure our owner doesn't need us anymore
6110 
6111 		if (fOwner->CurrentFocus() == this) {
6112 			MakeFocus(false);
6113 			// MakeFocus() is virtual and might not be
6114 			// passing through to the BView version,
6115 			// but we need to make sure at this point
6116 			// that we are not the focus view anymore.
6117 			if (fOwner->CurrentFocus() == this)
6118 				fOwner->_SetFocus(NULL, true);
6119 		}
6120 
6121 		if (fOwner->fDefaultButton == this)
6122 			fOwner->SetDefaultButton(NULL);
6123 
6124 		if (fOwner->fKeyMenuBar == this)
6125 			fOwner->fKeyMenuBar = NULL;
6126 
6127 		if (fOwner->fLastMouseMovedView == this)
6128 			fOwner->fLastMouseMovedView = NULL;
6129 
6130 		if (fOwner->fLastViewToken == _get_object_token_(this))
6131 			fOwner->fLastViewToken = B_NULL_TOKEN;
6132 
6133 		_SetOwner(NULL);
6134 	}
6135 }
6136 
6137 
6138 void
6139 BView::_Draw(BRect updateRect)
6140 {
6141 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
6142 		return;
6143 
6144 	// NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
6145 	// -> View is simply not drawn at all
6146 
6147 	_SwitchServerCurrentView();
6148 
6149 	ConvertFromScreen(&updateRect);
6150 
6151 	// TODO: make states robust (the hook implementation could
6152 	// mess things up if it uses non-matching Push- and PopState(),
6153 	// we would not be guaranteed to still have the same state on
6154 	// the stack after having called Draw())
6155 	PushState();
6156 	Draw(updateRect);
6157 	PopState();
6158 	Flush();
6159 }
6160 
6161 
6162 void
6163 BView::_DrawAfterChildren(BRect updateRect)
6164 {
6165 	if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
6166 		|| !(Flags() & B_DRAW_ON_CHILDREN))
6167 		return;
6168 
6169 	_SwitchServerCurrentView();
6170 
6171 	ConvertFromScreen(&updateRect);
6172 
6173 	// TODO: make states robust (see above)
6174 	PushState();
6175 	DrawAfterChildren(updateRect);
6176 	PopState();
6177 	Flush();
6178 }
6179 
6180 
6181 void
6182 BView::_FontsUpdated(BMessage* message)
6183 {
6184 	MessageReceived(message);
6185 
6186 	for (BView* child = fFirstChild; child != NULL;
6187 			child = child->fNextSibling) {
6188 		child->_FontsUpdated(message);
6189 	}
6190 }
6191 
6192 
6193 void
6194 BView::_Pulse()
6195 {
6196 	if ((Flags() & B_PULSE_NEEDED) != 0)
6197 		Pulse();
6198 
6199 	for (BView* child = fFirstChild; child != NULL;
6200 			child = child->fNextSibling) {
6201 		child->_Pulse();
6202 	}
6203 }
6204 
6205 
6206 void
6207 BView::_UpdateStateForRemove()
6208 {
6209 	// TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
6210 	if (!_CheckOwnerLockAndSwitchCurrent())
6211 		return;
6212 
6213 	fState->UpdateFrom(*fOwner->fLink);
6214 //	if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
6215 //		fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
6216 //
6217 //		status_t code;
6218 //		if (fOwner->fLink->FlushWithReply(code) == B_OK
6219 //			&& code == B_OK) {
6220 //			fOwner->fLink->Read<BPoint>(&fParentOffset);
6221 //			fOwner->fLink->Read<BRect>(&fBounds);
6222 //			fState->valid_flags |= B_VIEW_FRAME_BIT;
6223 //		}
6224 //	}
6225 
6226 	// update children as well
6227 
6228 	for (BView* child = fFirstChild; child != NULL;
6229 			child = child->fNextSibling) {
6230 		if (child->fOwner)
6231 			child->_UpdateStateForRemove();
6232 	}
6233 }
6234 
6235 
6236 inline void
6237 BView::_UpdatePattern(::pattern pattern)
6238 {
6239 	if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
6240 		return;
6241 
6242 	if (fOwner) {
6243 		_CheckLockAndSwitchCurrent();
6244 
6245 		fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
6246 		fOwner->fLink->Attach< ::pattern>(pattern);
6247 
6248 		fState->valid_flags |= B_VIEW_PATTERN_BIT;
6249 	}
6250 
6251 	fState->pattern = pattern;
6252 }
6253 
6254 
6255 void
6256 BView::_FlushIfNotInTransaction()
6257 {
6258 	if (!fOwner->fInTransaction) {
6259 		fOwner->Flush();
6260 	}
6261 }
6262 
6263 
6264 BShelf*
6265 BView::_Shelf() const
6266 {
6267 	return fShelf;
6268 }
6269 
6270 
6271 void
6272 BView::_SetShelf(BShelf* shelf)
6273 {
6274 	if (fShelf != NULL && fOwner != NULL)
6275 		fOwner->RemoveHandler(fShelf);
6276 
6277 	fShelf = shelf;
6278 
6279 	if (fShelf != NULL && fOwner != NULL)
6280 		fOwner->AddHandler(fShelf);
6281 }
6282 
6283 
6284 status_t
6285 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
6286 	uint32 followFlags, uint32 options)
6287 {
6288 	if (!_CheckOwnerLockAndSwitchCurrent())
6289 		return B_ERROR;
6290 
6291 	int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
6292 
6293 	fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
6294 	fOwner->fLink->Attach<int32>(serverToken);
6295 	fOwner->fLink->Attach<BRect>(srcRect);
6296 	fOwner->fLink->Attach<BRect>(dstRect);
6297 	fOwner->fLink->Attach<int32>(followFlags);
6298 	fOwner->fLink->Attach<int32>(options);
6299 
6300 	status_t status = B_ERROR;
6301 	fOwner->fLink->FlushWithReply(status);
6302 
6303 	return status;
6304 }
6305 
6306 
6307 bool
6308 BView::_CheckOwnerLockAndSwitchCurrent() const
6309 {
6310 	STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
6311 
6312 	if (fOwner == NULL) {
6313 		debugger("View method requires owner and doesn't have one.");
6314 		return false;
6315 	}
6316 
6317 	_CheckLockAndSwitchCurrent();
6318 
6319 	return true;
6320 }
6321 
6322 
6323 bool
6324 BView::_CheckOwnerLock() const
6325 {
6326 	if (fOwner) {
6327 		fOwner->check_lock();
6328 		return true;
6329 	} else {
6330 		debugger("View method requires owner and doesn't have one.");
6331 		return false;
6332 	}
6333 }
6334 
6335 
6336 void
6337 BView::_CheckLockAndSwitchCurrent() const
6338 {
6339 	STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
6340 
6341 	if (!fOwner)
6342 		return;
6343 
6344 	fOwner->check_lock();
6345 
6346 	_SwitchServerCurrentView();
6347 }
6348 
6349 
6350 void
6351 BView::_CheckLock() const
6352 {
6353 	if (fOwner)
6354 		fOwner->check_lock();
6355 }
6356 
6357 
6358 void
6359 BView::_SwitchServerCurrentView() const
6360 {
6361 	int32 serverToken = _get_object_token_(this);
6362 
6363 	if (fOwner->fLastViewToken != serverToken) {
6364 		STRACE(("contacting app_server... sending token: %" B_PRId32 "\n",
6365 			serverToken));
6366 		fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
6367 		fOwner->fLink->Attach<int32>(serverToken);
6368 
6369 		fOwner->fLastViewToken = serverToken;
6370 	}
6371 }
6372 
6373 
6374 status_t
6375 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
6376 {
6377 	if (scrollBar == NULL || delta == 0.0f)
6378 		return B_BAD_VALUE;
6379 
6380 	float smallStep;
6381 	float largeStep;
6382 	scrollBar->GetSteps(&smallStep, &largeStep);
6383 
6384 	// pressing the shift key scrolls faster (following the pseudo-standard set
6385 	// by other desktop environments).
6386 	if ((modifiers() & B_SHIFT_KEY) != 0)
6387 		delta *= largeStep;
6388 	else
6389 		delta *= smallStep * 3;
6390 
6391 	scrollBar->SetValue(scrollBar->Value() + delta);
6392 
6393 	return B_OK;
6394 }
6395 
6396 
6397 #if __GNUC__ == 2
6398 
6399 
6400 extern "C" void
6401 _ReservedView1__5BView(BView* view, BRect rect)
6402 {
6403 	view->BView::DrawAfterChildren(rect);
6404 }
6405 
6406 
6407 extern "C" void
6408 _ReservedView2__5BView(BView* view)
6409 {
6410 	// MinSize()
6411 	perform_data_min_size data;
6412 	view->Perform(PERFORM_CODE_MIN_SIZE, &data);
6413 }
6414 
6415 
6416 extern "C" void
6417 _ReservedView3__5BView(BView* view)
6418 {
6419 	// MaxSize()
6420 	perform_data_max_size data;
6421 	view->Perform(PERFORM_CODE_MAX_SIZE, &data);
6422 }
6423 
6424 
6425 extern "C" BSize
6426 _ReservedView4__5BView(BView* view)
6427 {
6428 	// PreferredSize()
6429 	perform_data_preferred_size data;
6430 	view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
6431 	return data.return_value;
6432 }
6433 
6434 
6435 extern "C" BAlignment
6436 _ReservedView5__5BView(BView* view)
6437 {
6438 	// LayoutAlignment()
6439 	perform_data_layout_alignment data;
6440 	view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
6441 	return data.return_value;
6442 }
6443 
6444 
6445 extern "C" bool
6446 _ReservedView6__5BView(BView* view)
6447 {
6448 	// HasHeightForWidth()
6449 	perform_data_has_height_for_width data;
6450 	view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
6451 	return data.return_value;
6452 }
6453 
6454 
6455 extern "C" void
6456 _ReservedView7__5BView(BView* view, float width, float* min, float* max,
6457 	float* preferred)
6458 {
6459 	// GetHeightForWidth()
6460 	perform_data_get_height_for_width data;
6461 	data.width = width;
6462 	view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
6463 	if (min != NULL)
6464 		*min = data.min;
6465 	if (max != NULL)
6466 		*max = data.max;
6467 	if (preferred != NULL)
6468 		*preferred = data.preferred;
6469 }
6470 
6471 
6472 extern "C" void
6473 _ReservedView8__5BView(BView* view, BLayout* layout)
6474 {
6475 	// SetLayout()
6476 	perform_data_set_layout data;
6477 	data.layout = layout;
6478 	view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
6479 }
6480 
6481 
6482 extern "C" void
6483 _ReservedView9__5BView(BView* view, bool descendants)
6484 {
6485 	// LayoutInvalidated()
6486 	perform_data_layout_invalidated data;
6487 	data.descendants = descendants;
6488 	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
6489 }
6490 
6491 
6492 extern "C" void
6493 _ReservedView10__5BView(BView* view)
6494 {
6495 	// DoLayout()
6496 	view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
6497 }
6498 
6499 
6500 #endif	// __GNUC__ == 2
6501 
6502 
6503 extern "C" bool
6504 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
6505 	BView* view, BPoint point, BToolTip** _toolTip)
6506 {
6507 	// GetToolTipAt()
6508 	perform_data_get_tool_tip_at data;
6509 	data.point = point;
6510 	data.tool_tip = _toolTip;
6511 	view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
6512 	return data.return_value;
6513 }
6514 
6515 
6516 extern "C" void
6517 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
6518 	BView* view)
6519 {
6520 	// LayoutChanged();
6521 	view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
6522 }
6523 
6524 
6525 void BView::_ReservedView13() {}
6526 void BView::_ReservedView14() {}
6527 void BView::_ReservedView15() {}
6528 void BView::_ReservedView16() {}
6529 
6530 
6531 BView::BView(const BView& other)
6532 	:
6533 	BHandler()
6534 {
6535 	// this is private and not functional, but exported
6536 }
6537 
6538 
6539 BView&
6540 BView::operator=(const BView& other)
6541 {
6542 	// this is private and not functional, but exported
6543 	return *this;
6544 }
6545 
6546 
6547 void
6548 BView::_PrintToStream()
6549 {
6550 	printf("BView::_PrintToStream()\n");
6551 	printf("\tName: %s\n"
6552 		"\tParent: %s\n"
6553 		"\tFirstChild: %s\n"
6554 		"\tNextSibling: %s\n"
6555 		"\tPrevSibling: %s\n"
6556 		"\tOwner(Window): %s\n"
6557 		"\tToken: %" B_PRId32 "\n"
6558 		"\tFlags: %" B_PRId32 "\n"
6559 		"\tView origin: (%f,%f)\n"
6560 		"\tView Bounds rectangle: (%f,%f,%f,%f)\n"
6561 		"\tShow level: %d\n"
6562 		"\tTopView?: %s\n"
6563 		"\tBPicture: %s\n"
6564 		"\tVertical Scrollbar %s\n"
6565 		"\tHorizontal Scrollbar %s\n"
6566 		"\tIs Printing?: %s\n"
6567 		"\tShelf?: %s\n"
6568 		"\tEventMask: %" B_PRId32 "\n"
6569 		"\tEventOptions: %" B_PRId32 "\n",
6570 	Name(),
6571 	fParent ? fParent->Name() : "NULL",
6572 	fFirstChild ? fFirstChild->Name() : "NULL",
6573 	fNextSibling ? fNextSibling->Name() : "NULL",
6574 	fPreviousSibling ? fPreviousSibling->Name() : "NULL",
6575 	fOwner ? fOwner->Name() : "NULL",
6576 	_get_object_token_(this),
6577 	fFlags,
6578 	fParentOffset.x, fParentOffset.y,
6579 	fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
6580 	fShowLevel,
6581 	fTopLevelView ? "YES" : "NO",
6582 	fCurrentPicture? "YES" : "NULL",
6583 	fVerScroller? "YES" : "NULL",
6584 	fHorScroller? "YES" : "NULL",
6585 	fIsPrinting? "YES" : "NO",
6586 	fShelf? "YES" : "NO",
6587 	fEventMask,
6588 	fEventOptions);
6589 
6590 	printf("\tState status:\n"
6591 		"\t\tLocalCoordianteSystem: (%f,%f)\n"
6592 		"\t\tPenLocation: (%f,%f)\n"
6593 		"\t\tPenSize: %f\n"
6594 		"\t\tHighColor: [%d,%d,%d,%d]\n"
6595 		"\t\tLowColor: [%d,%d,%d,%d]\n"
6596 		"\t\tViewColor: [%d,%d,%d,%d]\n"
6597 		"\t\tPattern: %" B_PRIx64 "\n"
6598 		"\t\tDrawingMode: %d\n"
6599 		"\t\tLineJoinMode: %d\n"
6600 		"\t\tLineCapMode: %d\n"
6601 		"\t\tMiterLimit: %f\n"
6602 		"\t\tAlphaSource: %d\n"
6603 		"\t\tAlphaFuntion: %d\n"
6604 		"\t\tScale: %f\n"
6605 		"\t\t(Print)FontAliasing: %s\n"
6606 		"\t\tFont Info:\n",
6607 	fState->origin.x, fState->origin.y,
6608 	fState->pen_location.x, fState->pen_location.y,
6609 	fState->pen_size,
6610 	fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
6611 	fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
6612 	fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
6613 	*((uint64*)&(fState->pattern)),
6614 	fState->drawing_mode,
6615 	fState->line_join,
6616 	fState->line_cap,
6617 	fState->miter_limit,
6618 	fState->alpha_source_mode,
6619 	fState->alpha_function_mode,
6620 	fState->scale,
6621 	fState->font_aliasing? "YES" : "NO");
6622 
6623 	fState->font.PrintToStream();
6624 
6625 	// TODO: also print the line array.
6626 }
6627 
6628 
6629 void
6630 BView::_PrintTree()
6631 {
6632 	int32 spaces = 2;
6633 	BView* c = fFirstChild; //c = short for: current
6634 	printf( "'%s'\n", Name() );
6635 	if (c != NULL) {
6636 		while(true) {
6637 			// action block
6638 			{
6639 				for (int i = 0; i < spaces; i++)
6640 					printf(" ");
6641 
6642 				printf( "'%s'\n", c->Name() );
6643 			}
6644 
6645 			// go deep
6646 			if (c->fFirstChild) {
6647 				c = c->fFirstChild;
6648 				spaces += 2;
6649 			} else {
6650 				// go right
6651 				if (c->fNextSibling) {
6652 					c = c->fNextSibling;
6653 				} else {
6654 					// go up
6655 					while (!c->fParent->fNextSibling && c->fParent != this) {
6656 						c = c->fParent;
6657 						spaces -= 2;
6658 					}
6659 
6660 					// that enough! We've reached this view.
6661 					if (c->fParent == this)
6662 						break;
6663 
6664 					c = c->fParent->fNextSibling;
6665 					spaces -= 2;
6666 				}
6667 			}
6668 		}
6669 	}
6670 }
6671 
6672 
6673 // #pragma mark -
6674 
6675 
6676 BLayoutItem*
6677 BView::Private::LayoutItemAt(int32 index)
6678 {
6679 	return fView->fLayoutData->fLayoutItems.ItemAt(index);
6680 }
6681 
6682 
6683 int32
6684 BView::Private::CountLayoutItems()
6685 {
6686 	return fView->fLayoutData->fLayoutItems.CountItems();
6687 }
6688 
6689 
6690 void
6691 BView::Private::RegisterLayoutItem(BLayoutItem* item)
6692 {
6693 	fView->fLayoutData->fLayoutItems.AddItem(item);
6694 }
6695 
6696 
6697 void
6698 BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6699 {
6700 	fView->fLayoutData->fLayoutItems.RemoveItem(item);
6701 }
6702 
6703 
6704 bool
6705 BView::Private::MinMaxValid()
6706 {
6707 	return fView->fLayoutData->fMinMaxValid;
6708 }
6709 
6710 
6711 bool
6712 BView::Private::WillLayout()
6713 {
6714 	BView::LayoutData* data = fView->fLayoutData;
6715 	if (data->fLayoutInProgress)
6716 		return false;
6717 	if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6718 		return true;
6719 	return false;
6720 }
6721