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