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