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