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 "Utilities.h" 37 38 #include <ctype.h> 39 #include <fs_attr.h> 40 #include <fs_info.h> 41 #include <stdarg.h> 42 #include <string.h> 43 #include <stdlib.h> 44 #include <time.h> 45 46 #include <BitmapStream.h> 47 #include <Catalog.h> 48 #include <Debug.h> 49 #include <Font.h> 50 #include <IconUtils.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 "Attributes.h" 62 #include "ContainerWindow.h" 63 #include "MimeTypes.h" 64 #include "Model.h" 65 #include "PoseView.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 hash = seed; 103 104 while((ch = *string++) != 0) { 105 hash = (hash << 7) ^ (hash >> 24); 106 hash ^= ch; 107 } 108 hash ^= hash << 12; 109 110 return hash; 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 hash ^= hash << 12; 125 126 hash &= ~0xff; 127 hash |= type; 128 129 return hash; 130 } 131 132 133 bool 134 ValidateStream(BMallocIO* stream, uint32 key, int32 version) 135 { 136 uint32 testKey; 137 int32 testVersion; 138 139 if (stream->Read(&testKey, sizeof(uint32)) <= 0 140 || stream->Read(&testVersion, sizeof(int32)) <= 0) { 141 return false; 142 } 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) && periodic->pose_view->LockLooper()) { 232 periodic->pose_view->UpdateIcon(periodic->pose); 233 periodic->pose_view->UnlockLooper(); 234 } 235 } 236 237 fLock->Unlock(); 238 } 239 240 241 PeriodicUpdatePoses gPeriodicUpdatePoses; 242 243 } // namespace BPrivate 244 245 246 void 247 PoseInfo::EndianSwap(void* castToThis) 248 { 249 PoseInfo* self = (PoseInfo*)castToThis; 250 251 PRINT(("swapping PoseInfo\n")); 252 253 STATIC_ASSERT(sizeof(ino_t) == sizeof(int64)); 254 self->fInitedDirectory = SwapInt64(self->fInitedDirectory); 255 swap_data(B_POINT_TYPE, &self->fLocation, sizeof(BPoint), B_SWAP_ALWAYS); 256 257 // do a sanity check on the icon position 258 if (self->fLocation.x < -20000 || self->fLocation.x > 20000 259 || self->fLocation.y < -20000 || self->fLocation.y > 20000) { 260 // position out of range, force autoplcemement 261 PRINT((" rejecting icon position out of range\n")); 262 self->fInitedDirectory = -1LL; 263 self->fLocation = BPoint(0, 0); 264 } 265 } 266 267 268 void 269 PoseInfo::PrintToStream() 270 { 271 PRINT(("%s, inode:%" B_PRIx64 ", location %f %f\n", 272 fInvisible ? "hidden" : "visible", 273 fInitedDirectory, fLocation.x, fLocation.y)); 274 } 275 276 277 // #pragma mark - ExtendedPoseInfo 278 279 280 size_t 281 ExtendedPoseInfo::Size() const 282 { 283 return sizeof(ExtendedPoseInfo) + fNumFrames * sizeof(FrameLocation); 284 } 285 286 287 size_t 288 ExtendedPoseInfo::Size(int32 count) 289 { 290 return sizeof(ExtendedPoseInfo) + count * sizeof(FrameLocation); 291 } 292 293 294 size_t 295 ExtendedPoseInfo::SizeWithHeadroom() const 296 { 297 return sizeof(ExtendedPoseInfo) + (fNumFrames + 1) * sizeof(FrameLocation); 298 } 299 300 301 size_t 302 ExtendedPoseInfo::SizeWithHeadroom(size_t oldSize) 303 { 304 int32 count = (ssize_t)oldSize - (ssize_t)sizeof(ExtendedPoseInfo); 305 if (count > 0) 306 count /= sizeof(FrameLocation); 307 else 308 count = 0; 309 310 return Size(count + 1); 311 } 312 313 314 bool 315 ExtendedPoseInfo::HasLocationForFrame(BRect frame) const 316 { 317 for (int32 index = 0; index < fNumFrames; index++) { 318 if (fLocations[index].fFrame == frame) 319 return true; 320 } 321 322 return false; 323 } 324 325 326 BPoint 327 ExtendedPoseInfo::LocationForFrame(BRect frame) const 328 { 329 for (int32 index = 0; index < fNumFrames; index++) { 330 if (fLocations[index].fFrame == frame) 331 return fLocations[index].fLocation; 332 } 333 334 TRESPASS(); 335 return BPoint(0, 0); 336 } 337 338 339 bool 340 ExtendedPoseInfo::SetLocationForFrame(BPoint newLocation, BRect frame) 341 { 342 for (int32 index = 0; index < fNumFrames; index++) { 343 if (fLocations[index].fFrame == frame) { 344 if (fLocations[index].fLocation == newLocation) 345 return false; 346 347 fLocations[index].fLocation = newLocation; 348 return true; 349 } 350 } 351 352 fLocations[fNumFrames].fFrame = frame; 353 fLocations[fNumFrames].fLocation = newLocation; 354 fLocations[fNumFrames].fWorkspaces = 0xffffffff; 355 fNumFrames++; 356 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 which, const BMessage* message, 559 BMessenger target, uint32 resizingMode, uint32 flags) 560 : 561 BView(rect, name, resizingMode, flags), 562 fMessage(*message), 563 fTarget(target) 564 { 565 fBitmap = new BBitmap(Bounds(), kDefaultIconDepth); 566 BMimeType mime(mimeType); 567 status_t result = mime.GetIcon(fBitmap, which); 568 ASSERT(mime.IsValid()); 569 if (result != B_OK) { 570 PRINT(("failed to get icon for %s, %s\n", mimeType, strerror(result))); 571 BMimeType mime(B_FILE_MIMETYPE); 572 ASSERT(mime.IsInstalled()); 573 mime.GetIcon(fBitmap, which); 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 which) 593 { 594 BRect rect(0, 0, which - 1, which - 1); 595 rect.OffsetTo(offset); 596 return rect; 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 resizingMode, uint32 flags) 663 : 664 BStringView(bounds, name, text, resizingMode, flags), 665 fBitmap(NULL), 666 fViewColor(ViewColor()), 667 fLowColor(LowColor()), 668 fOriginalBitmap(NULL) 669 { 670 } 671 672 673 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name, 674 const char* text, BBitmap* inBitmap, uint32 resizingMode, uint32 flags) 675 : 676 BStringView(bounds, name, text, resizingMode, flags), 677 fBitmap(NULL), 678 fViewColor(ViewColor()), 679 fLowColor(LowColor()), 680 fOriginalBitmap(inBitmap) 681 { 682 } 683 684 685 FlickerFreeStringView::~FlickerFreeStringView() 686 { 687 delete fBitmap; 688 } 689 690 691 void 692 FlickerFreeStringView::Draw(BRect) 693 { 694 BRect bounds(Bounds()); 695 if (fBitmap == NULL) 696 fBitmap = new OffscreenBitmap(Bounds()); 697 698 BView* offscreen = fBitmap->BeginUsing(bounds); 699 700 if (Parent() != NULL) { 701 fViewColor = Parent()->ViewColor(); 702 fLowColor = Parent()->ViewColor(); 703 } 704 705 offscreen->SetViewColor(fViewColor); 706 offscreen->SetHighColor(HighColor()); 707 offscreen->SetLowColor(fLowColor); 708 709 BFont font; 710 GetFont(&font); 711 offscreen->SetFont(&font); 712 713 offscreen->Sync(); 714 if (fOriginalBitmap != NULL) 715 offscreen->DrawBitmap(fOriginalBitmap, Frame(), bounds); 716 else 717 offscreen->FillRect(bounds, B_SOLID_LOW); 718 719 if (Text() != NULL) { 720 BPoint loc; 721 722 font_height height; 723 GetFontHeight(&height); 724 725 edge_info eInfo; 726 switch (Alignment()) { 727 case B_ALIGN_LEFT: 728 case B_ALIGN_HORIZONTAL_UNSET: 729 case B_ALIGN_USE_FULL_WIDTH: 730 { 731 // If the first char has a negative left edge give it 732 // some more room by shifting that much more to the right. 733 font.GetEdges(Text(), 1, &eInfo); 734 loc.x = bounds.left + (2 - eInfo.left); 735 break; 736 } 737 738 case B_ALIGN_CENTER: 739 { 740 float width = StringWidth(Text()); 741 float center = (bounds.right - bounds.left) / 2; 742 loc.x = center - (width/2); 743 break; 744 } 745 746 case B_ALIGN_RIGHT: 747 { 748 float width = StringWidth(Text()); 749 loc.x = bounds.right - width - 2; 750 break; 751 } 752 } 753 loc.y = bounds.bottom - (1 + height.descent); 754 offscreen->DrawString(Text(), loc); 755 } 756 offscreen->Sync(); 757 SetDrawingMode(B_OP_COPY); 758 DrawBitmap(fBitmap->Bitmap()); 759 fBitmap->DoneUsing(); 760 } 761 762 763 void 764 FlickerFreeStringView::AttachedToWindow() 765 { 766 _inherited::AttachedToWindow(); 767 if (Parent() != NULL) { 768 fViewColor = Parent()->ViewColor(); 769 fLowColor = Parent()->ViewColor(); 770 } 771 SetViewColor(B_TRANSPARENT_32_BIT); 772 SetLowColor(B_TRANSPARENT_32_BIT); 773 } 774 775 776 void 777 FlickerFreeStringView::SetViewColor(rgb_color color) 778 { 779 if (fViewColor != color) { 780 fViewColor = color; 781 Invalidate(); 782 } 783 _inherited::SetViewColor(B_TRANSPARENT_32_BIT); 784 } 785 786 787 void 788 FlickerFreeStringView::SetLowColor(rgb_color color) 789 { 790 if (fLowColor != color) { 791 fLowColor = color; 792 Invalidate(); 793 } 794 _inherited::SetLowColor(B_TRANSPARENT_32_BIT); 795 } 796 797 798 // #pragma mark - TitledSeparatorItem 799 800 801 TitledSeparatorItem::TitledSeparatorItem(const char* label) 802 : 803 BMenuItem(label, 0) 804 { 805 _inherited::SetEnabled(false); 806 } 807 808 809 TitledSeparatorItem::~TitledSeparatorItem() 810 { 811 } 812 813 814 void 815 TitledSeparatorItem::SetEnabled(bool) 816 { 817 // leave disabled 818 } 819 820 821 void 822 TitledSeparatorItem::GetContentSize(float* width, float* height) 823 { 824 _inherited::GetContentSize(width, height); 825 } 826 827 828 inline rgb_color 829 ShiftMenuBackgroundColor(float by) 830 { 831 return tint_color(ui_color(B_MENU_BACKGROUND_COLOR), by); 832 } 833 834 835 void 836 TitledSeparatorItem::Draw() 837 { 838 BRect frame(Frame()); 839 840 BMenu* parent = Menu(); 841 ASSERT(parent != NULL); 842 843 menu_info minfo; 844 get_menu_info(&minfo); 845 846 if (minfo.separator > 0) { 847 frame.left += 10; 848 frame.right -= 10; 849 } else { 850 frame.left += 1; 851 frame.right -= 1; 852 } 853 854 float startX = frame.left; 855 float endX = frame.right; 856 857 float maxStringWidth = endX - startX - (2 * kMinSeparatorStubX 858 + 2 * kStubToStringSlotX); 859 860 // ToDo: 861 // handle case where maxStringWidth turns out negative here 862 863 BString truncatedLabel(Label()); 864 parent->TruncateString(&truncatedLabel, B_TRUNCATE_END, maxStringWidth); 865 866 maxStringWidth = parent->StringWidth(truncatedLabel.String()); 867 868 // first calculate the length of the stub part of the 869 // divider line, so we can use it for secondStartX 870 float firstEndX = ((endX - startX) - maxStringWidth) / 2 871 - kStubToStringSlotX; 872 if (firstEndX < 0) 873 firstEndX = 0; 874 875 float secondStartX = endX - firstEndX; 876 877 // now finish calculating firstEndX 878 firstEndX += startX; 879 880 parent->PushState(); 881 882 int32 y = (int32) (frame.top + (frame.bottom - frame.top) / 2); 883 884 parent->BeginLineArray(minfo.separator == 2 ? 6 : 4); 885 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y), 886 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 887 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y), 888 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 889 890 if (minfo.separator == 2) { 891 y++; 892 frame.left++; 893 frame.right--; 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 y++; 900 if (minfo.separator == 2) { 901 frame.left++; 902 frame.right--; 903 } 904 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y), 905 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 906 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y), 907 ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 908 909 parent->EndLineArray(); 910 911 font_height finfo; 912 parent->GetFontHeight(&finfo); 913 914 parent->SetLowColor(parent->ViewColor()); 915 BPoint loc(firstEndX + kStubToStringSlotX, 916 ContentLocation().y + finfo.ascent); 917 918 parent->MovePenTo(loc + BPoint(1, 1)); 919 parent->SetHighColor(ShiftMenuBackgroundColor(B_DARKEN_1_TINT)); 920 parent->DrawString(truncatedLabel.String()); 921 922 parent->MovePenTo(loc); 923 parent->SetHighColor(ShiftMenuBackgroundColor(B_DISABLED_LABEL_TINT)); 924 parent->DrawString(truncatedLabel.String()); 925 926 parent->PopState(); 927 } 928 929 930 // #pragma mark - ShortcutFilter 931 932 933 ShortcutFilter::ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier, 934 uint32 shortcutWhat, BHandler* target) 935 : 936 BMessageFilter(B_KEY_DOWN), 937 fShortcutKey(shortcutKey), 938 fShortcutModifier(shortcutModifier), 939 fShortcutWhat(shortcutWhat), 940 fTarget(target) 941 { 942 } 943 944 945 filter_result 946 ShortcutFilter::Filter(BMessage* message, BHandler**) 947 { 948 if (message->what == B_KEY_DOWN) { 949 uint32 modifiers; 950 uint32 rawKeyChar = 0; 951 uint8 byte = 0; 952 int32 key = 0; 953 954 if (message->FindInt32("modifiers", (int32*)&modifiers) != B_OK 955 || message->FindInt32("raw_char", (int32*)&rawKeyChar) != B_OK 956 || message->FindInt8("byte", (int8*)&byte) != B_OK 957 || message->FindInt32("key", &key) != B_OK) { 958 return B_DISPATCH_MESSAGE; 959 } 960 961 modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY 962 | B_OPTION_KEY | B_MENU_KEY; 963 // strip caps lock, etc. 964 965 if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) { 966 fTarget->Looper()->PostMessage(fShortcutWhat, fTarget); 967 return B_SKIP_MESSAGE; 968 } 969 } 970 971 // let others deal with this 972 return B_DISPATCH_MESSAGE; 973 } 974 975 976 // #pragma mark - BPrivate functions 977 978 979 namespace BPrivate { 980 981 void 982 EmbedUniqueVolumeInfo(BMessage* message, const BVolume* volume) 983 { 984 BDirectory rootDirectory; 985 time_t created; 986 fs_info info; 987 988 if (volume->GetRootDirectory(&rootDirectory) == B_OK 989 && rootDirectory.GetCreationTime(&created) == B_OK 990 && fs_stat_dev(volume->Device(), &info) == 0) { 991 message->AddInt32("creationDate", created); 992 message->AddInt64("capacity", volume->Capacity()); 993 message->AddString("deviceName", info.device_name); 994 message->AddString("volumeName", info.volume_name); 995 message->AddString("fshName", info.fsh_name); 996 } 997 } 998 999 1000 status_t 1001 MatchArchivedVolume(BVolume* volume, const BMessage* message, int32 index) 1002 { 1003 time_t created; 1004 off_t capacity; 1005 1006 if (message->FindInt32("creationDate", index, &created) != B_OK 1007 || message->FindInt64("capacity", index, &capacity) != B_OK) { 1008 return B_ERROR; 1009 } 1010 1011 BVolumeRoster roster; 1012 BVolume tempVolume; 1013 BString deviceName; 1014 BString volumeName; 1015 BString fshName; 1016 1017 if (message->FindString("deviceName", &deviceName) == B_OK 1018 && message->FindString("volumeName", &volumeName) == B_OK 1019 && message->FindString("fshName", &fshName) == B_OK) { 1020 // New style volume identifiers: We have a couple of characteristics, 1021 // and compute a score from them. The volume with the greatest score 1022 // (if over a certain threshold) is the one we're looking for. We 1023 // pick the first volume, in case there is more than one with the 1024 // same score. 1025 dev_t foundDevice = -1; 1026 int foundScore = -1; 1027 roster.Rewind(); 1028 while (roster.GetNextVolume(&tempVolume) == B_OK) { 1029 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) { 1030 // get creation time and fs_info 1031 BDirectory root; 1032 tempVolume.GetRootDirectory(&root); 1033 time_t cmpCreated; 1034 fs_info info; 1035 if (root.GetCreationTime(&cmpCreated) == B_OK 1036 && fs_stat_dev(tempVolume.Device(), &info) == 0) { 1037 // compute the score 1038 int score = 0; 1039 1040 // creation time 1041 if (created == cmpCreated) 1042 score += 5; 1043 1044 // capacity 1045 if (capacity == tempVolume.Capacity()) 1046 score += 4; 1047 1048 // device name 1049 if (deviceName == info.device_name) 1050 score += 3; 1051 1052 // volume name 1053 if (volumeName == info.volume_name) 1054 score += 2; 1055 1056 // fsh name 1057 if (fshName == info.fsh_name) 1058 score += 1; 1059 1060 // check score 1061 if (score >= 9 && score > foundScore) { 1062 foundDevice = tempVolume.Device(); 1063 foundScore = score; 1064 } 1065 } 1066 } 1067 } 1068 if (foundDevice >= 0) 1069 return volume->SetTo(foundDevice); 1070 } else { 1071 // Old style volume identifiers: We have only creation time and 1072 // capacity. Both must match. 1073 roster.Rewind(); 1074 while (roster.GetNextVolume(&tempVolume) == B_OK) { 1075 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) { 1076 BDirectory root; 1077 tempVolume.GetRootDirectory(&root); 1078 time_t cmpCreated; 1079 root.GetCreationTime(&cmpCreated); 1080 if (created == cmpCreated && capacity == tempVolume.Capacity()) { 1081 *volume = tempVolume; 1082 return B_OK; 1083 } 1084 } 1085 } 1086 } 1087 1088 return B_DEV_BAD_DRIVE_NUM; 1089 } 1090 1091 1092 void 1093 StringFromStream(BString* string, BMallocIO* stream, bool endianSwap) 1094 { 1095 int32 length; 1096 stream->Read(&length, sizeof(length)); 1097 if (endianSwap) 1098 length = SwapInt32(length); 1099 1100 if (length < 0 || length > 10000) { 1101 // TODO: should fail here 1102 PRINT(("problems instatiating a string, length probably wrong %" 1103 B_PRId32 "\n", length)); 1104 return; 1105 } 1106 1107 char* buffer = string->LockBuffer(length + 1); 1108 stream->Read(buffer, (size_t)length + 1); 1109 string->UnlockBuffer(length); 1110 } 1111 1112 1113 void 1114 StringToStream(const BString* string, BMallocIO* stream) 1115 { 1116 int32 length = string->Length(); 1117 stream->Write(&length, sizeof(int32)); 1118 stream->Write(string->String(), (size_t)string->Length() + 1); 1119 } 1120 1121 1122 int32 1123 ArchiveSize(const BString* string) 1124 { 1125 return string->Length() + 1 + (ssize_t)sizeof(int32); 1126 } 1127 1128 1129 int32 1130 CountRefs(const BMessage* message) 1131 { 1132 uint32 type; 1133 int32 count; 1134 message->GetInfo("refs", &type, &count); 1135 1136 return count; 1137 } 1138 1139 1140 static entry_ref* 1141 EachEntryRefCommon(BMessage* message, entry_ref *(*func)(entry_ref*, void*), 1142 void* passThru, int32 maxCount) 1143 { 1144 uint32 type; 1145 int32 count; 1146 message->GetInfo("refs", &type, &count); 1147 1148 if (maxCount >= 0 && count > maxCount) 1149 count = maxCount; 1150 1151 for (int32 index = 0; index < count; index++) { 1152 entry_ref ref; 1153 message->FindRef("refs", index, &ref); 1154 entry_ref* newRef = (func)(&ref, passThru); 1155 if (newRef != NULL) 1156 return newRef; 1157 } 1158 1159 return NULL; 1160 } 1161 1162 1163 bool 1164 ContainsEntryRef(const BMessage* message, const entry_ref* ref) 1165 { 1166 entry_ref match; 1167 for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK); 1168 index++) { 1169 if (*ref == match) 1170 return true; 1171 } 1172 1173 return false; 1174 } 1175 1176 1177 entry_ref* 1178 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*), 1179 void* passThru) 1180 { 1181 return EachEntryRefCommon(message, func, passThru, -1); 1182 } 1183 1184 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *); 1185 1186 1187 const entry_ref* 1188 EachEntryRef(const BMessage* message, 1189 const entry_ref* (*func)(const entry_ref*, void*), void* passThru) 1190 { 1191 return EachEntryRefCommon(const_cast<BMessage*>(message), 1192 (EachEntryIteratee)func, passThru, -1); 1193 } 1194 1195 1196 entry_ref* 1197 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*), 1198 void* passThru, int32 maxCount) 1199 { 1200 return EachEntryRefCommon(message, func, passThru, maxCount); 1201 } 1202 1203 1204 const entry_ref * 1205 EachEntryRef(const BMessage* message, 1206 const entry_ref *(*func)(const entry_ref *, void *), void* passThru, 1207 int32 maxCount) 1208 { 1209 return EachEntryRefCommon(const_cast<BMessage *>(message), 1210 (EachEntryIteratee)func, passThru, maxCount); 1211 } 1212 1213 1214 void 1215 TruncateLeaf(BString* string) 1216 { 1217 for (int32 index = string->Length(); index >= 0; index--) { 1218 if ((*string)[index] == '/') { 1219 string->Truncate(index + 1); 1220 return; 1221 } 1222 } 1223 } 1224 1225 1226 int64 1227 StringToScalar(const char* text) 1228 { 1229 char* end; 1230 int64 val; 1231 1232 char* buffer = new char [strlen(text) + 1]; 1233 strcpy(buffer, text); 1234 1235 if (strstr(buffer, "k") || strstr(buffer, "K")) { 1236 val = strtoll(buffer, &end, 10); 1237 val *= kKBSize; 1238 } else if (strstr(buffer, "mb") || strstr(buffer, "MB")) { 1239 val = strtoll(buffer, &end, 10); 1240 val *= kMBSize; 1241 } else if (strstr(buffer, "gb") || strstr(buffer, "GB")) { 1242 val = strtoll(buffer, &end, 10); 1243 val *= kGBSize; 1244 } else if (strstr(buffer, "byte") || strstr(buffer, "BYTE")) { 1245 val = strtoll(buffer, &end, 10); 1246 val *= kGBSize; 1247 } else { 1248 // no suffix, try plain byte conversion 1249 val = strtoll(buffer, &end, 10); 1250 } 1251 delete[] buffer; 1252 1253 return val; 1254 } 1255 1256 1257 static BRect 1258 LineBounds(BPoint where, float length, bool vertical) 1259 { 1260 BRect rect; 1261 rect.SetLeftTop(where); 1262 rect.SetRightBottom(where + BPoint(2, 2)); 1263 if (vertical) 1264 rect.bottom = rect.top + length; 1265 else 1266 rect.right = rect.left + length; 1267 1268 return rect; 1269 } 1270 1271 1272 SeparatorLine::SeparatorLine(BPoint where, float length, bool vertical, 1273 const char* name) 1274 : 1275 BView(LineBounds(where, length, vertical), name, 1276 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW) 1277 { 1278 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 1279 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 1280 } 1281 1282 1283 void 1284 SeparatorLine::Draw(BRect) 1285 { 1286 BRect bounds(Bounds()); 1287 rgb_color hiliteColor = tint_color(ViewColor(), 1.5f); 1288 1289 bool vertical = (bounds.left > bounds.right - 3); 1290 BeginLineArray(2); 1291 if (vertical) { 1292 AddLine(bounds.LeftTop(), bounds.LeftBottom(), hiliteColor); 1293 AddLine(bounds.LeftTop() + BPoint(1, 0), 1294 bounds.LeftBottom() + BPoint(1, 0), kWhite); 1295 } else { 1296 AddLine(bounds.LeftTop(), bounds.RightTop(), hiliteColor); 1297 AddLine(bounds.LeftTop() + BPoint(0, 1), 1298 bounds.RightTop() + BPoint(0, 1), kWhite); 1299 } 1300 EndLineArray(); 1301 } 1302 1303 1304 void 1305 HexDump(const void* buf, int32 length) 1306 { 1307 const int32 kBytesPerLine = 16; 1308 int32 offset; 1309 unsigned char* buffer = (unsigned char*)buf; 1310 1311 for (offset = 0; ; offset += kBytesPerLine, buffer += kBytesPerLine) { 1312 int32 remain = length; 1313 int32 index; 1314 1315 printf( "0x%06x: ", (int)offset); 1316 1317 for (index = 0; index < kBytesPerLine; index++) { 1318 if (remain-- > 0) 1319 printf("%02x%c", buffer[index], remain > 0 ? ',' : ' '); 1320 else 1321 printf(" "); 1322 } 1323 1324 remain = length; 1325 printf(" \'"); 1326 for (index = 0; index < kBytesPerLine; index++) { 1327 if (remain-- > 0) 1328 printf("%c", buffer[index] > ' ' ? buffer[index] : '.'); 1329 else 1330 printf(" "); 1331 } 1332 printf("\'\n"); 1333 1334 length -= kBytesPerLine; 1335 if (length <= 0) 1336 break; 1337 } 1338 fflush(stdout); 1339 } 1340 1341 1342 void 1343 EnableNamedMenuItem(BMenu* menu, const char* itemName, bool on) 1344 { 1345 BMenuItem* item = menu->FindItem(itemName); 1346 if (item != NULL) 1347 item->SetEnabled(on); 1348 } 1349 1350 1351 void 1352 MarkNamedMenuItem(BMenu* menu, const char* itemName, bool on) 1353 { 1354 BMenuItem* item = menu->FindItem(itemName); 1355 if (item != NULL) 1356 item->SetMarked(on); 1357 } 1358 1359 1360 void 1361 EnableNamedMenuItem(BMenu* menu, uint32 commandName, bool on) 1362 { 1363 BMenuItem* item = menu->FindItem(commandName); 1364 if (item != NULL) 1365 item->SetEnabled(on); 1366 } 1367 1368 1369 void 1370 MarkNamedMenuItem(BMenu* menu, uint32 commandName, bool on) 1371 { 1372 BMenuItem* item = menu->FindItem(commandName); 1373 if (item != NULL) 1374 item->SetMarked(on); 1375 } 1376 1377 1378 void 1379 DeleteSubmenu(BMenuItem* submenuItem) 1380 { 1381 if (submenuItem == NULL) 1382 return; 1383 1384 BMenu* menu = submenuItem->Submenu(); 1385 if (menu == NULL) 1386 return; 1387 1388 for (;;) { 1389 BMenuItem* item = menu->RemoveItem((int32)0); 1390 if (item == NULL) 1391 return; 1392 1393 delete item; 1394 } 1395 } 1396 1397 1398 status_t 1399 GetAppSignatureFromAttr(BFile* file, char* attr) 1400 { 1401 // This call is a performance improvement that 1402 // avoids using the BAppFileInfo API when retrieving the 1403 // app signature -- the call is expensive because by default 1404 // the resource fork is scanned to read the attribute 1405 1406 #ifdef B_APP_FILE_INFO_IS_FAST 1407 BAppFileInfo appFileInfo(file); 1408 return appFileInfo.GetSignature(attr); 1409 #else 1410 ssize_t readResult = file->ReadAttr(kAttrAppSignature, B_MIME_STRING_TYPE, 1411 0, attr, B_MIME_TYPE_LENGTH); 1412 1413 if (readResult <= 0) 1414 return (status_t)readResult; 1415 1416 return B_OK; 1417 #endif // B_APP_FILE_INFO_IS_FAST 1418 } 1419 1420 1421 status_t 1422 GetAppIconFromAttr(BFile* file, BBitmap* icon, icon_size which) 1423 { 1424 // This call is a performance improvement that 1425 // avoids using the BAppFileInfo API when retrieving the 1426 // app icons -- the call is expensive because by default 1427 // the resource fork is scanned to read the icons 1428 1429 //#ifdef B_APP_FILE_INFO_IS_FAST 1430 BAppFileInfo appFileInfo(file); 1431 return appFileInfo.GetIcon(icon, which); 1432 //#else 1433 // 1434 // const char* attrName = kAttrIcon; 1435 // uint32 type = B_VECTOR_ICON_TYPE; 1436 // 1437 // // try vector icon 1438 // attr_info ainfo; 1439 // status_t result = file->GetAttrInfo(attrName, &ainfo); 1440 // 1441 // if (result == B_OK) { 1442 // uint8 buffer[ainfo.size]; 1443 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, 1444 // ainfo.size); 1445 // if (readResult == ainfo.size) { 1446 // if (BIconUtils::GetVectorIcon(buffer, ainfo.size, icon) == B_OK) 1447 // return B_OK; 1448 // } 1449 // } 1450 // 1451 // // try again with R5 icons 1452 // attrName = which == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon; 1453 // type = which == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE; 1454 // 1455 // result = file->GetAttrInfo(attrName, &ainfo); 1456 // if (result < B_OK) 1457 // return result; 1458 // 1459 // uint8 buffer[ainfo.size]; 1460 // 1461 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size); 1462 // if (readResult <= 0) 1463 // return (status_t)readResult; 1464 // 1465 // if (icon->ColorSpace() != B_CMAP8) 1466 // result = BIconUtils::ConvertFromCMAP8(buffer, which, which, which, icon); 1467 // else 1468 // icon->SetBits(buffer, icon->BitsLength(), 0, B_CMAP8); 1469 // 1470 // return result; 1471 //#endif // B_APP_FILE_INFO_IS_FAST 1472 } 1473 1474 1475 status_t 1476 GetFileIconFromAttr(BNode* node, BBitmap* icon, icon_size which) 1477 { 1478 BNodeInfo fileInfo(node); 1479 return fileInfo.GetIcon(icon, which); 1480 } 1481 1482 1483 void 1484 PrintToStream(rgb_color color) 1485 { 1486 printf("r:%x, g:%x, b:%x, a:%x\n", 1487 color.red, color.green, color.blue, color.alpha); 1488 } 1489 1490 1491 extern BMenuItem* 1492 EachMenuItem(BMenu* menu, bool recursive, BMenuItem* (*func)(BMenuItem *)) 1493 { 1494 int32 count = menu->CountItems(); 1495 for (int32 index = 0; index < count; index++) { 1496 BMenuItem* item = menu->ItemAt(index); 1497 BMenuItem* newItem = (func)(item); 1498 if (newItem != NULL) 1499 return newItem; 1500 1501 if (recursive) { 1502 BMenu* submenu = menu->SubmenuAt(index); 1503 if (submenu != NULL) 1504 return EachMenuItem(submenu, true, func); 1505 } 1506 } 1507 1508 return NULL; 1509 } 1510 1511 1512 extern const BMenuItem* 1513 EachMenuItem(const BMenu* menu, bool recursive, 1514 BMenuItem* (*func)(const BMenuItem *)) 1515 { 1516 int32 count = menu->CountItems(); 1517 for (int32 index = 0; index < count; index++) { 1518 BMenuItem* item = menu->ItemAt(index); 1519 BMenuItem* newItem = (func)(item); 1520 if (newItem != NULL) 1521 return newItem; 1522 1523 if (recursive) { 1524 BMenu* submenu = menu->SubmenuAt(index); 1525 if (submenu != NULL) 1526 return EachMenuItem(submenu, true, func); 1527 } 1528 } 1529 1530 return NULL; 1531 } 1532 1533 1534 // #pragma mark - PositionPassingMenuItem 1535 1536 1537 PositionPassingMenuItem::PositionPassingMenuItem(const char* title, 1538 BMessage* message, char shortcut, uint32 modifiers) 1539 : 1540 BMenuItem(title, message, shortcut, modifiers) 1541 { 1542 } 1543 1544 1545 PositionPassingMenuItem::PositionPassingMenuItem(BMenu* menu, BMessage* message) 1546 : 1547 BMenuItem(menu, message) 1548 { 1549 } 1550 1551 1552 status_t 1553 PositionPassingMenuItem::Invoke(BMessage* message) 1554 { 1555 if (Menu() == NULL) 1556 return B_ERROR; 1557 1558 if (!IsEnabled()) 1559 return B_ERROR; 1560 1561 if (message == NULL) 1562 message = Message(); 1563 1564 if (message == NULL) 1565 return B_BAD_VALUE; 1566 1567 BMessage clone(*message); 1568 clone.AddInt32("index", Menu()->IndexOf(this)); 1569 clone.AddInt64("when", system_time()); 1570 clone.AddPointer("source", this); 1571 1572 // embed the invoke location of the menu so that we can create 1573 // a new folder, etc. on the spot 1574 BMenu* menu = Menu(); 1575 1576 for (;;) { 1577 if (!menu->Supermenu()) 1578 break; 1579 1580 menu = menu->Supermenu(); 1581 } 1582 1583 // use the window position only, if the item was invoked from the menu 1584 // menu->Window() points to the window the item was invoked from 1585 if (dynamic_cast<BContainerWindow*>(menu->Window()) == NULL) { 1586 LooperAutoLocker lock(menu); 1587 if (lock.IsLocked()) { 1588 BPoint invokeOrigin(menu->Window()->Frame().LeftTop()); 1589 clone.AddPoint("be:invoke_origin", invokeOrigin); 1590 } 1591 } 1592 1593 return BInvoker::Invoke(&clone); 1594 } 1595 1596 1597 // #pragma mark - BPrivate functions 1598 1599 1600 bool 1601 BootedInSafeMode() 1602 { 1603 const char* safeMode = getenv("SAFEMODE"); 1604 return (safeMode && strcmp(safeMode, "yes") == 0); 1605 } 1606 1607 1608 float 1609 ComputeTypeAheadScore(const char* text, const char* match, bool wordMode) 1610 { 1611 // highest score: exact match 1612 const char* found = strcasestr(text, match); 1613 if (found != NULL) { 1614 if (found == text) 1615 return kExactMatchScore; 1616 1617 return 1.f / (found - text); 1618 } 1619 1620 // there was no exact match 1621 1622 // second best: all characters at word beginnings 1623 if (wordMode) { 1624 float score = 0; 1625 for (int32 j = 0, k = 0; match[j]; j++) { 1626 while (text[k] 1627 && tolower(text[k]) != tolower(match[j])) { 1628 k++; 1629 } 1630 if (text[k] == '\0') { 1631 score = 0; 1632 break; 1633 } 1634 1635 bool wordStart = k == 0 || isspace(text[k - 1]); 1636 if (wordStart) 1637 score++; 1638 if (j > 0) { 1639 bool wordEnd = !text[k + 1] || isspace(text[k + 1]); 1640 if (wordEnd) 1641 score += 0.3; 1642 if (match[j - 1] == text[k - 1]) 1643 score += 0.7; 1644 } 1645 1646 score += 1.f / (k + 1); 1647 k++; 1648 } 1649 1650 return score; 1651 } 1652 1653 return -1; 1654 } 1655 1656 1657 // #pragma mark - throw on error functions. 1658 1659 1660 void 1661 _ThrowOnError(status_t result, const char* DEBUG_ONLY(file), 1662 int32 DEBUG_ONLY(line)) 1663 { 1664 if (result != B_OK) { 1665 PRINT(("%s at %s:%d\n", strerror(result), file, (int)line)); 1666 throw result; 1667 } 1668 } 1669 1670 1671 void 1672 _ThrowIfNotSize(ssize_t size, const char* DEBUG_ONLY(file), 1673 int32 DEBUG_ONLY(line)) 1674 { 1675 if (size < B_OK) { 1676 PRINT(("%s at %s:%d\n", strerror((status_t)size), file, (int)line)); 1677 throw (status_t)size; 1678 } 1679 } 1680 1681 1682 void 1683 _ThrowOnAssert(bool success, const char* DEBUG_ONLY(file), 1684 int32 DEBUG_ONLY(line)) 1685 { 1686 if (!success) { 1687 PRINT(("Assert failed at %s:%d\n", file, (int)line)); 1688 throw B_ERROR; 1689 } 1690 } 1691 1692 } // namespace BPrivate 1693