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