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