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