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 // Icon cache is used for drawing node icons; it caches icons 36 // and reuses them for successive draws 37 38 // 39 // Possible performance improvements: 40 // - Mime API requires BBitmaps to retrieve bits and successive 41 // SetBits that cause app server contention 42 // Consider having special purpose "give me just the bits" calls 43 // to deal with that. 44 // - Related to this, node cache entries would only store the raw bits 45 // to cut down on number of BBitmaps and related overhead 46 // - Make the cache miss and fill case for the shared cache reuse the 47 // already calculated hash value 48 // 49 // Other ToDo items: 50 // Use lazily allocated bitmap arrays for every view for node icon cache 51 // drawing 52 // Have an overflow list for deleting shared icons, delete from the list 53 // every now and then 54 55 56 // Actual icon lookup sequence: 57 // icon from node 58 // preferred app for node -> icon for type 59 // preferred app for type -> icon for type 60 // metamime -> icon for type 61 // preferred app for supertype -> icon for type 62 // supertype metamime -> icon for type 63 // generic icon 64 65 66 #include <ControlLook.h> 67 #include <Debug.h> 68 #include <Screen.h> 69 #include <Volume.h> 70 71 #include <fs_info.h> 72 73 #include "Bitmaps.h" 74 #include "FSUtils.h" 75 #include "IconCache.h" 76 #include "MimeTypes.h" 77 #include "Model.h" 78 #include "Thumbnails.h" 79 80 81 //#if DEBUG 82 //# define LOG_DISK_HITS 83 // the LOG_DISK_HITS define is used to check that the disk is not hit more 84 // than needed - enable it, open a window with a bunch of poses, force 85 // it to redraw, shouldn't recache 86 //# define LOG_ADD_ITEM 87 //#endif 88 89 // set up a few printing macros to get rid of a ton of debugging ifdefs 90 // in the code 91 #ifdef LOG_DISK_HITS 92 # define PRINT_DISK_HITS(ARGS) _debugPrintf ARGS 93 #else 94 # define PRINT_DISK_HITS(ARGS) (void)0 95 #endif 96 97 #ifdef LOG_ADD_ITEM 98 # define PRINT_ADD_ITEM(ARGS) _debugPrintf ARGS 99 #else 100 # define PRINT_ADD_ITEM(ARGS) (void)0 101 #endif 102 103 #undef NODE_CACHE_ASYNC_DRAWS 104 105 106 BSize IconCache::sMiniIconSize; 107 108 109 static inline icon_size 110 icon_size_for(BSize size) 111 { 112 ASSERT(size.Width() == size.Height()); 113 return (icon_size)(size.IntegerWidth() + 1); 114 } 115 116 117 IconCacheEntry::IconCacheEntry() 118 : 119 fLargeIcon(NULL), 120 fHighlightedLargeIcon(NULL), 121 fMiniIcon(NULL), 122 fHighlightedMiniIcon(NULL), 123 fAliasTo(NULL) 124 { 125 } 126 127 128 IconCacheEntry::~IconCacheEntry() 129 { 130 if (fAliasTo == NULL) { 131 delete fLargeIcon; 132 delete fHighlightedLargeIcon; 133 delete fMiniIcon; 134 delete fHighlightedMiniIcon; 135 136 // clean up a bit to leave the hash table entry in an initialized state 137 fLargeIcon = NULL; 138 fHighlightedLargeIcon = NULL; 139 fMiniIcon = NULL; 140 fHighlightedMiniIcon = NULL; 141 } 142 fAliasTo = NULL; 143 } 144 145 146 void 147 IconCacheEntry::SetAliasFor(const SharedIconCache* sharedCache, 148 const SharedCacheEntry* entry) 149 { 150 sharedCache->SetAliasFor(this, entry); 151 ASSERT(fAliasTo != NULL); 152 } 153 154 155 IconCacheEntry* 156 IconCacheEntry::ResolveIfAlias(const SharedIconCache* sharedCache) 157 { 158 return sharedCache->ResolveIfAlias(this); 159 } 160 161 162 IconCacheEntry* 163 IconCacheEntry::ResolveIfAlias(const SharedIconCache* sharedCache, 164 IconCacheEntry* entry) 165 { 166 if (entry == NULL) 167 return NULL; 168 169 return sharedCache->ResolveIfAlias(entry); 170 } 171 172 173 bool 174 IconCacheEntry::CanConstructBitmap(IconDrawMode mode, BSize) const 175 { 176 if (mode == kSelected) { 177 // for now only 178 return true; 179 } 180 181 return false; 182 } 183 184 185 bool 186 IconCacheEntry::HaveIconBitmap(IconDrawMode mode, BSize size) const 187 { 188 ASSERT(mode == kSelected || mode == kNormalIcon); 189 // for now only 190 191 if (mode == kNormalIcon) { 192 return size == IconCache::sMiniIconSize ? fMiniIcon != NULL 193 : fLargeIcon != NULL 194 && fLargeIcon->Bounds().Size() == size; 195 } else if (mode == kSelected) { 196 return size == IconCache::sMiniIconSize ? fHighlightedMiniIcon != NULL 197 : fHighlightedLargeIcon != NULL 198 && fHighlightedLargeIcon->Bounds().Size() == size; 199 } 200 201 return false; 202 } 203 204 205 BBitmap* 206 IconCacheEntry::IconForMode(IconDrawMode mode, BSize size) const 207 { 208 ASSERT(mode == kSelected || mode == kNormalIcon); 209 // for now only 210 211 if (mode == kNormalIcon) { 212 if (size == IconCache::sMiniIconSize) 213 return fMiniIcon; 214 else 215 return fLargeIcon; 216 } else if (mode == kSelected) { 217 if (size == IconCache::sMiniIconSize) 218 return fHighlightedMiniIcon; 219 else 220 return fHighlightedLargeIcon; 221 } 222 223 return NULL; 224 } 225 226 227 bool 228 IconCacheEntry::IconHitTest(BPoint where, IconDrawMode mode, 229 BSize size) const 230 { 231 ASSERT(where.x < size.width && where.y < size.height); 232 BBitmap* bitmap = IconForMode(mode, size); 233 if (bitmap == NULL) 234 return false; 235 236 uchar* bits = (uchar*)bitmap->Bits(); 237 ASSERT(bits != NULL); 238 239 BRect bounds(bitmap->Bounds()); 240 bounds.InsetBy((bounds.Width() + 1.0) / 8.0, (bounds.Height() + 1.0) / 8.0); 241 if (bounds.Contains(where)) 242 return true; 243 244 switch (bitmap->ColorSpace()) { 245 case B_RGBA32: 246 // test alpha channel 247 return *(bits + (int32)(floorf(where.y) * bitmap->BytesPerRow() 248 + floorf(where.x) * 4 + 3)) > 20; 249 250 case B_CMAP8: 251 return *(bits + (int32)(floorf(where.y) * icon_size_for(size) + where.x)) 252 != B_TRANSPARENT_8_BIT; 253 254 default: 255 return true; 256 } 257 } 258 259 260 BBitmap* 261 IconCacheEntry::ConstructBitmap(BBitmap* constructFrom, 262 IconDrawMode requestedMode, IconDrawMode constructFromMode, 263 BSize size, LazyBitmapAllocator* lazyBitmap) 264 { 265 ASSERT(requestedMode == kSelected && constructFromMode == kNormalIcon); 266 // for now 267 268 if (requestedMode == kSelected && constructFromMode == kNormalIcon) { 269 return IconCache::sIconCache->MakeSelectedIcon(constructFrom, size, 270 lazyBitmap); 271 } 272 273 return NULL; 274 } 275 276 277 BBitmap* 278 IconCacheEntry::ConstructBitmap(IconDrawMode requestedMode, BSize size, 279 LazyBitmapAllocator* lazyBitmap) 280 { 281 BBitmap* source = (size == IconCache::sMiniIconSize) ? fMiniIcon : fLargeIcon; 282 ASSERT(source != NULL); 283 284 return ConstructBitmap(source, requestedMode, kNormalIcon, size, 285 lazyBitmap); 286 } 287 288 289 bool 290 IconCacheEntry::AlternateModeForIconConstructing(IconDrawMode requestedMode, 291 IconDrawMode &alternate, BSize) 292 { 293 if ((requestedMode & kSelected) != 0) { 294 // for now 295 alternate = kNormalIcon; 296 return true; 297 } 298 299 return false; 300 } 301 302 303 void 304 IconCacheEntry::SetIcon(BBitmap* bitmap, IconDrawMode mode, BSize size) 305 { 306 BBitmap** icon = NULL; 307 if (mode == kNormalIcon) { 308 if (size == IconCache::sMiniIconSize) 309 icon = &fMiniIcon; 310 else 311 icon = &fLargeIcon; 312 } else if (mode == kSelectedIcon) { 313 if (size == IconCache::sMiniIconSize) 314 icon = &fHighlightedMiniIcon; 315 else 316 icon = &fHighlightedLargeIcon; 317 } 318 if (icon == NULL) 319 TRESPASS(); 320 321 if ((*icon) != NULL) 322 delete *icon; 323 *icon = bitmap; 324 } 325 326 327 IconCache::IconCache() 328 : 329 fInitHighlightTable(true) 330 { 331 InitHighlightTable(); 332 333 sMiniIconSize = be_control_look->ComposeIconSize(B_MINI_ICON); 334 } 335 336 337 // The following calls use the icon lookup sequence node-prefered app for 338 // node-metamime-preferred app for metamime to find an icon; 339 // if we are trying to get a specialized icon, we will first look for a normal 340 // icon in each of the locations, if we get a hit, we look for the 341 // specialized, if we don't find one, we try to auto-construct one, if we 342 // can't we assume the icon is not available for now the code only looks for 343 // normal icons, selected icons are auto-generated. 344 345 346 IconCacheEntry* 347 IconCache::GetIconForPreferredApp(const char* fileTypeSignature, 348 const char* preferredApp, IconDrawMode mode, BSize size, 349 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 350 { 351 ASSERT(fSharedCache.IsLocked()); 352 353 if (preferredApp == NULL || *preferredApp == '\0') 354 return NULL; 355 356 if (entry == NULL) { 357 entry = fSharedCache.FindItem(fileTypeSignature, preferredApp); 358 if (entry != NULL) { 359 entry = entry->ResolveIfAlias(&fSharedCache, entry); 360 #if xDEBUG 361 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n", 362 __FILE__, __LINE__, preferredApp, fileTypeSignature, entry)); 363 #endif 364 if (entry->HaveIconBitmap(mode, size)) 365 return entry; 366 } 367 } 368 369 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 370 PRINT_DISK_HITS( 371 ("File %s; Line %d # hitting disk for preferredApp %s, type %s\n", 372 __FILE__, __LINE__, preferredApp, fileTypeSignature)); 373 374 BMimeType preferredAppType(preferredApp); 375 BString signature(fileTypeSignature); 376 signature.ToLower(); 377 if (preferredAppType.GetIconForType(signature.String(), 378 lazyBitmap->Get(), icon_size_for(size)) != B_OK) { 379 return NULL; 380 } 381 382 BBitmap* bitmap = lazyBitmap->Adopt(); 383 if (entry == NULL) { 384 PRINT_ADD_ITEM( 385 ("File %s; Line %d # adding entry for preferredApp %s, " 386 "type %s\n", __FILE__, __LINE__, preferredApp, 387 fileTypeSignature)); 388 entry = fSharedCache.AddItem(fileTypeSignature, preferredApp); 389 } 390 entry->SetIcon(bitmap, kNormalIcon, size); 391 } 392 393 if (mode != kNormalIcon 394 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 395 entry->ConstructBitmap(mode, size, lazyBitmap); 396 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 397 } 398 399 return entry; 400 } 401 402 403 IconCacheEntry* 404 IconCache::GetIconFromMetaMime(const char* fileType, IconDrawMode mode, 405 BSize size, LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 406 { 407 ASSERT(fSharedCache.IsLocked()); 408 409 if (entry == NULL) 410 entry = fSharedCache.FindItem(fileType); 411 412 if (entry != NULL) { 413 entry = entry->ResolveIfAlias(&fSharedCache, entry); 414 // metamime defines an icon and we have it cached 415 if (entry->HaveIconBitmap(mode, size)) 416 return entry; 417 } 418 419 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 420 PRINT_DISK_HITS(("File %s; Line %d # hitting disk for metamime %s\n", 421 __FILE__, __LINE__, fileType)); 422 423 BMimeType mime(fileType); 424 // try getting the icon directly from the metamime 425 if (mime.GetIcon(lazyBitmap->Get(), icon_size_for(size)) != B_OK) { 426 // try getting it from the preferred app of this type 427 char preferredAppSig[B_MIME_TYPE_LENGTH]; 428 if (mime.GetPreferredApp(preferredAppSig) != B_OK) 429 return NULL; 430 431 SharedCacheEntry* aliasTo = NULL; 432 if (entry != NULL) { 433 aliasTo 434 = (SharedCacheEntry*)entry->ResolveIfAlias(&fSharedCache); 435 } 436 437 // look for icon defined by preferred app from metamime 438 aliasTo = (SharedCacheEntry*)GetIconForPreferredApp(fileType, 439 preferredAppSig, mode, size, lazyBitmap, aliasTo); 440 441 if (aliasTo == NULL) 442 return NULL; 443 444 // make an aliased entry so that the next time we get a 445 // hit on the first FindItem in here 446 if (entry == NULL) { 447 PRINT_ADD_ITEM( 448 ("File %s; Line %d # adding entry as alias for type %s\n", 449 __FILE__, __LINE__, fileType)); 450 entry = fSharedCache.AddItem(fileType); 451 entry->SetAliasFor(&fSharedCache, aliasTo); 452 } 453 ASSERT(aliasTo->HaveIconBitmap(mode, size)); 454 return aliasTo; 455 } 456 457 // at this point, we've found an icon for the MIME type 458 BBitmap* bitmap = lazyBitmap->Adopt(); 459 if (entry == NULL) { 460 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for type %s\n", 461 __FILE__, __LINE__, fileType)); 462 entry = fSharedCache.AddItem(fileType); 463 } 464 entry->SetIcon(bitmap, kNormalIcon, size); 465 } 466 467 ASSERT(entry != NULL); 468 469 if (mode != kNormalIcon 470 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 471 entry->ConstructBitmap(mode, size, lazyBitmap); 472 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 473 } 474 475 #if xDEBUG 476 if (!entry->HaveIconBitmap(mode, size)) 477 PRINT(("failing on %s, mode %ld, size %ld\n", fileType, mode, size)); 478 #endif 479 480 ASSERT(entry->HaveIconBitmap(mode, size)); 481 482 return entry; 483 } 484 485 486 IconCacheEntry* 487 IconCache::GetIconFromFileTypes(ModelNodeLazyOpener* modelOpener, 488 IconSource &source, IconDrawMode mode, BSize size, 489 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 490 { 491 ASSERT(fSharedCache.IsLocked()); 492 // use file types to get the icon 493 Model* model = modelOpener->TargetModel(); 494 495 const char* fileType = model->MimeType(); 496 const char* nodePreferredApp = model->PreferredAppSignature(); 497 if (source == kUnknownSource || source == kUnknownNotFromNode 498 || source == kPreferredAppForNode) { 499 if (nodePreferredApp[0]) { 500 // file has a locally set preferred app, try getting an icon from 501 // there 502 entry = GetIconForPreferredApp(fileType, nodePreferredApp, mode, 503 size, lazyBitmap, entry); 504 #if xDEBUG 505 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n", 506 __FILE__, __LINE__, nodePreferredApp, fileType, entry)); 507 #endif 508 if (entry != NULL) { 509 source = kPreferredAppForNode; 510 ASSERT(entry->HaveIconBitmap(mode, size)); 511 512 return entry; 513 } 514 } 515 if (source == kPreferredAppForNode) 516 source = kUnknownSource; 517 } 518 519 entry = GetIconFromMetaMime(fileType, mode, size, lazyBitmap, entry); 520 if (entry == NULL) { 521 // Try getting a supertype handler icon 522 BMimeType mime(fileType); 523 if (!mime.IsSupertypeOnly()) { 524 BMimeType superType; 525 mime.GetSupertype(&superType); 526 const char* superTypeFileType = superType.Type(); 527 if (superTypeFileType != NULL) { 528 entry = GetIconFromMetaMime(superTypeFileType, mode, size, 529 lazyBitmap, entry); 530 } 531 #if DEBUG 532 else { 533 PRINT(("File %s; Line %d # failed to get supertype for " 534 "type %s\n", __FILE__, __LINE__, fileType)); 535 } 536 #endif 537 } 538 } 539 540 ASSERT(entry == NULL || entry->HaveIconBitmap(mode, size)); 541 if (entry != NULL) { 542 if (nodePreferredApp != NULL && *nodePreferredApp != '\0') { 543 // we got a miss using GetIconForPreferredApp before, cache this 544 // fileType/preferredApp combo with an aliased entry 545 546 // make an aliased entry so that the next time we get a 547 // hit and substitute a generic icon right away 548 549 PRINT_ADD_ITEM( 550 ("File %s; Line %d # adding entry as alias for " 551 "preferredApp %s, type %s\n", 552 __FILE__, __LINE__, nodePreferredApp, fileType)); 553 IconCacheEntry* aliasedEntry 554 = fSharedCache.AddItem(fileType, nodePreferredApp); 555 aliasedEntry->SetAliasFor(&fSharedCache, 556 (SharedCacheEntry*)entry); 557 // OK to cast here, have a runtime check 558 source = kPreferredAppForNode; 559 // set source as preferred for node, so that next time we 560 // get a hit in the initial find that uses 561 // GetIconForPreferredApp 562 } else 563 source = kMetaMime; 564 565 #if DEBUG 566 if (!entry->HaveIconBitmap(mode, size)) 567 model->PrintToStream(); 568 #endif 569 ASSERT(entry->HaveIconBitmap(mode, size)); 570 } 571 572 return entry; 573 } 574 575 IconCacheEntry* 576 IconCache::GetVolumeIcon(AutoLock<SimpleIconCache>*nodeCacheLocker, 577 AutoLock<SimpleIconCache>* sharedCacheLocker, 578 AutoLock<SimpleIconCache>** resultingOpenCache, 579 Model* model, IconSource &source, 580 IconDrawMode mode, BSize size, LazyBitmapAllocator* lazyBitmap) 581 { 582 *resultingOpenCache = nodeCacheLocker; 583 nodeCacheLocker->Lock(); 584 585 IconCacheEntry* entry = 0; 586 if (source != kUnknownSource) { 587 // cached in the node cache 588 entry = fNodeCache.FindItem(model->NodeRef()); 589 if (entry != NULL) { 590 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, entry); 591 592 if (source == kTrackerDefault) { 593 // if tracker default, resolved entry is from shared cache 594 // this could be done a little cleaner if entry had a way to 595 // reach the cache it is in 596 *resultingOpenCache = sharedCacheLocker; 597 sharedCacheLocker->Lock(); 598 } 599 600 if (entry->HaveIconBitmap(mode, size)) 601 return entry; 602 } 603 } 604 605 // try getting using the BVolume::GetIcon call; if miss, 606 // go for the default mime based icon 607 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 608 BVolume volume(model->NodeRef()->device); 609 610 if (volume.IsShared()) { 611 // check if it's a network share and give it a special icon 612 BBitmap* bitmap = lazyBitmap->Get(); 613 GetTrackerResources()->GetIconResource(R_ShareIcon, 614 icon_size_for(size), bitmap); 615 if (entry == NULL) { 616 PRINT_ADD_ITEM( 617 ("File %s; Line %d # adding entry for model %s\n", 618 __FILE__, __LINE__, model->Name())); 619 entry = fNodeCache.AddItem(model->NodeRef()); 620 } 621 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 622 } else if (volume.GetIcon(lazyBitmap->Get(), icon_size_for(size)) == B_OK) { 623 // ask the device for an icon 624 BBitmap* bitmap = lazyBitmap->Adopt(); 625 ASSERT(bitmap != NULL); 626 if (entry == NULL) { 627 PRINT_ADD_ITEM( 628 ("File %s; Line %d # adding entry for model %s\n", 629 __FILE__, __LINE__, model->Name())); 630 entry = fNodeCache.AddItem(model->NodeRef()); 631 } 632 ASSERT(entry != NULL); 633 entry->SetIcon(bitmap, kNormalIcon, size); 634 source = kVolume; 635 } else { 636 *resultingOpenCache = sharedCacheLocker; 637 sharedCacheLocker->Lock(); 638 639 // if the volume doesnt have a device it gets the generic icon 640 entry = GetIconFromMetaMime(B_VOLUME_MIMETYPE, mode, 641 size, lazyBitmap, entry); 642 } 643 } 644 645 if (mode != kNormalIcon && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 646 entry->ConstructBitmap(mode, size, lazyBitmap); 647 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 648 } 649 650 return entry; 651 } 652 653 654 IconCacheEntry* 655 IconCache::GetRootIcon(AutoLock<SimpleIconCache>*, 656 AutoLock<SimpleIconCache>* sharedCacheLocker, 657 AutoLock<SimpleIconCache>** resultingOpenCache, 658 Model*, IconSource &source, IconDrawMode mode, 659 BSize size, LazyBitmapAllocator* lazyBitmap) 660 { 661 *resultingOpenCache = sharedCacheLocker; 662 (*resultingOpenCache)->Lock(); 663 664 source = kTrackerSupplied; 665 666 return GetIconFromMetaMime(B_ROOT_MIMETYPE, mode, size, lazyBitmap, 0); 667 } 668 669 670 IconCacheEntry* 671 IconCache::GetWellKnownIcon(AutoLock<SimpleIconCache>*, 672 AutoLock<SimpleIconCache>* sharedCacheLocker, 673 AutoLock<SimpleIconCache>** resultingOpenCache, 674 Model* model, IconSource &source, IconDrawMode mode, BSize size, 675 LazyBitmapAllocator* lazyBitmap) 676 { 677 const WellKnowEntryList::WellKnownEntry* wellKnownEntry 678 = WellKnowEntryList::MatchEntry(model->NodeRef()); 679 if (wellKnownEntry == NULL) 680 return NULL; 681 682 BString type("tracker/active_"); 683 type += wellKnownEntry->name; 684 685 *resultingOpenCache = sharedCacheLocker; 686 (*resultingOpenCache)->Lock(); 687 688 source = kTrackerSupplied; 689 690 IconCacheEntry* entry = fSharedCache.FindItem(type.String()); 691 if (entry != NULL) { 692 entry = entry->ResolveIfAlias(&fSharedCache, entry); 693 if (entry->HaveIconBitmap(mode, size)) 694 return entry; 695 } 696 697 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 698 // match up well known entries in the file system with specialized 699 // icons stored in Tracker's resources 700 int32 resourceId = -1; 701 switch ((uint32)wellKnownEntry->which) { 702 case B_BOOT_DISK: 703 resourceId = R_BootVolumeIcon; 704 break; 705 706 case B_BEOS_DIRECTORY: 707 resourceId = R_BeosFolderIcon; 708 break; 709 710 case B_USER_DIRECTORY: 711 resourceId = R_HomeDirIcon; 712 break; 713 714 case B_SYSTEM_FONTS_DIRECTORY: 715 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY: 716 case B_USER_FONTS_DIRECTORY: 717 case B_USER_NONPACKAGED_FONTS_DIRECTORY: 718 resourceId = R_FontDirIcon; 719 break; 720 721 case B_BEOS_APPS_DIRECTORY: 722 case B_APPS_DIRECTORY: 723 case B_USER_DESKBAR_APPS_DIRECTORY: 724 resourceId = R_AppsDirIcon; 725 break; 726 727 case B_BEOS_PREFERENCES_DIRECTORY: 728 case B_PREFERENCES_DIRECTORY: 729 case B_USER_DESKBAR_PREFERENCES_DIRECTORY: 730 resourceId = R_PrefsDirIcon; 731 break; 732 733 case B_USER_MAIL_DIRECTORY: 734 resourceId = R_MailDirIcon; 735 break; 736 737 case B_USER_QUERIES_DIRECTORY: 738 resourceId = R_QueryDirIcon; 739 break; 740 741 case B_SYSTEM_DEVELOP_DIRECTORY: 742 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY: 743 case B_USER_DESKBAR_DEVELOP_DIRECTORY: 744 resourceId = R_DevelopDirIcon; 745 break; 746 747 case B_USER_CONFIG_DIRECTORY: 748 resourceId = R_ConfigDirIcon; 749 break; 750 751 case B_USER_PEOPLE_DIRECTORY: 752 resourceId = R_PersonDirIcon; 753 break; 754 755 case B_USER_DOWNLOADS_DIRECTORY: 756 resourceId = R_DownloadDirIcon; 757 break; 758 759 default: 760 return NULL; 761 } 762 763 entry = fSharedCache.AddItem(type.String()); 764 765 BBitmap* bitmap = lazyBitmap->Get(); 766 GetTrackerResources()->GetIconResource(resourceId, 767 icon_size_for(size), bitmap); 768 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 769 } 770 771 if (mode != kNormalIcon 772 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 773 entry->ConstructBitmap(mode, size, lazyBitmap); 774 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 775 } 776 777 ASSERT(entry->HaveIconBitmap(mode, size)); 778 779 return entry; 780 } 781 782 783 IconCacheEntry* 784 IconCache::GetNodeIcon(ModelNodeLazyOpener* modelOpener, 785 AutoLock<SimpleIconCache>* nodeCacheLocker, 786 AutoLock<SimpleIconCache>** resultingOpenCache, 787 Model* model, IconSource& source, 788 IconDrawMode mode, BSize size, 789 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry, bool permanent) 790 { 791 *resultingOpenCache = nodeCacheLocker; 792 (*resultingOpenCache)->Lock(); 793 794 entry = fNodeCache.FindItem(model->NodeRef()); 795 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 796 modelOpener->OpenNode(); 797 798 PRINT_DISK_HITS(("File %s; Line %d # hitting disk for node %s\n", 799 __FILE__, __LINE__, model->Name())); 800 801 // if we are dealing with an application, use the BAppFileInfo 802 // superset of node; this makes GetIcon grab the proper icon for 803 // an app 804 805 BFile* file = NULL; 806 status_t result = B_ERROR; 807 if (model->IsExecutable() 808 && (file = dynamic_cast<BFile*>(model->Node())) != NULL) { 809 result = GetAppIconFromAttr(file, lazyBitmap->Get(), icon_size_for(size)); 810 } else { 811 result = GetThumbnailFromAttr(model, lazyBitmap->Get(), size); 812 if (result != B_OK && result != B_BUSY) { 813 result = GetFileIconFromAttr(model->Node(), lazyBitmap->Get(), 814 icon_size_for(size)); 815 } 816 } 817 818 if (result == B_OK) { 819 // node has its own icon, use it 820 BBitmap* bitmap = lazyBitmap->Adopt(); 821 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for model %s\n", 822 __FILE__, __LINE__, model->Name())); 823 entry = fNodeCache.AddItem(model->NodeRef(), permanent); 824 ASSERT(entry != NULL); 825 entry->SetIcon(bitmap, kNormalIcon, size); 826 if (mode != kNormalIcon) { 827 entry->ConstructBitmap(mode, size, lazyBitmap); 828 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 829 } 830 source = kNode; 831 } 832 } 833 834 if (entry == NULL) { 835 (*resultingOpenCache)->Unlock(); 836 *resultingOpenCache = NULL; 837 } else if (!entry->HaveIconBitmap(mode, size) 838 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 839 entry->ConstructBitmap(mode, size, lazyBitmap); 840 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 841 ASSERT(entry->HaveIconBitmap(mode, size)); 842 } 843 844 return entry; 845 } 846 847 848 IconCacheEntry* 849 IconCache::GetGenericIcon(AutoLock<SimpleIconCache>* sharedCacheLocker, 850 AutoLock<SimpleIconCache>** resultingOpenCache, 851 Model* model, IconSource &source, 852 IconDrawMode mode, BSize size, 853 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 854 { 855 *resultingOpenCache = sharedCacheLocker; 856 (*resultingOpenCache)->Lock(); 857 858 entry = GetIconFromMetaMime(B_FILE_MIMETYPE, mode, size, lazyBitmap, 0); 859 if (entry == NULL) 860 return NULL; 861 862 // make an aliased entry so that the next time we get a 863 // hit and substitute a generic icon right away 864 PRINT_ADD_ITEM( 865 ("File %s; Line %d # adding entry for preferredApp %s, type %s\n", 866 __FILE__, __LINE__, model->PreferredAppSignature(), 867 model->MimeType())); 868 IconCacheEntry* aliasedEntry = fSharedCache.AddItem( 869 model->MimeType(), model->PreferredAppSignature()); 870 aliasedEntry->SetAliasFor(&fSharedCache, (SharedCacheEntry*)entry); 871 872 source = kMetaMime; 873 874 ASSERT(entry->HaveIconBitmap(mode, size)); 875 876 return entry; 877 } 878 879 880 IconCacheEntry* 881 IconCache::GetFallbackIcon(AutoLock<SimpleIconCache>* sharedCacheLocker, 882 AutoLock<SimpleIconCache>** resultingOpenCache, 883 Model* model, IconDrawMode mode, BSize size, 884 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 885 { 886 *resultingOpenCache = sharedCacheLocker; 887 (*resultingOpenCache)->Lock(); 888 889 entry = fSharedCache.AddItem(model->MimeType(), 890 model->PreferredAppSignature()); 891 892 BBitmap* bitmap = lazyBitmap->Get(); 893 GetTrackerResources()->GetIconResource(R_FileIcon, 894 icon_size_for(size), bitmap); 895 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 896 897 if (mode != kNormalIcon) { 898 entry->ConstructBitmap(mode, size, lazyBitmap); 899 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 900 } 901 902 ASSERT(entry->HaveIconBitmap(mode, size)); 903 904 return entry; 905 } 906 907 908 IconCacheEntry* 909 IconCache::Preload(AutoLock<SimpleIconCache>* nodeCacheLocker, 910 AutoLock<SimpleIconCache>* sharedCacheLocker, 911 AutoLock<SimpleIconCache>** resultingCache, 912 Model* model, IconDrawMode mode, BSize size, 913 bool permanent) 914 { 915 IconCacheEntry* entry = NULL; 916 917 AutoLock<SimpleIconCache>* resultingOpenCache = NULL; 918 // resultingOpenCache is the locker that points to the cache that 919 // ended with a hit and will be used for the drawing 920 921 { 922 // scope for modelOpener 923 924 ModelNodeLazyOpener modelOpener(model); 925 // this opener takes care of opening the model and possibly 926 // closing it when we are done 927 LazyBitmapAllocator lazyBitmap(size); 928 // lazyBitmap manages bitmap allocation and freeing if needed 929 930 IconSource source = model->IconFrom(); 931 if (source == kUnknownSource || source == kUnknownNotFromNode) { 932 // fish for special first models and handle them appropriately 933 if (model->IsVolume()) { 934 // volume may use specialized icon in the volume node 935 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 936 &resultingOpenCache, model, source, mode, size, 937 &lazyBitmap, entry, permanent); 938 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 939 // look for volume defined icon 940 entry = GetVolumeIcon(nodeCacheLocker, sharedCacheLocker, 941 &resultingOpenCache, model, source, mode, 942 size, &lazyBitmap); 943 } 944 } else if (model->IsRoot()) { 945 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 946 &resultingOpenCache, model, source, mode, size, 947 &lazyBitmap); 948 ASSERT(entry != NULL); 949 } else { 950 if (source == kUnknownSource) { 951 // look for node icons first 952 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 953 &resultingOpenCache, model, source, 954 mode, size, &lazyBitmap, entry, permanent); 955 } 956 957 if (entry == NULL) { 958 // no node icon, look for file type based one 959 modelOpener.OpenNode(); 960 // use file types to get the icon 961 resultingOpenCache = sharedCacheLocker; 962 resultingOpenCache->Lock(); 963 964 entry = GetIconFromFileTypes(&modelOpener, source, mode, 965 size, &lazyBitmap, 0); 966 if (entry == NULL) { 967 // we don't have an icon, go with the generic 968 entry = GetGenericIcon(sharedCacheLocker, 969 &resultingOpenCache, model, source, mode, 970 size, &lazyBitmap, entry); 971 } 972 } 973 } 974 975 // update the icon source 976 model->SetIconFrom(source); 977 } else { 978 // we already know where the icon should come from, 979 // use shortcuts to get it 980 switch (source) { 981 case kNode: 982 resultingOpenCache = nodeCacheLocker; 983 resultingOpenCache->Lock(); 984 985 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 986 &resultingOpenCache, model, source, mode, 987 size, &lazyBitmap, entry, permanent); 988 if (entry != NULL) { 989 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, 990 entry); 991 if (!entry->HaveIconBitmap(mode, size) 992 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 993 entry->ConstructBitmap(mode, size, &lazyBitmap); 994 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 995 } 996 ASSERT(entry->HaveIconBitmap(mode, size)); 997 } 998 break; 999 case kTrackerSupplied: 1000 if (model->IsRoot()) { 1001 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 1002 &resultingOpenCache, model, source, mode, size, 1003 &lazyBitmap); 1004 break; 1005 } else { 1006 entry = GetWellKnownIcon(nodeCacheLocker, 1007 sharedCacheLocker, &resultingOpenCache, model, 1008 source, mode, size, &lazyBitmap); 1009 if (entry != NULL) 1010 break; 1011 } 1012 // fall through 1013 case kTrackerDefault: 1014 case kVolume: 1015 if (model->IsVolume()) { 1016 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 1017 &resultingOpenCache, model, source, 1018 mode, size, &lazyBitmap, entry, permanent); 1019 if (entry == NULL 1020 || !entry->HaveIconBitmap(mode, size)) { 1021 entry = GetVolumeIcon(nodeCacheLocker, 1022 sharedCacheLocker, &resultingOpenCache, model, 1023 source, mode, size, &lazyBitmap); 1024 } 1025 break; 1026 } 1027 // fall through 1028 case kMetaMime: 1029 case kPreferredAppForType: 1030 case kPreferredAppForNode: 1031 resultingOpenCache = sharedCacheLocker; 1032 resultingOpenCache->Lock(); 1033 1034 entry = GetIconFromFileTypes(&modelOpener, source, mode, 1035 size, &lazyBitmap, 0); 1036 1037 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1038 // we don't have an icon, go with the generic 1039 entry = GetGenericIcon(sharedCacheLocker, 1040 &resultingOpenCache, model, source, mode, size, 1041 &lazyBitmap, entry); 1042 } 1043 1044 model->SetIconFrom(source); 1045 // The source shouldn't change in this case; if it does 1046 // though we might never be hitting the correct icon and 1047 // instead keep leaking entries after each miss this now 1048 // happens if an app defines an icon but a 1049 // GetIconForType() fails and we fall back to generic 1050 // icon. 1051 // ToDo: fix this and add an assert to the effect 1052 1053 ASSERT(entry != NULL); 1054 ASSERT(entry->HaveIconBitmap(mode, size)); 1055 break; 1056 1057 default: 1058 TRESPASS(); 1059 break; 1060 } 1061 } 1062 1063 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1064 // we don't have an icon, go with the generic 1065 PRINT( 1066 ("icon cache complete miss, falling back on generic icon " 1067 "for %s\n", model->Name())); 1068 entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache, 1069 model, source, mode, size, &lazyBitmap, entry); 1070 1071 // we don't even have generic, something is really broken, 1072 // go with hardcoded generic icon 1073 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1074 PRINT( 1075 ("icon cache complete miss, falling back on generic " 1076 "icon for %s\n", model->Name())); 1077 entry = GetFallbackIcon(sharedCacheLocker, 1078 &resultingOpenCache, model, mode, size, &lazyBitmap, 1079 entry); 1080 } 1081 1082 // force icon pick up next time around because we probably just 1083 // hit a node in transition 1084 model->SetIconFrom(kUnknownSource); 1085 } 1086 } 1087 1088 ASSERT(entry != NULL && entry->HaveIconBitmap(mode, size)); 1089 1090 if (resultingCache != NULL) 1091 *resultingCache = resultingOpenCache; 1092 1093 return entry; 1094 } 1095 1096 1097 void 1098 IconCache::Draw(Model* model, BView* view, BPoint where, IconDrawMode mode, 1099 BSize size, bool async) 1100 { 1101 // the following does not actually lock the caches, we are using the 1102 // lockLater mode; we will decide which of the two to lock down depending 1103 // on where we get the icon from 1104 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1105 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1106 1107 AutoLock<SimpleIconCache>* resultingCacheLocker; 1108 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1109 &resultingCacheLocker, model, mode, size, false); 1110 // Preload finds/creates the appropriate entry, locking down the 1111 // cache it is in and returns the whole state back to here 1112 1113 if (entry == NULL) 1114 return; 1115 1116 ASSERT(entry != NULL); 1117 ASSERT(entry->HaveIconBitmap(mode, size)); 1118 // got the entry, now draw it 1119 resultingCacheLocker->LockedItem()->Draw(entry, view, where, mode, 1120 size, async); 1121 1122 // either of the two cache lockers that got locked down by this call get 1123 // unlocked at this point 1124 } 1125 1126 1127 void 1128 IconCache::SyncDraw(Model* model, BView* view, BPoint where, 1129 IconDrawMode mode, BSize size, 1130 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1131 void* passThruState) 1132 { 1133 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1134 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1135 1136 AutoLock<SimpleIconCache>* resultingCacheLocker; 1137 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1138 &resultingCacheLocker, model, mode, size, false); 1139 1140 if (entry == NULL) 1141 return; 1142 1143 ASSERT(entry != NULL); 1144 ASSERT(entry->HaveIconBitmap(mode, size)); 1145 resultingCacheLocker->LockedItem()->Draw(entry, view, where, 1146 mode, size, blitFunc, passThruState); 1147 } 1148 1149 1150 void 1151 IconCache::Preload(Model* model, IconDrawMode mode, BSize size, 1152 bool permanent) 1153 { 1154 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1155 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1156 1157 Preload(&nodeCacheLocker, &sharedCacheLocker, 0, model, mode, size, 1158 permanent); 1159 } 1160 1161 1162 status_t 1163 IconCache::Preload(const char* fileType, IconDrawMode mode, BSize size) 1164 { 1165 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache); 1166 LazyBitmapAllocator lazyBitmap(size); 1167 1168 BMimeType mime(fileType); 1169 char preferredAppSig[B_MIME_TYPE_LENGTH]; 1170 status_t result = mime.GetPreferredApp(preferredAppSig); 1171 if (result != B_OK) 1172 return result; 1173 1174 // try getting the icon from the preferred app for the signature 1175 IconCacheEntry* entry = GetIconForPreferredApp(fileType, preferredAppSig, 1176 mode, size, &lazyBitmap, 0); 1177 if (entry != NULL) 1178 return B_OK; 1179 1180 // try getting the icon directly from the metamime 1181 result = mime.GetIcon(lazyBitmap.Get(), icon_size_for(size)); 1182 1183 if (result != B_OK) 1184 return result; 1185 1186 entry = fSharedCache.AddItem(fileType); 1187 BBitmap* bitmap = lazyBitmap.Adopt(); 1188 entry->SetIcon(bitmap, kNormalIcon, size); 1189 if (mode != kNormalIcon) { 1190 entry->ConstructBitmap(mode, size, &lazyBitmap); 1191 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 1192 } 1193 1194 return B_OK; 1195 } 1196 1197 1198 void 1199 IconCache::Deleting(const Model* model) 1200 { 1201 AutoLock<SimpleIconCache> lock(&fNodeCache); 1202 1203 if (model->IconFrom() == kNode) 1204 fNodeCache.Deleting(model->NodeRef()); 1205 1206 // don't care if the node uses the shared cache 1207 } 1208 1209 1210 void 1211 IconCache::Removing(const Model* model) 1212 { 1213 AutoLock<SimpleIconCache> lock(&fNodeCache); 1214 1215 if (model->IconFrom() == kNode) 1216 fNodeCache.Removing(model->NodeRef()); 1217 } 1218 1219 1220 void 1221 IconCache::Deleting(const BView* view) 1222 { 1223 AutoLock<SimpleIconCache> lock(&fNodeCache); 1224 fNodeCache.Deleting(view); 1225 } 1226 1227 1228 void 1229 IconCache::IconChanged(Model* model) 1230 { 1231 AutoLock<SimpleIconCache> lock(&fNodeCache); 1232 1233 if (model->IconFrom() == kNode || model->IconFrom() == kVolume) 1234 fNodeCache.Deleting(model->NodeRef()); 1235 1236 model->ResetIconFrom(); 1237 } 1238 1239 1240 void 1241 IconCache::IconChanged(const char* mimeType, const char* appSignature) 1242 { 1243 AutoLock<SimpleIconCache> sharedLock(&fSharedCache); 1244 SharedCacheEntry* entry = fSharedCache.FindItem(mimeType, appSignature); 1245 if (entry == NULL) 1246 return; 1247 1248 AutoLock<SimpleIconCache> nodeLock(&fNodeCache); 1249 1250 entry = (SharedCacheEntry*)fSharedCache.ResolveIfAlias(entry); 1251 ASSERT(entry != NULL); 1252 1253 fNodeCache.RemoveAliasesTo(entry); 1254 fSharedCache.RemoveAliasesTo(entry); 1255 1256 fSharedCache.IconChanged(entry); 1257 } 1258 1259 1260 BBitmap* 1261 IconCache::MakeSelectedIcon(const BBitmap* normal, BSize size, 1262 LazyBitmapAllocator* lazyBitmap) 1263 { 1264 return MakeTransformedIcon(normal, size, fHighlightTable, lazyBitmap); 1265 } 1266 1267 1268 #if xDEBUG 1269 static void 1270 DumpBitmap(const BBitmap* bitmap) 1271 { 1272 if (bitmap == NULL) { 1273 printf("NULL bitmap passed to DumpBitmap\n"); 1274 return; 1275 } 1276 int32 length = bitmap->BitsLength(); 1277 1278 printf("data length %ld \n", length); 1279 1280 int32 columns = (int32)bitmap->Bounds().Width() + 1; 1281 const unsigned char* bitPtr = (const unsigned char*)bitmap->Bits(); 1282 for (; length >= 0; length--) { 1283 for (int32 columnIndex = 0; columnIndex < columns; 1284 columnIndex++, length--) 1285 printf("%c%c", "0123456789ABCDEF"[(*bitPtr)/0x10], 1286 "0123456789ABCDEF"[(*bitPtr++)%0x10]); 1287 1288 printf("\n"); 1289 } 1290 printf("\n"); 1291 } 1292 #endif 1293 1294 1295 void 1296 IconCache::InitHighlightTable() 1297 { 1298 // build the color transform tables for different icon modes 1299 BScreen screen(B_MAIN_SCREEN_ID); 1300 rgb_color color; 1301 for (int32 index = 0; index < kColorTransformTableSize; index++) { 1302 color = screen.ColorForIndex((uchar)index); 1303 fHighlightTable[index] = screen.IndexForColor(tint_color(color, 1.3f)); 1304 } 1305 1306 fHighlightTable[B_TRANSPARENT_8_BIT] = B_TRANSPARENT_8_BIT; 1307 fInitHighlightTable = false; 1308 } 1309 1310 1311 BBitmap* 1312 IconCache::MakeTransformedIcon(const BBitmap* source, BSize /*size*/, 1313 int32 colorTransformTable[], LazyBitmapAllocator* lazyBitmap) 1314 { 1315 if (fInitHighlightTable) 1316 InitHighlightTable(); 1317 1318 BBitmap* result = lazyBitmap->Get(); 1319 uint8* src = (uint8*)source->Bits(); 1320 uint8* dst = (uint8*)result->Bits(); 1321 1322 // ASSERT(result->ColorSpace() == source->ColorSpace() 1323 // && result->Bounds() == source->Bounds()); 1324 if (result->ColorSpace() != source->ColorSpace() 1325 || result->Bounds() != source->Bounds()) { 1326 printf("IconCache::MakeTransformedIcon() - bitmap format mismatch!\n"); 1327 return NULL; 1328 } 1329 1330 switch (result->ColorSpace()) { 1331 case B_RGB32: 1332 case B_RGBA32: { 1333 uint32 width = source->Bounds().IntegerWidth() + 1; 1334 uint32 height = source->Bounds().IntegerHeight() + 1; 1335 uint32 srcBPR = source->BytesPerRow(); 1336 uint32 dstBPR = result->BytesPerRow(); 1337 for (uint32 y = 0; y < height; y++) { 1338 uint8* d = dst; 1339 uint8* s = src; 1340 for (uint32 x = 0; x < width; x++) { 1341 // 66% brightness 1342 d[0] = (int)s[0] * 168 >> 8; 1343 d[1] = (int)s[1] * 168 >> 8; 1344 d[2] = (int)s[2] * 168 >> 8; 1345 d[3] = s[3]; 1346 d += 4; 1347 s += 4; 1348 } 1349 dst += dstBPR; 1350 src += srcBPR; 1351 } 1352 break; 1353 } 1354 1355 case B_CMAP8: { 1356 int32 bitsLength = result->BitsLength(); 1357 for (int32 i = 0; i < bitsLength; i++) 1358 *dst++ = (uint8)colorTransformTable[*src++]; 1359 break; 1360 } 1361 1362 default: 1363 memset(dst, 0, result->BitsLength()); 1364 // unkown colorspace, no tinting for you 1365 // "black" should make the problem stand out 1366 break; 1367 } 1368 1369 return result; 1370 } 1371 1372 1373 bool 1374 IconCache::IconHitTest(BPoint where, const Model* model, IconDrawMode mode, 1375 BSize size) 1376 { 1377 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1378 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1379 1380 AutoLock<SimpleIconCache>* resultingCacheLocker; 1381 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1382 &resultingCacheLocker, const_cast<Model*>(model), mode, size, false); 1383 // Preload finds/creates the appropriate entry, locking down the 1384 // cache it is in and returns the whole state back to here 1385 1386 if (entry != NULL) 1387 return entry->IconHitTest(where, mode, size); 1388 1389 return false; 1390 } 1391 1392 1393 void 1394 IconCacheEntry::RetireIcons(BObjectList<BBitmap>* retiredBitmapList) 1395 { 1396 if (fLargeIcon != NULL) { 1397 retiredBitmapList->AddItem(fLargeIcon); 1398 fLargeIcon = NULL; 1399 } 1400 if (fHighlightedLargeIcon != NULL) { 1401 retiredBitmapList->AddItem(fHighlightedLargeIcon); 1402 fHighlightedLargeIcon = NULL; 1403 } 1404 if (fMiniIcon != NULL) { 1405 retiredBitmapList->AddItem(fMiniIcon); 1406 fMiniIcon = NULL; 1407 } 1408 if (fHighlightedMiniIcon != NULL) { 1409 retiredBitmapList->AddItem(fHighlightedMiniIcon); 1410 fHighlightedMiniIcon = NULL; 1411 } 1412 1413 int32 count = retiredBitmapList->CountItems(); 1414 if (count > 10 * 1024) { 1415 PRINT(("nuking old icons from the retired bitmap list\n")); 1416 for (count = 512; count > 0; count--) 1417 delete retiredBitmapList->RemoveItemAt(0); 1418 } 1419 } 1420 1421 1422 // #pragma mark - SharedIconCache 1423 1424 1425 SharedIconCache::SharedIconCache() 1426 : 1427 SimpleIconCache("Tracker shared icon cache"), 1428 fHashTable(), 1429 fRetiredBitmaps(256, true) 1430 { 1431 fHashTable.Init(256); 1432 } 1433 1434 1435 void 1436 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1437 IconDrawMode mode, BSize size, bool async) 1438 { 1439 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, async); 1440 } 1441 1442 1443 void 1444 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1445 IconDrawMode mode, BSize size, void (*blitFunc)(BView*, BPoint, 1446 BBitmap*, void*), void* passThruState) 1447 { 1448 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, 1449 blitFunc, passThruState); 1450 } 1451 1452 1453 SharedCacheEntry* 1454 SharedIconCache::FindItem(const char* fileType, 1455 const char* appSignature) const 1456 { 1457 ASSERT(fileType); 1458 if (!fileType) 1459 fileType = B_FILE_MIMETYPE; 1460 1461 return fHashTable.Lookup(SharedCacheEntry::TypeAndSignature(fileType, 1462 appSignature)); 1463 } 1464 1465 1466 SharedCacheEntry* 1467 SharedIconCache::AddItem(const char* fileType, const char* appSignature) 1468 { 1469 ASSERT(fileType != NULL); 1470 if (fileType == NULL) 1471 fileType = B_FILE_MIMETYPE; 1472 1473 SharedCacheEntry* entry = new SharedCacheEntry(fileType, appSignature); 1474 if (fHashTable.Insert(entry) == B_OK) 1475 return entry; 1476 1477 delete entry; 1478 return NULL; 1479 } 1480 1481 1482 void 1483 SharedIconCache::IconChanged(SharedCacheEntry* entry) 1484 { 1485 // by now there should be no aliases to entry, just remove entry 1486 // itself 1487 ASSERT(entry->fAliasTo == NULL); 1488 entry->RetireIcons(&fRetiredBitmaps); 1489 fHashTable.Remove(entry); 1490 } 1491 1492 1493 void 1494 SharedIconCache::RemoveAliasesTo(SharedCacheEntry* alias) 1495 { 1496 EntryHashTable::Iterator it = fHashTable.GetIterator(); 1497 while (it.HasNext()) { 1498 SharedCacheEntry* entry = it.Next(); 1499 if (entry->fAliasTo == alias) 1500 fHashTable.RemoveUnchecked(entry); 1501 } 1502 } 1503 1504 1505 void 1506 SharedIconCache::SetAliasFor(IconCacheEntry* entry, 1507 const SharedCacheEntry* original) const 1508 { 1509 entry->fAliasTo = original; 1510 } 1511 1512 1513 SharedCacheEntry::SharedCacheEntry() 1514 : 1515 fNext(NULL) 1516 { 1517 } 1518 1519 1520 SharedCacheEntry::SharedCacheEntry(const char* fileType, 1521 const char* appSignature) 1522 : 1523 fNext(NULL), 1524 fFileType(fileType), 1525 fAppSignature(appSignature) 1526 { 1527 } 1528 1529 1530 void 1531 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1532 BSize size, bool async) 1533 { 1534 BBitmap* bitmap = IconForMode(mode, size); 1535 ASSERT(bitmap != NULL); 1536 1537 drawing_mode oldMode = view->DrawingMode(); 1538 1539 if (bitmap->ColorSpace() == B_RGBA32) { 1540 if (oldMode != B_OP_ALPHA) { 1541 view->SetDrawingMode(B_OP_ALPHA); 1542 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1543 } 1544 } else 1545 view->SetDrawingMode(B_OP_OVER); 1546 1547 if (async) 1548 view->DrawBitmapAsync(bitmap, where); 1549 else 1550 view->DrawBitmap(bitmap, where); 1551 1552 view->SetDrawingMode(oldMode); 1553 } 1554 1555 1556 void 1557 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1558 BSize size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1559 void* passThruState) 1560 { 1561 BBitmap* bitmap = IconForMode(mode, size); 1562 if (bitmap == NULL) 1563 return; 1564 1565 (blitFunc)(view, where, bitmap, passThruState); 1566 } 1567 1568 1569 /* static */ size_t 1570 SharedCacheEntry::Hash(const TypeAndSignature& typeAndSignature) 1571 { 1572 size_t hash = HashString(typeAndSignature.type, 0); 1573 if (typeAndSignature.signature != NULL 1574 && *typeAndSignature.signature != '\0') 1575 hash = HashString(typeAndSignature.signature, hash); 1576 1577 return hash; 1578 } 1579 1580 1581 size_t 1582 SharedCacheEntry::Hash() const 1583 { 1584 return Hash(TypeAndSignature(fFileType.String(), fAppSignature.String())); 1585 } 1586 1587 1588 bool 1589 SharedCacheEntry::operator==(const TypeAndSignature& typeAndSignature) const 1590 { 1591 return fFileType == typeAndSignature.type 1592 && fAppSignature == typeAndSignature.signature; 1593 } 1594 1595 1596 // #pragma mark - NodeCacheEntry 1597 1598 1599 NodeCacheEntry::NodeCacheEntry(bool permanent) 1600 : 1601 fNext(NULL), 1602 fPermanent(permanent) 1603 { 1604 } 1605 1606 1607 NodeCacheEntry::NodeCacheEntry(const node_ref* node, bool permanent) 1608 : 1609 fNext(NULL), 1610 fRef(*node), 1611 fPermanent(permanent) 1612 { 1613 } 1614 1615 1616 void 1617 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1618 BSize size, bool async) 1619 { 1620 BBitmap* bitmap = IconForMode(mode, size); 1621 if (bitmap == NULL) 1622 return; 1623 1624 drawing_mode oldMode = view->DrawingMode(); 1625 1626 if (bitmap->ColorSpace() == B_RGBA32) { 1627 if (oldMode != B_OP_ALPHA) { 1628 view->SetDrawingMode(B_OP_ALPHA); 1629 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1630 } 1631 } else 1632 view->SetDrawingMode(B_OP_OVER); 1633 1634 if (false && async) { 1635 TRESPASS(); 1636 // need to copy the bits first in here 1637 view->DrawBitmapAsync(bitmap, where); 1638 } else 1639 view->DrawBitmap(bitmap, where); 1640 1641 view->SetDrawingMode(oldMode); 1642 } 1643 1644 1645 void 1646 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1647 BSize size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1648 void* passThruState) 1649 { 1650 BBitmap* bitmap = IconForMode(mode, size); 1651 if (bitmap == NULL) 1652 return; 1653 1654 (blitFunc)(view, where, bitmap, passThruState); 1655 } 1656 1657 1658 const node_ref* 1659 NodeCacheEntry::Node() const 1660 { 1661 return &fRef; 1662 } 1663 1664 1665 size_t 1666 NodeCacheEntry::Hash() const 1667 { 1668 return Hash(&fRef); 1669 } 1670 1671 1672 /* static */ size_t 1673 NodeCacheEntry::Hash(const node_ref* node) 1674 { 1675 return node->device ^ ((uint32*)&node->node)[0] 1676 ^ ((uint32*)&node->node)[1]; 1677 } 1678 1679 1680 bool 1681 NodeCacheEntry::operator==(const node_ref* node) const 1682 { 1683 return fRef == *node; 1684 } 1685 1686 1687 bool 1688 NodeCacheEntry::Permanent() const 1689 { 1690 return fPermanent; 1691 } 1692 1693 1694 // #pragma mark - NodeIconCache 1695 1696 1697 NodeIconCache::NodeIconCache() 1698 : 1699 SimpleIconCache("Tracker node icon cache") 1700 { 1701 fHashTable.Init(100); 1702 } 1703 1704 1705 void 1706 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1707 IconDrawMode mode, BSize size, bool async) 1708 { 1709 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, async); 1710 } 1711 1712 1713 void 1714 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1715 IconDrawMode mode, BSize size, 1716 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), void* passThruState) 1717 { 1718 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, 1719 blitFunc, passThruState); 1720 } 1721 1722 1723 NodeCacheEntry* 1724 NodeIconCache::FindItem(const node_ref* node) const 1725 { 1726 return fHashTable.Lookup(node); 1727 } 1728 1729 1730 NodeCacheEntry* 1731 NodeIconCache::AddItem(const node_ref* node, bool permanent) 1732 { 1733 NodeCacheEntry* entry = new NodeCacheEntry(node, permanent); 1734 if (fHashTable.Insert(entry) == B_OK) 1735 return entry; 1736 1737 delete entry; 1738 return NULL; 1739 } 1740 1741 1742 void 1743 NodeIconCache::Deleting(const node_ref* node) 1744 { 1745 NodeCacheEntry* entry = FindItem(node); 1746 if (entry == NULL || entry->Permanent()) 1747 return; 1748 1749 fHashTable.Remove(entry); 1750 } 1751 1752 1753 void 1754 NodeIconCache::Removing(const node_ref* node) 1755 { 1756 NodeCacheEntry* entry = FindItem(node); 1757 ASSERT(entry != NULL); 1758 if (entry == NULL) 1759 return; 1760 1761 fHashTable.Remove(entry); 1762 } 1763 1764 1765 void 1766 NodeIconCache::Deleting(const BView*) 1767 { 1768 #ifdef NODE_CACHE_ASYNC_DRAWS 1769 TRESPASS(); 1770 #endif 1771 } 1772 1773 1774 void 1775 NodeIconCache::IconChanged(const Model* model) 1776 { 1777 Deleting(model->NodeRef()); 1778 } 1779 1780 1781 void 1782 NodeIconCache::RemoveAliasesTo(SharedCacheEntry* alias) 1783 { 1784 EntryHashTable::Iterator it = fHashTable.GetIterator(); 1785 while (it.HasNext()) { 1786 NodeCacheEntry* entry = it.Next(); 1787 if (entry->fAliasTo == alias) 1788 fHashTable.RemoveUnchecked(entry); 1789 } 1790 } 1791 1792 1793 // #pragma mark - SimpleIconCache 1794 1795 1796 SimpleIconCache::SimpleIconCache(const char* name) 1797 : 1798 fLock(name) 1799 { 1800 } 1801 1802 1803 void 1804 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1805 BSize, bool) 1806 { 1807 TRESPASS(); 1808 // pure virtual, do nothing 1809 } 1810 1811 1812 void 1813 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1814 BSize, void(*)(BView*, BPoint, BBitmap*, void*), void*) 1815 { 1816 TRESPASS(); 1817 // pure virtual, do nothing 1818 } 1819 1820 1821 bool 1822 SimpleIconCache::Lock() 1823 { 1824 return fLock.Lock(); 1825 } 1826 1827 1828 void 1829 SimpleIconCache::Unlock() 1830 { 1831 fLock.Unlock(); 1832 } 1833 1834 1835 bool 1836 SimpleIconCache::IsLocked() const 1837 { 1838 return fLock.IsLocked(); 1839 } 1840 1841 1842 // #pragma mark - LazyBitmapAllocator 1843 1844 1845 LazyBitmapAllocator::LazyBitmapAllocator(BSize size, 1846 color_space colorSpace, bool preallocate) 1847 : 1848 fBitmap(NULL), 1849 fSize(size), 1850 fColorSpace(colorSpace) 1851 { 1852 if (preallocate) 1853 Get(); 1854 } 1855 1856 1857 LazyBitmapAllocator::~LazyBitmapAllocator() 1858 { 1859 delete fBitmap; 1860 } 1861 1862 1863 BBitmap* 1864 LazyBitmapAllocator::Get() 1865 { 1866 if (fBitmap == NULL) 1867 fBitmap = new BBitmap(BRect(BPoint(0, 0), fSize), fColorSpace); 1868 1869 return fBitmap; 1870 } 1871 1872 1873 BBitmap* 1874 LazyBitmapAllocator::Adopt() 1875 { 1876 if (fBitmap == NULL) 1877 Get(); 1878 1879 BBitmap* bitmap = fBitmap; 1880 fBitmap = NULL; 1881 1882 return bitmap; 1883 } 1884 1885 1886 IconCache* IconCache::sIconCache; 1887