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