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 != NULL && 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* type, 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(type); 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", type, 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 AdoptParentColors(); 604 } 605 606 607 void 608 DraggableIcon::MouseDown(BPoint point) 609 { 610 if (!DragStarted(&fMessage)) 611 return; 612 613 BRect rect(Bounds()); 614 BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true); 615 dragBitmap->Lock(); 616 BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0); 617 dragBitmap->AddChild(view); 618 view->SetOrigin(0, 0); 619 BRect clipRect(view->Bounds()); 620 BRegion newClip; 621 newClip.Set(clipRect); 622 view->ConstrainClippingRegion(&newClip); 623 624 // Transparent draw magic 625 view->SetHighColor(0, 0, 0, 0); 626 view->FillRect(view->Bounds()); 627 view->SetDrawingMode(B_OP_ALPHA); 628 view->SetHighColor(0, 0, 0, 128); 629 // set the level of transparency by value 630 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 631 view->DrawBitmap(fBitmap); 632 view->Sync(); 633 dragBitmap->Unlock(); 634 DragMessage(&fMessage, dragBitmap, B_OP_ALPHA, point, fTarget.Target(0)); 635 } 636 637 638 bool 639 DraggableIcon::DragStarted(BMessage*) 640 { 641 return true; 642 } 643 644 645 void 646 DraggableIcon::Draw(BRect) 647 { 648 SetDrawingMode(B_OP_ALPHA); 649 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 650 DrawBitmap(fBitmap); 651 } 652 653 654 // #pragma mark - FlickerFreeStringView 655 656 657 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name, 658 const char* text, uint32 resizingMode, uint32 flags) 659 : 660 BStringView(bounds, name, text, resizingMode, flags), 661 fBitmap(NULL), 662 fViewColor(ViewColor()), 663 fLowColor(LowColor()), 664 fOriginalBitmap(NULL) 665 { 666 } 667 668 669 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name, 670 const char* text, BBitmap* inBitmap, uint32 resizingMode, uint32 flags) 671 : 672 BStringView(bounds, name, text, resizingMode, flags), 673 fBitmap(NULL), 674 fViewColor(ViewColor()), 675 fLowColor(LowColor()), 676 fOriginalBitmap(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 == NULL) 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 (fOriginalBitmap != NULL) 711 offscreen->DrawBitmap(fOriginalBitmap, 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 != NULL); 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 957 modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY 958 | B_OPTION_KEY | B_MENU_KEY; 959 // strip caps lock, etc. 960 961 if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) { 962 fTarget->Looper()->PostMessage(fShortcutWhat, fTarget); 963 return B_SKIP_MESSAGE; 964 } 965 } 966 967 // let others deal with this 968 return B_DISPATCH_MESSAGE; 969 } 970 971 972 // #pragma mark - BPrivate functions 973 974 975 namespace BPrivate { 976 977 void 978 EmbedUniqueVolumeInfo(BMessage* message, const BVolume* volume) 979 { 980 BDirectory rootDirectory; 981 time_t created; 982 fs_info info; 983 984 if (volume->GetRootDirectory(&rootDirectory) == B_OK 985 && rootDirectory.GetCreationTime(&created) == B_OK 986 && fs_stat_dev(volume->Device(), &info) == 0) { 987 message->AddInt64("creationDate", created); 988 message->AddInt64("capacity", volume->Capacity()); 989 message->AddString("deviceName", info.device_name); 990 message->AddString("volumeName", info.volume_name); 991 message->AddString("fshName", info.fsh_name); 992 } 993 } 994 995 996 status_t 997 MatchArchivedVolume(BVolume* volume, const BMessage* message, int32 index) 998 { 999 int64 created64; 1000 off_t capacity; 1001 1002 if (message->FindInt64("creationDate", index, &created64) != B_OK) { 1003 int32 created32; 1004 if (message->FindInt32("creationDate", index, &created32) != B_OK) 1005 return B_ERROR; 1006 created64 = created32; 1007 } 1008 1009 time_t created = created64; 1010 1011 if (message->FindInt64("capacity", index, &capacity) != B_OK) 1012 return B_ERROR; 1013 1014 BVolumeRoster roster; 1015 BVolume tempVolume; 1016 BString deviceName; 1017 BString volumeName; 1018 BString fshName; 1019 1020 if (message->FindString("deviceName", &deviceName) == B_OK 1021 && message->FindString("volumeName", &volumeName) == B_OK 1022 && message->FindString("fshName", &fshName) == B_OK) { 1023 // New style volume identifiers: We have a couple of characteristics, 1024 // and compute a score from them. The volume with the greatest score 1025 // (if over a certain threshold) is the one we're looking for. We 1026 // pick the first volume, in case there is more than one with the 1027 // same score. 1028 dev_t foundDevice = -1; 1029 int foundScore = -1; 1030 roster.Rewind(); 1031 while (roster.GetNextVolume(&tempVolume) == B_OK) { 1032 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) { 1033 // get creation time and fs_info 1034 BDirectory root; 1035 tempVolume.GetRootDirectory(&root); 1036 time_t cmpCreated; 1037 fs_info info; 1038 if (root.GetCreationTime(&cmpCreated) == B_OK 1039 && fs_stat_dev(tempVolume.Device(), &info) == 0) { 1040 // compute the score 1041 int score = 0; 1042 1043 // creation time 1044 if (created == cmpCreated) 1045 score += 5; 1046 1047 // capacity 1048 if (capacity == tempVolume.Capacity()) 1049 score += 4; 1050 1051 // device name 1052 if (deviceName == info.device_name) 1053 score += 3; 1054 1055 // volume name 1056 if (volumeName == info.volume_name) 1057 score += 2; 1058 1059 // fsh name 1060 if (fshName == info.fsh_name) 1061 score += 1; 1062 1063 // check score 1064 if (score >= 9 && score > foundScore) { 1065 foundDevice = tempVolume.Device(); 1066 foundScore = score; 1067 } 1068 } 1069 } 1070 } 1071 if (foundDevice >= 0) 1072 return volume->SetTo(foundDevice); 1073 } else { 1074 // Old style volume identifiers: We have only creation time and 1075 // capacity. Both must match. 1076 roster.Rewind(); 1077 while (roster.GetNextVolume(&tempVolume) == B_OK) { 1078 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) { 1079 BDirectory root; 1080 tempVolume.GetRootDirectory(&root); 1081 time_t cmpCreated; 1082 root.GetCreationTime(&cmpCreated); 1083 if (created == cmpCreated && capacity == tempVolume.Capacity()) { 1084 *volume = tempVolume; 1085 return B_OK; 1086 } 1087 } 1088 } 1089 } 1090 1091 return B_DEV_BAD_DRIVE_NUM; 1092 } 1093 1094 1095 void 1096 StringFromStream(BString* string, BMallocIO* stream, bool endianSwap) 1097 { 1098 int32 length; 1099 stream->Read(&length, sizeof(length)); 1100 if (endianSwap) 1101 length = SwapInt32(length); 1102 1103 if (length < 0 || length > 10000) { 1104 // TODO: should fail here 1105 PRINT(("problems instatiating a string, length probably wrong %" 1106 B_PRId32 "\n", length)); 1107 return; 1108 } 1109 1110 char* buffer = string->LockBuffer(length + 1); 1111 stream->Read(buffer, (size_t)length + 1); 1112 string->UnlockBuffer(length); 1113 } 1114 1115 1116 void 1117 StringToStream(const BString* string, BMallocIO* stream) 1118 { 1119 int32 length = string->Length(); 1120 stream->Write(&length, sizeof(int32)); 1121 stream->Write(string->String(), (size_t)string->Length() + 1); 1122 } 1123 1124 1125 int32 1126 ArchiveSize(const BString* string) 1127 { 1128 return string->Length() + 1 + (ssize_t)sizeof(int32); 1129 } 1130 1131 1132 int32 1133 CountRefs(const BMessage* message) 1134 { 1135 uint32 type; 1136 int32 count; 1137 message->GetInfo("refs", &type, &count); 1138 1139 return count; 1140 } 1141 1142 1143 static entry_ref* 1144 EachEntryRefCommon(BMessage* message, entry_ref *(*func)(entry_ref*, void*), 1145 void* passThru, int32 maxCount) 1146 { 1147 uint32 type; 1148 int32 count; 1149 message->GetInfo("refs", &type, &count); 1150 1151 if (maxCount >= 0 && count > maxCount) 1152 count = maxCount; 1153 1154 for (int32 index = 0; index < count; index++) { 1155 entry_ref ref; 1156 message->FindRef("refs", index, &ref); 1157 entry_ref* newRef = (func)(&ref, passThru); 1158 if (newRef != NULL) 1159 return newRef; 1160 } 1161 1162 return NULL; 1163 } 1164 1165 1166 bool 1167 ContainsEntryRef(const BMessage* message, const entry_ref* ref) 1168 { 1169 entry_ref match; 1170 for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK); 1171 index++) { 1172 if (*ref == match) 1173 return true; 1174 } 1175 1176 return false; 1177 } 1178 1179 1180 entry_ref* 1181 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*), 1182 void* passThru) 1183 { 1184 return EachEntryRefCommon(message, func, passThru, -1); 1185 } 1186 1187 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *); 1188 1189 1190 const entry_ref* 1191 EachEntryRef(const BMessage* message, 1192 const entry_ref* (*func)(const entry_ref*, void*), void* passThru) 1193 { 1194 return EachEntryRefCommon(const_cast<BMessage*>(message), 1195 (EachEntryIteratee)func, passThru, -1); 1196 } 1197 1198 1199 entry_ref* 1200 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*), 1201 void* passThru, int32 maxCount) 1202 { 1203 return EachEntryRefCommon(message, func, passThru, maxCount); 1204 } 1205 1206 1207 const entry_ref * 1208 EachEntryRef(const BMessage* message, 1209 const entry_ref *(*func)(const entry_ref *, void *), void* passThru, 1210 int32 maxCount) 1211 { 1212 return EachEntryRefCommon(const_cast<BMessage *>(message), 1213 (EachEntryIteratee)func, passThru, maxCount); 1214 } 1215 1216 1217 void 1218 TruncateLeaf(BString* string) 1219 { 1220 for (int32 index = string->Length(); index >= 0; index--) { 1221 if ((*string)[index] == '/') { 1222 string->Truncate(index + 1); 1223 return; 1224 } 1225 } 1226 } 1227 1228 1229 int64 1230 StringToScalar(const char* text) 1231 { 1232 char* end; 1233 int64 val; 1234 1235 char* buffer = new char [strlen(text) + 1]; 1236 strcpy(buffer, text); 1237 1238 if (strstr(buffer, "k") || strstr(buffer, "K")) { 1239 val = strtoll(buffer, &end, 10); 1240 val *= kKBSize; 1241 } else if (strstr(buffer, "mb") || strstr(buffer, "MB")) { 1242 val = strtoll(buffer, &end, 10); 1243 val *= kMBSize; 1244 } else if (strstr(buffer, "gb") || strstr(buffer, "GB")) { 1245 val = strtoll(buffer, &end, 10); 1246 val *= kGBSize; 1247 } else if (strstr(buffer, "byte") || strstr(buffer, "BYTE")) { 1248 val = strtoll(buffer, &end, 10); 1249 val *= kGBSize; 1250 } else { 1251 // no suffix, try plain byte conversion 1252 val = strtoll(buffer, &end, 10); 1253 } 1254 delete[] buffer; 1255 1256 return val; 1257 } 1258 1259 1260 int32 1261 ListIconSize() 1262 { 1263 static int32 sIconSize = std::max((int32)B_MINI_ICON, 1264 (int32)ceilf(B_MINI_ICON * be_plain_font->Size() / 12)); 1265 return sIconSize; 1266 } 1267 1268 1269 static BRect 1270 LineBounds(BPoint where, float length, bool vertical) 1271 { 1272 BRect rect; 1273 rect.SetLeftTop(where); 1274 rect.SetRightBottom(where + BPoint(2, 2)); 1275 if (vertical) 1276 rect.bottom = rect.top + length; 1277 else 1278 rect.right = rect.left + length; 1279 1280 return rect; 1281 } 1282 1283 1284 SeparatorLine::SeparatorLine(BPoint where, float length, bool vertical, 1285 const char* name) 1286 : 1287 BView(LineBounds(where, length, vertical), name, 1288 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW) 1289 { 1290 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 1291 SetLowUIColor(B_PANEL_BACKGROUND_COLOR); 1292 } 1293 1294 1295 void 1296 SeparatorLine::Draw(BRect) 1297 { 1298 BRect bounds(Bounds()); 1299 rgb_color hiliteColor = tint_color(ViewColor(), 1.5f); 1300 1301 bool vertical = (bounds.left > bounds.right - 3); 1302 BeginLineArray(2); 1303 if (vertical) { 1304 AddLine(bounds.LeftTop(), bounds.LeftBottom(), hiliteColor); 1305 AddLine(bounds.LeftTop() + BPoint(1, 0), 1306 bounds.LeftBottom() + BPoint(1, 0), kWhite); 1307 } else { 1308 AddLine(bounds.LeftTop(), bounds.RightTop(), hiliteColor); 1309 AddLine(bounds.LeftTop() + BPoint(0, 1), 1310 bounds.RightTop() + BPoint(0, 1), kWhite); 1311 } 1312 EndLineArray(); 1313 } 1314 1315 1316 void 1317 HexDump(const void* buf, int32 length) 1318 { 1319 const int32 kBytesPerLine = 16; 1320 int32 offset; 1321 unsigned char* buffer = (unsigned char*)buf; 1322 1323 for (offset = 0; ; offset += kBytesPerLine, buffer += kBytesPerLine) { 1324 int32 remain = length; 1325 int32 index; 1326 1327 printf( "0x%06x: ", (int)offset); 1328 1329 for (index = 0; index < kBytesPerLine; index++) { 1330 if (remain-- > 0) 1331 printf("%02x%c", buffer[index], remain > 0 ? ',' : ' '); 1332 else 1333 printf(" "); 1334 } 1335 1336 remain = length; 1337 printf(" \'"); 1338 for (index = 0; index < kBytesPerLine; index++) { 1339 if (remain-- > 0) 1340 printf("%c", buffer[index] > ' ' ? buffer[index] : '.'); 1341 else 1342 printf(" "); 1343 } 1344 printf("\'\n"); 1345 1346 length -= kBytesPerLine; 1347 if (length <= 0) 1348 break; 1349 } 1350 fflush(stdout); 1351 } 1352 1353 1354 void 1355 EnableNamedMenuItem(BMenu* menu, const char* itemName, bool on) 1356 { 1357 BMenuItem* item = menu->FindItem(itemName); 1358 if (item != NULL) 1359 item->SetEnabled(on); 1360 } 1361 1362 1363 void 1364 MarkNamedMenuItem(BMenu* menu, const char* itemName, bool on) 1365 { 1366 BMenuItem* item = menu->FindItem(itemName); 1367 if (item != NULL) 1368 item->SetMarked(on); 1369 } 1370 1371 1372 void 1373 EnableNamedMenuItem(BMenu* menu, uint32 commandName, bool on) 1374 { 1375 BMenuItem* item = menu->FindItem(commandName); 1376 if (item != NULL) 1377 item->SetEnabled(on); 1378 } 1379 1380 1381 void 1382 MarkNamedMenuItem(BMenu* menu, uint32 commandName, bool on) 1383 { 1384 BMenuItem* item = menu->FindItem(commandName); 1385 if (item != NULL) 1386 item->SetMarked(on); 1387 } 1388 1389 1390 void 1391 DeleteSubmenu(BMenuItem* submenuItem) 1392 { 1393 if (submenuItem == NULL) 1394 return; 1395 1396 BMenu* menu = submenuItem->Submenu(); 1397 if (menu == NULL) 1398 return; 1399 1400 for (;;) { 1401 BMenuItem* item = menu->RemoveItem((int32)0); 1402 if (item == NULL) 1403 return; 1404 1405 delete item; 1406 } 1407 } 1408 1409 1410 status_t 1411 GetAppSignatureFromAttr(BFile* file, char* attr) 1412 { 1413 // This call is a performance improvement that 1414 // avoids using the BAppFileInfo API when retrieving the 1415 // app signature -- the call is expensive because by default 1416 // the resource fork is scanned to read the attribute 1417 1418 #ifdef B_APP_FILE_INFO_IS_FAST 1419 BAppFileInfo appFileInfo(file); 1420 return appFileInfo.GetSignature(attr); 1421 #else 1422 ssize_t readResult = file->ReadAttr(kAttrAppSignature, B_MIME_STRING_TYPE, 1423 0, attr, B_MIME_TYPE_LENGTH); 1424 1425 if (readResult <= 0) 1426 return (status_t)readResult; 1427 1428 return B_OK; 1429 #endif // B_APP_FILE_INFO_IS_FAST 1430 } 1431 1432 1433 status_t 1434 GetAppIconFromAttr(BFile* file, BBitmap* icon, icon_size which) 1435 { 1436 // This call is a performance improvement that 1437 // avoids using the BAppFileInfo API when retrieving the 1438 // app icons -- the call is expensive because by default 1439 // the resource fork is scanned to read the icons 1440 1441 //#ifdef B_APP_FILE_INFO_IS_FAST 1442 BAppFileInfo appFileInfo(file); 1443 return appFileInfo.GetIcon(icon, which); 1444 //#else 1445 // 1446 // const char* attrName = kAttrIcon; 1447 // uint32 type = B_VECTOR_ICON_TYPE; 1448 // 1449 // // try vector icon 1450 // attr_info ainfo; 1451 // status_t result = file->GetAttrInfo(attrName, &ainfo); 1452 // 1453 // if (result == B_OK) { 1454 // uint8 buffer[ainfo.size]; 1455 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, 1456 // ainfo.size); 1457 // if (readResult == ainfo.size) { 1458 // if (BIconUtils::GetVectorIcon(buffer, ainfo.size, icon) == B_OK) 1459 // return B_OK; 1460 // } 1461 // } 1462 // 1463 // // try again with R5 icons 1464 // attrName = which == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon; 1465 // type = which == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE; 1466 // 1467 // result = file->GetAttrInfo(attrName, &ainfo); 1468 // if (result < B_OK) 1469 // return result; 1470 // 1471 // uint8 buffer[ainfo.size]; 1472 // 1473 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size); 1474 // if (readResult <= 0) 1475 // return (status_t)readResult; 1476 // 1477 // if (icon->ColorSpace() != B_CMAP8) 1478 // result = BIconUtils::ConvertFromCMAP8(buffer, which, which, which, icon); 1479 // else 1480 // icon->SetBits(buffer, icon->BitsLength(), 0, B_CMAP8); 1481 // 1482 // return result; 1483 //#endif // B_APP_FILE_INFO_IS_FAST 1484 } 1485 1486 1487 status_t 1488 GetFileIconFromAttr(BNode* node, BBitmap* icon, icon_size which) 1489 { 1490 // get icon from the node info 1491 BNodeInfo nodeInfo(node); 1492 return nodeInfo.GetIcon(icon, which); 1493 } 1494 1495 1496 // #pragma mark - PrintToStream 1497 1498 1499 void 1500 PrintToStream(rgb_color color) 1501 { 1502 printf("r:%x, g:%x, b:%x, a:%x\n", 1503 color.red, color.green, color.blue, color.alpha); 1504 } 1505 1506 1507 // #pragma mark - EachMenuItem 1508 1509 1510 extern BMenuItem* 1511 EachMenuItem(BMenu* menu, bool recursive, BMenuItem* (*func)(BMenuItem *)) 1512 { 1513 int32 count = menu->CountItems(); 1514 for (int32 index = 0; index < count; index++) { 1515 BMenuItem* item = menu->ItemAt(index); 1516 BMenuItem* newItem = (func)(item); 1517 if (newItem != NULL) 1518 return newItem; 1519 1520 if (recursive) { 1521 BMenu* submenu = menu->SubmenuAt(index); 1522 if (submenu != NULL) 1523 return EachMenuItem(submenu, true, func); 1524 } 1525 } 1526 1527 return NULL; 1528 } 1529 1530 1531 extern const BMenuItem* 1532 EachMenuItem(const BMenu* menu, bool recursive, 1533 BMenuItem* (*func)(const BMenuItem *)) 1534 { 1535 int32 count = menu->CountItems(); 1536 for (int32 index = 0; index < count; index++) { 1537 BMenuItem* item = menu->ItemAt(index); 1538 BMenuItem* newItem = (func)(item); 1539 if (newItem != NULL) 1540 return newItem; 1541 1542 if (recursive) { 1543 BMenu* submenu = menu->SubmenuAt(index); 1544 if (submenu != NULL) 1545 return EachMenuItem(submenu, true, func); 1546 } 1547 } 1548 1549 return NULL; 1550 } 1551 1552 1553 // #pragma mark - PositionPassingMenuItem 1554 1555 1556 PositionPassingMenuItem::PositionPassingMenuItem(const char* title, 1557 BMessage* message, char shortcut, uint32 modifiers) 1558 : 1559 BMenuItem(title, message, shortcut, modifiers) 1560 { 1561 } 1562 1563 1564 PositionPassingMenuItem::PositionPassingMenuItem(BMenu* menu, BMessage* message) 1565 : 1566 BMenuItem(menu, message) 1567 { 1568 } 1569 1570 1571 PositionPassingMenuItem::PositionPassingMenuItem(BMessage* data) 1572 : 1573 BMenuItem(data) 1574 { 1575 } 1576 1577 1578 BArchivable* 1579 PositionPassingMenuItem::Instantiate(BMessage* data) 1580 { 1581 if (validate_instantiation(data, "PositionPassingMenuItem")) 1582 return new PositionPassingMenuItem(data); 1583 1584 return NULL; 1585 } 1586 1587 1588 status_t 1589 PositionPassingMenuItem::Invoke(BMessage* message) 1590 { 1591 if (Menu() == NULL) 1592 return B_ERROR; 1593 1594 if (!IsEnabled()) 1595 return B_ERROR; 1596 1597 if (message == NULL) 1598 message = Message(); 1599 1600 if (message == NULL) 1601 return B_BAD_VALUE; 1602 1603 BMessage clone(*message); 1604 clone.AddInt32("index", Menu()->IndexOf(this)); 1605 clone.AddInt64("when", system_time()); 1606 clone.AddPointer("source", this); 1607 1608 // embed the invoke location of the menu so that we can create 1609 // a new folder, etc. on the spot 1610 BMenu* menu = Menu(); 1611 1612 for (;;) { 1613 if (!menu->Supermenu()) 1614 break; 1615 1616 menu = menu->Supermenu(); 1617 } 1618 1619 // use the window position only, if the item was invoked from the menu 1620 // menu->Window() points to the window the item was invoked from 1621 if (dynamic_cast<BContainerWindow*>(menu->Window()) == NULL) { 1622 AutoLocker<BLooper> lock(menu->Looper()); 1623 if (lock.IsLocked()) { 1624 BPoint invokeOrigin(menu->Window()->Frame().LeftTop()); 1625 clone.AddPoint("be:invoke_origin", invokeOrigin); 1626 } 1627 } 1628 1629 return BInvoker::Invoke(&clone); 1630 } 1631 1632 1633 // #pragma mark - BPrivate functions 1634 1635 1636 bool 1637 BootedInSafeMode() 1638 { 1639 const char* safeMode = getenv("SAFEMODE"); 1640 return (safeMode && strcmp(safeMode, "yes") == 0); 1641 } 1642 1643 1644 float 1645 ComputeTypeAheadScore(const char* text, const char* match, bool wordMode) 1646 { 1647 // highest score: exact match 1648 const char* found = strcasestr(text, match); 1649 if (found != NULL) { 1650 if (found == text) 1651 return kExactMatchScore; 1652 1653 return 1.f / (found - text); 1654 } 1655 1656 // there was no exact match 1657 1658 // second best: all characters at word beginnings 1659 if (wordMode) { 1660 float score = 0; 1661 for (int32 j = 0, k = 0; match[j]; j++) { 1662 while (text[k] 1663 && tolower(text[k]) != tolower(match[j])) { 1664 k++; 1665 } 1666 if (text[k] == '\0') { 1667 score = 0; 1668 break; 1669 } 1670 1671 bool wordStart = k == 0 || isspace(text[k - 1]); 1672 if (wordStart) 1673 score++; 1674 if (j > 0) { 1675 bool wordEnd = !text[k + 1] || isspace(text[k + 1]); 1676 if (wordEnd) 1677 score += 0.3; 1678 if (match[j - 1] == text[k - 1]) 1679 score += 0.7; 1680 } 1681 1682 score += 1.f / (k + 1); 1683 k++; 1684 } 1685 1686 return score; 1687 } 1688 1689 return -1; 1690 } 1691 1692 1693 // #pragma mark - throw on error functions. 1694 1695 1696 void 1697 _ThrowOnError(status_t result, const char* DEBUG_ONLY(file), 1698 int32 DEBUG_ONLY(line)) 1699 { 1700 if (result != B_OK) { 1701 PRINT(("%s at %s:%d\n", strerror(result), file, (int)line)); 1702 throw result; 1703 } 1704 } 1705 1706 1707 void 1708 _ThrowIfNotSize(ssize_t size, const char* DEBUG_ONLY(file), 1709 int32 DEBUG_ONLY(line)) 1710 { 1711 if (size < B_OK) { 1712 PRINT(("%s at %s:%d\n", strerror((status_t)size), file, (int)line)); 1713 throw (status_t)size; 1714 } 1715 } 1716 1717 1718 void 1719 _ThrowOnAssert(bool success, const char* DEBUG_ONLY(file), 1720 int32 DEBUG_ONLY(line)) 1721 { 1722 if (!success) { 1723 PRINT(("Assert failed at %s:%d\n", file, (int)line)); 1724 throw B_ERROR; 1725 } 1726 } 1727 1728 } // namespace BPrivate 1729