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