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 } // 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 = be_control_look->ComposeIconSize(B_MINI_ICON) 1264 .IntegerWidth() + 1; 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