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