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