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