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