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