xref: /haiku/src/kits/tracker/Utilities.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 #include <ctype.h>
36 #include <malloc.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <time.h>
40 #include <stdarg.h>
41 
42 #include <Bitmap.h>
43 #include <Debug.h>
44 #include <Directory.h>
45 #include <fs_info.h>
46 #include <IconUtils.h>
47 #include <MenuItem.h>
48 #include <OS.h>
49 #include <PopUpMenu.h>
50 #include <Region.h>
51 #include <StorageDefs.h>
52 #include <TextView.h>
53 #include <Volume.h>
54 #include <VolumeRoster.h>
55 #include <Window.h>
56 
57 #if B_BEOS_VERSION_DANO
58 #define _IMPEXP_BE
59 #endif
60 extern _IMPEXP_BE const uint32	LARGE_ICON_TYPE;
61 extern _IMPEXP_BE const uint32	MINI_ICON_TYPE;
62 #if B_BEOS_VERSION_DANO
63 #undef _IMPEXP_BE
64 #endif
65 
66 #include "Attributes.h"
67 #include "MimeTypes.h"
68 #include "Model.h"
69 #include "Utilities.h"
70 #include "ContainerWindow.h"
71 
72 #include <fs_attr.h>
73 
74 
75 
76 FILE *logFile = NULL;
77 
78 static const float kMinSeparatorStubX = 10;
79 static const float kStubToStringSlotX = 5;
80 
81 
82 namespace BPrivate {
83 
84 const rgb_color	kBlack = {0, 0, 0, 255};
85 const rgb_color	kWhite = {255, 255, 255, 255};
86 
87 
88 uint32
89 HashString(const char *string, uint32 seed)
90 {
91 	char ch;
92 	uint32 result = seed;
93 
94 	while((ch = *string++) != 0) {
95 		result = (result << 7) ^ (result >> 24);
96 		result ^= ch;
97 	}
98 
99 	result ^= result << 12;
100 	return result;
101 }
102 
103 
104 uint32
105 AttrHashString(const char *string, uint32 type)
106 {
107 	char c;
108 	uint32 hash = 0;
109 
110 	while((c = *string++) != 0) {
111 		hash = (hash << 7) ^ (hash >> 24);
112 		hash ^= c;
113 	}
114 
115 	hash ^= hash << 12;
116 
117 	hash &= ~0xff;
118 	hash |= type;
119 
120 	return hash;
121 }
122 
123 
124 bool
125 ValidateStream(BMallocIO *stream, uint32 key, int32 version)
126 {
127 	uint32 test_key;
128 	int32 test_version;
129 
130 	if (stream->Read(&test_key, sizeof(uint32)) <= 0
131 		|| stream->Read(&test_version, sizeof(int32)) <=0)
132 		return false;
133 
134 	return test_key == key && test_version == version;
135 }
136 
137 
138 void
139 DisallowFilenameKeys(BTextView *textView)
140 {
141 	textView->DisallowChar(':');
142 	textView->DisallowChar('/');
143 }
144 
145 
146 void
147 DisallowMetaKeys(BTextView *textView)
148 {
149 	textView->DisallowChar(B_TAB);
150 	textView->DisallowChar(B_ESCAPE);
151 	textView->DisallowChar(B_INSERT);
152 	textView->DisallowChar(B_DELETE);
153 	textView->DisallowChar(B_HOME);
154 	textView->DisallowChar(B_END);
155 	textView->DisallowChar(B_PAGE_UP);
156 	textView->DisallowChar(B_PAGE_DOWN);
157 	textView->DisallowChar(B_FUNCTION_KEY);
158 }
159 
160 }	// namespace BPrivate
161 
162 
163 void
164 PoseInfo::EndianSwap(void *castToThis)
165 {
166 	PoseInfo *self = (PoseInfo *)castToThis;
167 
168 	PRINT(("swapping PoseInfo\n"));
169 
170 	STATIC_ASSERT(sizeof(ino_t) == sizeof(int64));
171 	self->fInitedDirectory = SwapInt64(self->fInitedDirectory);
172 	swap_data(B_POINT_TYPE, &self->fLocation, sizeof(BPoint), B_SWAP_ALWAYS);
173 
174 	// do a sanity check on the icon position
175 	if (self->fLocation.x < -20000 || self->fLocation.x > 20000
176 		|| self->fLocation.y < -20000 || self->fLocation.y > 20000) {
177 		// position out of range, force autoplcemement
178 		PRINT((" rejecting icon position out of range\n"));
179 		self->fInitedDirectory = -1LL;
180 		self->fLocation = BPoint(0, 0);
181 	}
182 }
183 
184 
185 void
186 PoseInfo::PrintToStream()
187 {
188 	PRINT(("%s, inode:%Lx, location %f %f\n", fInvisible ? "hidden" : "visible",
189 		fInitedDirectory, fLocation.x, fLocation.y));
190 }
191 
192 
193 // #pragma mark -
194 
195 
196 size_t
197 ExtendedPoseInfo::Size() const
198 {
199 	return sizeof(ExtendedPoseInfo) + fNumFrames * sizeof(FrameLocation);
200 }
201 
202 
203 size_t
204 ExtendedPoseInfo::Size(int32 count)
205 {
206 	return sizeof(ExtendedPoseInfo) + count * sizeof(FrameLocation);
207 }
208 
209 
210 size_t
211 ExtendedPoseInfo::SizeWithHeadroom() const
212 {
213 	return sizeof(ExtendedPoseInfo) + (fNumFrames + 1) * sizeof(FrameLocation);
214 }
215 
216 
217 size_t
218 ExtendedPoseInfo::SizeWithHeadroom(size_t oldSize)
219 {
220 	int32 count = (ssize_t)oldSize - (ssize_t)sizeof(ExtendedPoseInfo);
221 	if (count > 0)
222 		count /= sizeof(FrameLocation);
223 	else
224 		count = 0;
225 
226 	return Size(count + 1);
227 }
228 
229 
230 bool
231 ExtendedPoseInfo::HasLocationForFrame(BRect frame) const
232 {
233 	for (int32 index = 0; index < fNumFrames; index++) {
234 		if (fLocations[index].fFrame == frame)
235 			return true;
236 	}
237 
238 	return false;
239 }
240 
241 
242 BPoint
243 ExtendedPoseInfo::LocationForFrame(BRect frame) const
244 {
245 	for (int32 index = 0; index < fNumFrames; index++) {
246 		if (fLocations[index].fFrame == frame)
247 			return fLocations[index].fLocation;
248 	}
249 
250 	TRESPASS();
251 	return BPoint(0, 0);
252 }
253 
254 
255 bool
256 ExtendedPoseInfo::SetLocationForFrame(BPoint newLocation, BRect frame)
257 {
258 	for (int32 index = 0; index < fNumFrames; index++) {
259 		if (fLocations[index].fFrame == frame) {
260 			if (fLocations[index].fLocation == newLocation)
261 				return false;
262 
263 			fLocations[index].fLocation = newLocation;
264 			return true;
265 		}
266 	}
267 
268 	fLocations[fNumFrames].fFrame = frame;
269 	fLocations[fNumFrames].fLocation = newLocation;
270 	fLocations[fNumFrames].fWorkspaces = 0xffffffff;
271 	fNumFrames++;
272 	return true;
273 }
274 
275 
276 void
277 ExtendedPoseInfo::EndianSwap(void *castToThis)
278 {
279 	ExtendedPoseInfo *self = (ExtendedPoseInfo *)castToThis;
280 
281 	PRINT(("swapping ExtendedPoseInfo\n"));
282 
283 	self->fWorkspaces = SwapUInt32(self->fWorkspaces);
284 	self->fNumFrames = SwapInt32(self->fNumFrames);
285 
286 	for (int32 index = 0; index < self->fNumFrames; index++) {
287 		swap_data(B_POINT_TYPE, &self->fLocations[index].fLocation,
288 			sizeof(BPoint), B_SWAP_ALWAYS);
289 
290 		if (self->fLocations[index].fLocation.x < -20000
291 			|| self->fLocations[index].fLocation.x > 20000
292 			|| self->fLocations[index].fLocation.y < -20000
293 			|| self->fLocations[index].fLocation.y > 20000) {
294 			// position out of range, force autoplcemement
295 			PRINT((" rejecting icon position out of range\n"));
296 			self->fLocations[index].fLocation = BPoint(0, 0);
297 		}
298 		swap_data(B_RECT_TYPE, &self->fLocations[index].fFrame,
299 			sizeof(BRect), B_SWAP_ALWAYS);
300 	}
301 }
302 
303 
304 void
305 ExtendedPoseInfo::PrintToStream()
306 {
307 }
308 
309 
310 // #pragma mark -
311 
312 
313 OffscreenBitmap::OffscreenBitmap(BRect frame)
314 	:
315 	fBitmap(NULL)
316 {
317 	NewBitmap(frame);
318 }
319 
320 
321 OffscreenBitmap::OffscreenBitmap()
322 	:
323 	fBitmap(NULL)
324 {
325 }
326 
327 
328 OffscreenBitmap::~OffscreenBitmap()
329 {
330 	delete fBitmap;
331 }
332 
333 
334 void
335 OffscreenBitmap::NewBitmap(BRect bounds)
336 {
337 	delete fBitmap;
338 	fBitmap = new BBitmap(bounds, B_RGB32, true);
339 	if (fBitmap->Lock()) {
340 		BView *view = new BView(fBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
341 		fBitmap->AddChild(view);
342 
343 		BRect clipRect = view->Bounds();
344 		BRegion newClip;
345 		newClip.Set(clipRect);
346 		view->ConstrainClippingRegion(&newClip);
347 
348 		fBitmap->Unlock();
349 	} else {
350 		delete fBitmap;
351 		fBitmap = NULL;
352 	}
353 }
354 
355 
356 BView *
357 OffscreenBitmap::BeginUsing(BRect frame)
358 {
359 	if (!fBitmap || fBitmap->Bounds() != frame)
360 		NewBitmap(frame);
361 
362 	fBitmap->Lock();
363 	return View();
364 }
365 
366 
367 void
368 OffscreenBitmap::DoneUsing()
369 {
370 	fBitmap->Unlock();
371 }
372 
373 
374 BBitmap *
375 OffscreenBitmap::Bitmap() const
376 {
377 	ASSERT(fBitmap);
378 	ASSERT(fBitmap->IsLocked());
379 	return fBitmap;
380 }
381 
382 
383 BView *
384 OffscreenBitmap::View() const
385 {
386 	ASSERT(fBitmap);
387 	return fBitmap->ChildAt(0);
388 }
389 
390 
391 // #pragma mark -
392 
393 
394 namespace BPrivate {
395 
396 /** Changes the alpha value of the given bitmap to create a nice
397  *	horizontal fade out in the specified region.
398  *	"from" is always transparent, "to" opaque.
399  */
400 
401 void
402 FadeRGBA32Horizontal(uint32 *bits, int32 width, int32 height, int32 from, int32 to)
403 {
404 	// check parameters
405 	if (width < 0 || height < 0 || from < 0 || to < 0)
406 		return;
407 
408 	float change = 1.f / (to - from);
409 	if (from > to) {
410 		int32 temp = from;
411 		from = to;
412 		to = temp;
413 	}
414 
415 	for (int32 y = 0; y < height; y++) {
416 		float alpha = change > 0 ? 0.0f : 1.0f;
417 
418 		for (int32 x = from; x <= to; x++) {
419 			if (bits[x] & 0xff000000) {
420 				uint32 a = uint32((bits[x] >> 24) * alpha);
421 				bits[x] = (bits[x] & 0x00ffffff) | (a << 24);
422 			}
423 			alpha += change;
424 		}
425 		bits += width;
426 	}
427 }
428 
429 
430 /** Changes the alpha value of the given bitmap to create a nice
431  *	vertical fade out in the specified region.
432  *	"from" is always transparent, "to" opaque.
433  */
434 
435 void
436 FadeRGBA32Vertical(uint32 *bits, int32 width, int32 height, int32 from, int32 to)
437 {
438 	// check parameters
439 	if (width < 0 || height < 0 || from < 0 || to < 0)
440 		return;
441 
442 	if (from > to)
443 		bits += width * (height - (from - to));
444 
445 	float change = 1.f / (to - from);
446 	if (from > to) {
447 		int32 temp = from;
448 		from = to;
449 		to = temp;
450 	}
451 
452 	float alpha = change > 0 ? 0.0f : 1.0f;
453 
454 	for (int32 y = from; y <= to; y++) {
455 		for (int32 x = 0; x < width; x++) {
456 			if (bits[x] & 0xff000000) {
457 				uint32 a = uint32((bits[x] >> 24) * alpha);
458 				bits[x] = (bits[x] & 0x00ffffff) | (a << 24);
459 			}
460 		}
461 		alpha += change;
462 		bits += width;
463 	}
464 }
465 
466 }	// namespace BPrivate
467 
468 
469 // #pragma mark -
470 
471 
472 DraggableIcon::DraggableIcon(BRect rect, const char *name, const char *mimeType,
473 		icon_size size, const BMessage *message, BMessenger target,
474 		uint32 resizeMask, uint32 flags)
475 	: BView(rect, name, resizeMask, flags),
476 	fMessage(*message),
477 	fTarget(target)
478 {
479 	fBitmap = new BBitmap(Bounds(), kDefaultIconDepth);
480 	BMimeType mime(mimeType);
481 	status_t error = mime.GetIcon(fBitmap, size);
482 	ASSERT(mime.IsValid());
483 	if (error != B_OK) {
484 		PRINT(("failed to get icon for %s, %s\n", mimeType, strerror(error)));
485 		BMimeType mime(B_FILE_MIMETYPE);
486 		ASSERT(mime.IsInstalled());
487 		mime.GetIcon(fBitmap, size);
488 	}
489 }
490 
491 
492 DraggableIcon::~DraggableIcon()
493 {
494 	delete fBitmap;
495 }
496 
497 
498 void
499 DraggableIcon::SetTarget(BMessenger target)
500 {
501 	fTarget = target;
502 }
503 
504 
505 BRect
506 DraggableIcon::PreferredRect(BPoint offset, icon_size size)
507 {
508 	BRect result(0, 0, size - 1, size - 1);
509 	result.OffsetTo(offset);
510 	return result;
511 }
512 
513 
514 void
515 DraggableIcon::AttachedToWindow()
516 {
517 	BView *parent = Parent();
518 	if (parent) {
519 		SetViewColor(parent->ViewColor());
520 		SetLowColor(parent->LowColor());
521 	}
522 }
523 
524 
525 void
526 DraggableIcon::MouseDown(BPoint point)
527 {
528 	if (!DragStarted(&fMessage))
529 		return;
530 
531 	BRect rect(Bounds());
532 	BBitmap *dragBitmap = new BBitmap(rect, B_RGBA32, true);
533 	dragBitmap->Lock();
534 	BView *view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
535 	dragBitmap->AddChild(view);
536 	view->SetOrigin(0, 0);
537 	BRect clipRect(view->Bounds());
538 	BRegion newClip;
539 	newClip.Set(clipRect);
540 	view->ConstrainClippingRegion(&newClip);
541 
542 	// Transparent draw magic
543 	view->SetHighColor(0, 0, 0, 0);
544 	view->FillRect(view->Bounds());
545 	view->SetDrawingMode(B_OP_ALPHA);
546 	view->SetHighColor(0, 0, 0, 128);
547 		// set the level of transparency by value
548 	view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
549 	view->DrawBitmap(fBitmap);
550 	view->Sync();
551 	dragBitmap->Unlock();
552 	DragMessage(&fMessage, dragBitmap, B_OP_ALPHA, point, fTarget.Target(0));
553 }
554 
555 
556 bool
557 DraggableIcon::DragStarted(BMessage *)
558 {
559 	return true;
560 }
561 
562 
563 void
564 DraggableIcon::Draw(BRect)
565 {
566 	SetDrawingMode(B_OP_OVER);
567 	DrawBitmap(fBitmap);
568 }
569 
570 
571 // #pragma mark -
572 
573 
574 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char *name,
575 		const char *text, uint32 resizeFlags, uint32 flags)
576 	: BStringView(bounds, name, text, resizeFlags, flags),
577 	fBitmap(NULL),
578 	fOrigBitmap(NULL)
579 {
580 }
581 
582 
583 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char *name,
584 		const char *text, BBitmap *inBitmap, uint32 resizeFlags, uint32 flags)
585 	: BStringView(bounds, name, text, resizeFlags, flags),
586 	fBitmap(NULL),
587 	fOrigBitmap(inBitmap)
588 {
589 }
590 
591 
592 FlickerFreeStringView::~FlickerFreeStringView()
593 {
594 	delete fBitmap;
595 }
596 
597 
598 void
599 FlickerFreeStringView::Draw(BRect)
600 {
601 	BRect bounds(Bounds());
602 	if (!fBitmap)
603 		fBitmap = new OffscreenBitmap(Bounds());
604 
605 	BView *offscreen = fBitmap->BeginUsing(bounds);
606 
607 	if (Parent()) {
608 		fViewColor = Parent()->ViewColor();
609 		fLowColor = Parent()->ViewColor();
610 	}
611 
612 	offscreen->SetViewColor(fViewColor);
613 	offscreen->SetHighColor(HighColor());
614 	offscreen->SetLowColor(fLowColor);
615 
616 	BFont font;
617     GetFont(&font);
618 	offscreen->SetFont(&font);
619 
620 	offscreen->Sync();
621 	if (fOrigBitmap)
622 		offscreen->DrawBitmap(fOrigBitmap, Frame(), bounds);
623 	else
624 		offscreen->FillRect(bounds, B_SOLID_LOW);
625 
626 	if (Text()) {
627 		BPoint loc;
628 
629 		font_height	height;
630 		GetFontHeight(&height);
631 
632 		edge_info eInfo;
633 		switch (Alignment()) {
634 			case B_ALIGN_LEFT:
635 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
636 			case B_ALIGN_HORIZONTAL_UNSET:
637 			case B_ALIGN_USE_FULL_WIDTH:
638 #endif
639 			{
640 				// If the first char has a negative left edge give it
641 				// some more room by shifting that much more to the right.
642 				font.GetEdges(Text(), 1, &eInfo);
643 				loc.x = bounds.left + (2 - eInfo.left);
644 				break;
645 			}
646 
647 			case B_ALIGN_CENTER:
648 			{
649 				float width = StringWidth(Text());
650 				float center = (bounds.right - bounds.left) / 2;
651 				loc.x = center - (width/2);
652 				break;
653 			}
654 
655 			case B_ALIGN_RIGHT:
656 			{
657 				float width = StringWidth(Text());
658 				loc.x = bounds.right - width - 2;
659 				break;
660 			}
661 		}
662 		loc.y = bounds.bottom - (1 + height.descent);
663 		offscreen->MovePenTo(loc);
664 		offscreen->DrawString(Text());
665 	}
666 	offscreen->Sync();
667 	SetDrawingMode(B_OP_COPY);
668 	DrawBitmap(fBitmap->Bitmap());
669 	fBitmap->DoneUsing();
670 }
671 
672 
673 void
674 FlickerFreeStringView::AttachedToWindow()
675 {
676 	_inherited::AttachedToWindow();
677 	if (Parent()) {
678 		fViewColor = Parent()->ViewColor();
679 		fLowColor = Parent()->ViewColor();
680 	}
681 	SetViewColor(B_TRANSPARENT_32_BIT);
682 	SetLowColor(B_TRANSPARENT_32_BIT);
683 }
684 
685 
686 void
687 FlickerFreeStringView::SetViewColor(rgb_color color)
688 {
689 	if (fViewColor != color) {
690 		fViewColor = color;
691 		Invalidate();
692 	}
693 	_inherited::SetViewColor(B_TRANSPARENT_32_BIT);
694 }
695 
696 
697 void
698 FlickerFreeStringView::SetLowColor(rgb_color color)
699 {
700 	if (fLowColor != color) {
701 		fLowColor = color;
702 		Invalidate();
703 	}
704 	_inherited::SetLowColor(B_TRANSPARENT_32_BIT);
705 }
706 
707 
708 // #pragma mark -
709 
710 
711 TitledSeparatorItem::TitledSeparatorItem(const char *label)
712 	: BMenuItem(label, 0)
713 {
714 	_inherited::SetEnabled(false);
715 }
716 
717 
718 TitledSeparatorItem::~TitledSeparatorItem()
719 {
720 }
721 
722 
723 void
724 TitledSeparatorItem::SetEnabled(bool)
725 {
726 	// leave disabled
727 }
728 
729 
730 void
731 TitledSeparatorItem::GetContentSize(float *width, float *height)
732 {
733 	_inherited::GetContentSize(width, height);
734 }
735 
736 
737 inline rgb_color
738 ShiftMenuBackgroundColor(float by)
739 {
740 	return tint_color(ui_color(B_MENU_BACKGROUND_COLOR), by);
741 }
742 
743 
744 void
745 TitledSeparatorItem::Draw()
746 {
747 	BRect frame(Frame());
748 
749 	BMenu *parent = Menu();
750 	ASSERT(parent);
751 
752 	menu_info minfo;
753 	get_menu_info(&minfo);
754 
755 	if (minfo.separator > 0) {
756 		frame.left += 10;
757 		frame.right -= 10;
758 	} else {
759 		frame.left += 1;
760 		frame.right -= 1;
761 	}
762 
763 	float startX = frame.left;
764 	float endX = frame.right;
765 
766 	float maxStringWidth = endX - startX - (2 * kMinSeparatorStubX
767 		+ 2 * kStubToStringSlotX);
768 
769 	// ToDo:
770 	// handle case where maxStringWidth turns out negative here
771 
772 	BString truncatedLabel(Label());
773 	parent->TruncateString(&truncatedLabel, B_TRUNCATE_END, maxStringWidth);
774 
775 	maxStringWidth = parent->StringWidth(truncatedLabel.String());
776 
777 	// first calculate the length of the stub part of the
778 	// divider line, so we can use it for secondStartX
779 	float firstEndX = ((endX - startX) - maxStringWidth) / 2 - kStubToStringSlotX;
780 	if (firstEndX < 0)
781 		firstEndX = 0;
782 
783 	float secondStartX = endX - firstEndX;
784 
785 	// now finish calculating firstEndX
786 	firstEndX += startX;
787 
788 	parent->PushState();
789 
790 	int32 y = (int32) (frame.top + (frame.bottom - frame.top) / 2);
791 
792 	parent->BeginLineArray(minfo.separator == 2 ? 6 : 4);
793 	parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y),
794 		ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
795 	parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y),
796 		ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
797 
798 	if (minfo.separator == 2) {
799 		y++;
800 		frame.left++;
801 		frame.right--;
802 		parent->AddLine(BPoint(frame.left,y), BPoint(firstEndX, y),
803 			ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
804 		parent->AddLine(BPoint(secondStartX,y), BPoint(frame.right, y),
805 			ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
806 	}
807 	y++;
808 	if (minfo.separator == 2) {
809 		frame.left++;
810 		frame.right--;
811 	}
812 	parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y),
813 		ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
814 	parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y),
815 		ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
816 
817 	parent->EndLineArray();
818 
819 	font_height	finfo;
820 	parent->GetFontHeight(&finfo);
821 
822 	parent->SetLowColor(parent->ViewColor());
823 	BPoint loc(firstEndX + kStubToStringSlotX, ContentLocation().y + finfo.ascent);
824 
825 	parent->MovePenTo(loc + BPoint(1, 1));
826 	parent->SetHighColor(ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
827 	parent->DrawString(truncatedLabel.String());
828 
829 	parent->MovePenTo(loc);
830 	parent->SetHighColor(ShiftMenuBackgroundColor(B_DISABLED_LABEL_TINT));
831 	parent->DrawString(truncatedLabel.String());
832 
833 	parent->PopState();
834 }
835 
836 
837 // #pragma mark -
838 
839 
840 ShortcutFilter::ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier,
841 		uint32 shortcutWhat, BHandler *target)
842 	: BMessageFilter(B_KEY_DOWN),
843 	fShortcutKey(shortcutKey),
844 	fShortcutModifier(shortcutModifier),
845 	fShortcutWhat(shortcutWhat),
846 	fTarget(target)
847 {
848 }
849 
850 
851 filter_result
852 ShortcutFilter::Filter(BMessage *message, BHandler **)
853 {
854 	if (message->what == B_KEY_DOWN) {
855 		uint32 modifiers;
856 		uint32 rawKeyChar = 0;
857 		uint8 byte = 0;
858 		int32 key = 0;
859 
860 		if (message->FindInt32("modifiers", (int32 *)&modifiers) != B_OK
861 			|| message->FindInt32("raw_char", (int32 *)&rawKeyChar) != B_OK
862 			|| message->FindInt8("byte", (int8 *)&byte) != B_OK
863 			|| message->FindInt32("key", &key) != B_OK)
864 			return B_DISPATCH_MESSAGE;
865 
866 		modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
867 			| B_OPTION_KEY | B_MENU_KEY;
868 			// strip caps lock, etc.
869 
870 		if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) {
871 			fTarget->Looper()->PostMessage(fShortcutWhat, fTarget);
872 			return B_SKIP_MESSAGE;
873 		}
874 	}
875 
876 	// let others deal with this
877 	return B_DISPATCH_MESSAGE;
878 }
879 
880 
881 // #pragma mark -
882 
883 
884 namespace BPrivate {
885 
886 void
887 EmbedUniqueVolumeInfo(BMessage *message, const BVolume *volume)
888 {
889 	BDirectory rootDirectory;
890 	time_t created;
891 	fs_info info;
892 
893 	if (volume->GetRootDirectory(&rootDirectory) == B_OK
894 		&& rootDirectory.GetCreationTime(&created) == B_OK
895 		&& fs_stat_dev(volume->Device(), &info) == 0) {
896 		message->AddInt32("creationDate", created);
897 		message->AddInt64("capacity", volume->Capacity());
898 		message->AddString("deviceName", info.device_name);
899 		message->AddString("volumeName", info.volume_name);
900 		message->AddString("fshName", info.fsh_name);
901 	}
902 }
903 
904 
905 status_t
906 MatchArchivedVolume(BVolume *result, const BMessage *message, int32 index)
907 {
908 	time_t created;
909 	off_t capacity;
910 
911 	if (message->FindInt32("creationDate", index, &created) != B_OK
912 		|| message->FindInt64("capacity", index, &capacity) != B_OK)
913 		return B_ERROR;
914 
915 	BVolumeRoster roster;
916 	BVolume volume;
917 	BString deviceName, volumeName, fshName;
918 
919 	if (message->FindString("deviceName", &deviceName) == B_OK
920 		&& message->FindString("volumeName", &volumeName) == B_OK
921 		&& message->FindString("fshName", &fshName) == B_OK) {
922 		// New style volume identifiers: We have a couple of characteristics,
923 		// and compute a score from them. The volume with the greatest score
924 		// (if over a certain threshold) is the one we're looking for. We
925 		// pick the first volume, in case there is more than one with the
926 		// same score.
927 		dev_t foundDevice = -1;
928 		int foundScore = -1;
929 		roster.Rewind();
930 		while (roster.GetNextVolume(&volume) == B_OK) {
931 			if (volume.IsPersistent() && volume.KnowsQuery()) {
932 				// get creation time and fs_info
933 				BDirectory root;
934 				volume.GetRootDirectory(&root);
935 				time_t cmpCreated;
936 				fs_info info;
937 				if (root.GetCreationTime(&cmpCreated) == B_OK
938 					&& fs_stat_dev(volume.Device(), &info) == 0) {
939 					// compute the score
940 					int score = 0;
941 
942 					// creation time
943 					if (created == cmpCreated)
944 						score += 5;
945 					// capacity
946 					if (capacity == volume.Capacity())
947 						score += 4;
948 					// device name
949 					if (deviceName == info.device_name)
950 						score += 3;
951 					// volume name
952 					if (volumeName == info.volume_name)
953 						score += 2;
954 					// fsh name
955 					if (fshName == info.fsh_name)
956 						score += 1;
957 
958 					// check score
959 					if (score >= 9 && score > foundScore) {
960 						foundDevice = volume.Device();
961 						foundScore = score;
962 					}
963 				}
964 			}
965 		}
966 		if (foundDevice >= 0)
967 			return result->SetTo(foundDevice);
968 	} else {
969 		// Old style volume identifiers: We have only creation time and
970 		// capacity. Both must match.
971 		roster.Rewind();
972 		while (roster.GetNextVolume(&volume) == B_OK)
973 			if (volume.IsPersistent() && volume.KnowsQuery()) {
974 				BDirectory root;
975 				volume.GetRootDirectory(&root);
976 				time_t cmpCreated;
977 				root.GetCreationTime(&cmpCreated);
978 				if (created == cmpCreated && capacity == volume.Capacity()) {
979 					*result = volume;
980 					return B_OK;
981 				}
982 			}
983 	}
984 
985 	return B_DEV_BAD_DRIVE_NUM;
986 }
987 
988 
989 void
990 StringFromStream(BString *string, BMallocIO *stream, bool endianSwap)
991 {
992 	int32 length;
993 	stream->Read(&length, sizeof(length));
994 	if (endianSwap)
995 		length = SwapInt32(length);
996 
997 	if (length <= 0 || length > 10000) {
998 		// ToDo:
999 		// should fail here
1000 		PRINT(("problems instatiating a string, length probably wrong %d\n", length));
1001 		return;
1002 	}
1003 
1004 	char *buffer = string->LockBuffer(length);
1005 	stream->Read(buffer, (size_t)length + 1);
1006 	string->UnlockBuffer(length);
1007 }
1008 
1009 
1010 void
1011 StringToStream(const BString *string, BMallocIO *stream)
1012 {
1013 	int32 length = string->Length();
1014 	stream->Write(&length, sizeof(int32));
1015 	stream->Write(string->String(), (size_t)string->Length() + 1);
1016 }
1017 
1018 
1019 int32
1020 ArchiveSize(const BString *string)
1021 {
1022 	return string->Length() + 1 + (ssize_t)sizeof(int32);
1023 }
1024 
1025 
1026 int32
1027 CountRefs(const BMessage *message)
1028 {
1029 	uint32 type;
1030 	int32 count;
1031 	message->GetInfo("refs", &type, &count);
1032 
1033 	return count;
1034 }
1035 
1036 
1037 static entry_ref *
1038 EachEntryRefCommon(BMessage *message, entry_ref *(*func)(entry_ref *, void *),
1039 	void *passThru, int32 maxCount)
1040 {
1041 	uint32 type;
1042 	int32 count;
1043 	message->GetInfo("refs", &type, &count);
1044 
1045 	if (maxCount >= 0 && count > maxCount)
1046 		count = maxCount;
1047 
1048 	for (int32 index = 0; index < count; index++) {
1049 		entry_ref ref;
1050 		message->FindRef("refs", index, &ref);
1051 		entry_ref *result = (func)(&ref, passThru);
1052 		if (result)
1053 			return result;
1054 	}
1055 
1056 	return NULL;
1057 }
1058 
1059 
1060 bool
1061 ContainsEntryRef(const BMessage *message, const entry_ref *ref)
1062 {
1063 	entry_ref match;
1064 	for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK); index++) {
1065 		if (*ref == match)
1066 			return true;
1067 	}
1068 
1069 	return false;
1070 }
1071 
1072 
1073 entry_ref *
1074 EachEntryRef(BMessage *message, entry_ref *(*func)(entry_ref *, void *),
1075 	void *passThru)
1076 {
1077 	return EachEntryRefCommon(message, func, passThru, -1);
1078 }
1079 
1080 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *);
1081 
1082 const entry_ref *
1083 EachEntryRef(const BMessage *message, const entry_ref *(*func)(const entry_ref *, void *),
1084 	void *passThru)
1085 {
1086 	return EachEntryRefCommon(const_cast<BMessage *>(message),
1087 		(EachEntryIteratee)func, passThru, -1);
1088 }
1089 
1090 
1091 entry_ref *
1092 EachEntryRef(BMessage *message, entry_ref *(*func)(entry_ref *, void *),
1093 	void *passThru, int32 maxCount)
1094 {
1095 	return EachEntryRefCommon(message, func, passThru, maxCount);
1096 }
1097 
1098 
1099 const entry_ref *
1100 EachEntryRef(const BMessage *message, const entry_ref *(*func)(const entry_ref *, void *),
1101 	void *passThru, int32 maxCount)
1102 {
1103 	return EachEntryRefCommon(const_cast<BMessage *>(message),
1104 		(EachEntryIteratee)func, passThru, maxCount);
1105 }
1106 
1107 
1108 void
1109 TruncateLeaf(BString *string)
1110 {
1111 	for (int32 index = string->Length(); index >= 0; index--) {
1112 		if ((*string)[index] == '/') {
1113 			string->Truncate(index + 1);
1114 			return;
1115 		}
1116 	}
1117 }
1118 
1119 
1120 int64
1121 StringToScalar(const char *text)
1122 {
1123 	char *end;
1124 	int64 val;
1125 
1126 	char *buffer = new char [strlen(text) + 1];
1127 	strcpy(buffer, text);
1128 
1129 	if (strstr(buffer, "k") || strstr(buffer, "K")) {
1130 		val = strtoll(buffer, &end, 10);
1131 		val *= kKBSize;
1132 	} else if (strstr(buffer, "mb") || strstr(buffer, "MB")) {
1133 		val = strtoll(buffer, &end, 10);
1134 		val *= kMBSize;
1135 	} else if (strstr(buffer, "gb") || strstr(buffer, "GB")) {
1136 		val = strtoll(buffer, &end, 10);
1137 		val *= kGBSize;
1138 	} else if (strstr(buffer, "byte") || strstr(buffer, "BYTE")) {
1139 		val = strtoll(buffer, &end, 10);
1140 		val *= kGBSize;
1141 	} else {
1142 		// no suffix, try plain byte conversion
1143 		val = strtoll(buffer, &end, 10);
1144 	}
1145 
1146 	delete [] buffer;
1147 	return val;
1148 }
1149 
1150 #if B_BEOS_VERSION <= B_BEOS_VERSION_MAUI && !defined(__HAIKU__)
1151 
1152 bool
1153 operator==(const rgb_color &a, const rgb_color &b)
1154 {
1155 	return a.red == b.red
1156 		&& a.green == b.green
1157 		&& a.blue == b.blue
1158 		&& a.alpha == b.alpha;
1159 }
1160 
1161 
1162 bool
1163 operator!=(const rgb_color &a, const rgb_color &b)
1164 {
1165 	return !operator==(a, b);
1166 }
1167 
1168 #endif
1169 
1170 
1171 static BRect
1172 LineBounds(BPoint where, float length, bool vertical)
1173 {
1174 	BRect result;
1175 	result.SetLeftTop(where);
1176 	result.SetRightBottom(where + BPoint(2, 2));
1177 	if (vertical)
1178 		result.bottom = result.top + length;
1179 	else
1180 		result.right = result.left + length;
1181 
1182 	return result;
1183 }
1184 
1185 
1186 SeparatorLine::SeparatorLine(BPoint where, float length, bool vertical, const char *name)
1187 	: BView(LineBounds(where, length, vertical), name,
1188 		B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW)
1189 {
1190 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
1191 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
1192 }
1193 
1194 
1195 void
1196 SeparatorLine::Draw(BRect)
1197 {
1198 	BRect bounds(Bounds());
1199 	rgb_color hiliteColor = tint_color(ViewColor(), 1.5f);
1200 
1201 	bool vertical = (bounds.left > bounds.right - 3);
1202 	BeginLineArray(2);
1203 	if (vertical) {
1204 		AddLine(bounds.LeftTop(), bounds.LeftBottom(), hiliteColor);
1205 		AddLine(bounds.LeftTop() + BPoint(1, 0), bounds.LeftBottom() + BPoint(1, 0), kWhite);
1206 	} else {
1207 		AddLine(bounds.LeftTop(), bounds.RightTop(), hiliteColor);
1208 		AddLine(bounds.LeftTop() + BPoint(0, 1), bounds.RightTop() + BPoint(0, 1), kWhite);
1209 	}
1210 	EndLineArray();
1211 }
1212 
1213 
1214 void
1215 HexDump(const void *buf, int32 length)
1216 {
1217 	const int32 kBytesPerLine = 16;
1218 	int32 offset;
1219 	unsigned char *buffer = (unsigned char *)buf;
1220 
1221 	for (offset = 0; ; offset += kBytesPerLine, buffer += kBytesPerLine) {
1222 		int32 remain = length;
1223 		int32 index;
1224 
1225 		printf( "0x%06x: ", (int)offset);
1226 
1227 		for (index = 0; index < kBytesPerLine; index++) {
1228 			if (remain-- > 0)
1229 				printf("%02x%c", buffer[index], remain > 0 ? ',' : ' ');
1230 			else
1231 				printf("   ");
1232 		}
1233 
1234 		remain = length;
1235 		printf(" \'");
1236 		for (index = 0; index < kBytesPerLine; index++) {
1237 			if (remain-- > 0)
1238 				printf("%c", buffer[index] > ' ' ? buffer[index] : '.');
1239 			else
1240 				printf(" ");
1241 		}
1242 		printf("\'\n");
1243 
1244 		length -= kBytesPerLine;
1245 		if (length <= 0)
1246 			break;
1247 	}
1248 	fflush(stdout);
1249 }
1250 
1251 
1252 void
1253 EnableNamedMenuItem(BMenu *menu, const char *itemName, bool on)
1254 {
1255 	BMenuItem *item = menu->FindItem(itemName);
1256 	if (item)
1257 		item->SetEnabled(on);
1258 }
1259 
1260 
1261 void
1262 MarkNamedMenuItem(BMenu *menu, const char *itemName, bool on)
1263 {
1264 	BMenuItem *item = menu->FindItem(itemName);
1265 	if (item)
1266 		item->SetMarked(on);
1267 }
1268 
1269 
1270 void
1271 EnableNamedMenuItem(BMenu *menu, uint32 commandName, bool on)
1272 {
1273 	BMenuItem *item = menu->FindItem(commandName);
1274 	if (item)
1275 		item->SetEnabled(on);
1276 }
1277 
1278 
1279 void
1280 MarkNamedMenuItem(BMenu *menu, uint32 commandName, bool on)
1281 {
1282 	BMenuItem *item = menu->FindItem(commandName);
1283 	if (item)
1284 		item->SetMarked(on);
1285 }
1286 
1287 
1288 void
1289 DeleteSubmenu(BMenuItem *submenuItem)
1290 {
1291 	if (!submenuItem)
1292 		return;
1293 
1294 	BMenu *menu = submenuItem->Submenu();
1295 	if (!menu)
1296 		return;
1297 
1298 	for (;;) {
1299 		BMenuItem *item = menu->RemoveItem((int32)0);
1300 		if (!item)
1301 			return;
1302 
1303 		delete item;
1304 	}
1305 }
1306 
1307 
1308 status_t
1309 GetAppSignatureFromAttr(BFile *file, char *result)
1310 {
1311 	// This call is a performance improvement that
1312 	// avoids using the BAppFileInfo API when retrieving the
1313 	// app signature -- the call is expensive because by default
1314 	// the resource fork is scanned to read the attribute
1315 
1316 #ifdef B_APP_FILE_INFO_IS_FAST
1317 	BAppFileInfo appFileInfo(file);
1318 	return appFileInfo.GetSignature(result);
1319 #else
1320 	ssize_t readResult = file->ReadAttr(kAttrAppSignature, B_MIME_STRING_TYPE,
1321 		0, result, B_MIME_TYPE_LENGTH);
1322 
1323 	if (readResult <= 0)
1324 		return (status_t)readResult;
1325 
1326 	return B_OK;
1327 #endif	// B_APP_FILE_INFO_IS_FAST
1328 }
1329 
1330 
1331 status_t
1332 GetAppIconFromAttr(BFile *file, BBitmap *result, icon_size size)
1333 {
1334 	// This call is a performance improvement that
1335 	// avoids using the BAppFileInfo API when retrieving the
1336 	// app icons -- the call is expensive because by default
1337 	// the resource fork is scanned to read the icons
1338 
1339 //#ifdef B_APP_FILE_INFO_IS_FAST
1340 	BAppFileInfo appFileInfo(file);
1341 	return appFileInfo.GetIcon(result, size);
1342 //#else
1343 //
1344 //	const char *attrName = kAttrIcon;
1345 //	uint32 type = B_RAW_TYPE;
1346 //
1347 //	// try vector icon
1348 //	attr_info ainfo;
1349 //	status_t ret = file->GetAttrInfo(attrName, &ainfo);
1350 //
1351 //	if (ret == B_OK) {
1352 //		uint8 buffer[ainfo.size];
1353 //		ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer,
1354 //											ainfo.size);
1355 //		if (readResult == ainfo.size) {
1356 //			if (BIconUtils::GetVectorIcon(buffer, ainfo.size, result) == B_OK)
1357 //				return B_OK;
1358 //		}
1359 //	}
1360 //
1361 //	// try again with R5 icons
1362 //	attrName = size == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon;
1363 //	type = size == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE;
1364 //
1365 //	ret = file->GetAttrInfo(attrName, &ainfo);
1366 //	if (ret < B_OK)
1367 //		return ret;
1368 //
1369 //	uint8 buffer[ainfo.size];
1370 //
1371 //	ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size);
1372 //	if (readResult <= 0)
1373 //		return (status_t)readResult;
1374 //
1375 //	if (result->ColorSpace() != B_CMAP8) {
1376 //		ret = BIconUtils::ConvertFromCMAP8(buffer, size, size, size, result);
1377 //	} else {
1378 //		result->SetBits(buffer, result->BitsLength(), 0, B_CMAP8);
1379 //	}
1380 //
1381 //	return ret;
1382 //#endif	// B_APP_FILE_INFO_IS_FAST
1383 }
1384 
1385 
1386 status_t
1387 GetFileIconFromAttr(BNode *file, BBitmap *result, icon_size size)
1388 {
1389 	BNodeInfo fileInfo(file);
1390 	return fileInfo.GetIcon(result, size);
1391 }
1392 
1393 
1394 void
1395 PrintToStream(rgb_color color)
1396 {
1397 	printf("r:%x, g:%x, b:%x, a:%x\n",
1398 		color.red, color.green, color.blue, color.alpha);
1399 }
1400 
1401 
1402 extern BMenuItem *
1403 EachMenuItem(BMenu *menu, bool recursive, BMenuItem *(*func)(BMenuItem *))
1404 {
1405 	int32 count = menu->CountItems();
1406 	for (int32 index = 0; index < count; index++) {
1407 		BMenuItem *item = menu->ItemAt(index);
1408 		BMenuItem *result = (func)(item);
1409 		if (result)
1410 			return result;
1411 
1412 		if (recursive) {
1413 			BMenu *submenu = menu->SubmenuAt(index);
1414 			if (submenu)
1415 				return EachMenuItem(submenu, true, func);
1416 		}
1417 	}
1418 
1419 	return NULL;
1420 }
1421 
1422 
1423 extern const BMenuItem *
1424 EachMenuItem(const BMenu *menu, bool recursive, BMenuItem *(*func)(const BMenuItem *))
1425 {
1426 	int32 count = menu->CountItems();
1427 	for (int32 index = 0; index < count; index++) {
1428 		BMenuItem *item = menu->ItemAt(index);
1429 		BMenuItem *result = (func)(item);
1430 		if (result)
1431 			return result;
1432 
1433 		if (recursive) {
1434 			BMenu *submenu = menu->SubmenuAt(index);
1435 			if (submenu)
1436 				return EachMenuItem(submenu, true, func);
1437 		}
1438 	}
1439 
1440 	return NULL;
1441 }
1442 
1443 
1444 PositionPassingMenuItem::PositionPassingMenuItem(const char *title,
1445 		BMessage *message, char shortcut, uint32 modifiers)
1446 	: BMenuItem(title, message, shortcut, modifiers)
1447 {
1448 }
1449 
1450 
1451 PositionPassingMenuItem::PositionPassingMenuItem(BMenu *menu,
1452 		BMessage *message)
1453 	: BMenuItem(menu, message)
1454 {
1455 }
1456 
1457 
1458 status_t
1459 PositionPassingMenuItem::Invoke(BMessage *message)
1460 {
1461 	if (!Menu())
1462 		return B_ERROR;
1463 
1464 	if (!IsEnabled())
1465 		return B_ERROR;
1466 
1467 	if (!message)
1468 		message = Message();
1469 
1470 	if (!message)
1471 		return B_BAD_VALUE;
1472 
1473 	BMessage clone(*message);
1474 	clone.AddInt32("index", Menu()->IndexOf(this));
1475 	clone.AddInt64("when", system_time());
1476 	clone.AddPointer("source", this);
1477 
1478 	// embed the invoke location of the menu so that we can create
1479 	// a new folder, etc. on the spot
1480 	BMenu *menu = Menu();
1481 
1482 	for (;;) {
1483 		if (!menu->Supermenu())
1484 			break;
1485 		menu = menu->Supermenu();
1486 	}
1487 
1488 	// use the window position only, if the item was invoked from the menu
1489 	// menu->Window() points to the window the item was invoked from
1490 	if (dynamic_cast<BContainerWindow *>(menu->Window()) == NULL) {
1491 		LooperAutoLocker lock(menu);
1492 		if (lock.IsLocked()) {
1493 			BPoint invokeOrigin(menu->Window()->Frame().LeftTop());
1494 			clone.AddPoint("be:invoke_origin", invokeOrigin);
1495 		}
1496 	}
1497 
1498 	return BInvoker::Invoke(&clone);
1499 }
1500 
1501 
1502 bool
1503 BootedInSafeMode()
1504 {
1505 	const char *safeMode = getenv("SAFEMODE");
1506 	return (safeMode && strcmp(safeMode, "yes") == 0);
1507 }
1508 
1509 
1510 void
1511 _ThrowOnError(status_t error, const char *DEBUG_ONLY(file), int32 DEBUG_ONLY(line))
1512 {
1513 	if (error != B_OK) {
1514 		PRINT(("failing %s at %s:%d\n", strerror(error), file, line));
1515 		throw error;
1516 	}
1517 }
1518 
1519 
1520 void
1521 _ThrowIfNotSize(ssize_t size, const char *DEBUG_ONLY(file), int32 DEBUG_ONLY(line))
1522 {
1523 	if (size < B_OK) {
1524 		PRINT(("failing %s at %s:%d\n", strerror(size), file, line));
1525 		throw (status_t)size;
1526 	}
1527 }
1528 
1529 
1530 void
1531 _ThrowOnError(status_t error, const char *DEBUG_ONLY(debugString),
1532 	const char *DEBUG_ONLY(file), int32 DEBUG_ONLY(line))
1533 {
1534 	if (error != B_OK) {
1535 		PRINT(("failing %s, %s at %s:%d\n", debugString, strerror(error), file, line));
1536 		throw error;
1537 	}
1538 }
1539 
1540 } // namespace BPrivate
1541