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