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 fAliasTo(NULL) 111 { 112 } 113 114 115 IconCacheEntry::~IconCacheEntry() 116 { 117 if (fAliasTo == NULL) { 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 fAliasTo = NULL; 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(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(fileType, nodePreferredApp); 535 aliasedEntry->SetAliasFor(&fSharedCache, 536 (SharedCacheEntry*)entry); 537 // OK to cast here, have a runtime check 538 source = kPreferredAppForNode; 539 // set source as preferred for node, so that next time we 540 // get a hit in the initial find that uses 541 // GetIconForPreferredApp 542 } else 543 source = kMetaMime; 544 545 #if DEBUG 546 if (!entry->HaveIconBitmap(mode, size)) 547 model->PrintToStream(); 548 #endif 549 ASSERT(entry->HaveIconBitmap(mode, size)); 550 } 551 552 return entry; 553 } 554 555 IconCacheEntry* 556 IconCache::GetVolumeIcon(AutoLock<SimpleIconCache>*nodeCacheLocker, 557 AutoLock<SimpleIconCache>* sharedCacheLocker, 558 AutoLock<SimpleIconCache>** resultingOpenCache, 559 Model* model, IconSource &source, 560 IconDrawMode mode, icon_size size, LazyBitmapAllocator* lazyBitmap) 561 { 562 *resultingOpenCache = nodeCacheLocker; 563 nodeCacheLocker->Lock(); 564 565 IconCacheEntry* entry = 0; 566 if (source != kUnknownSource) { 567 // cached in the node cache 568 entry = fNodeCache.FindItem(model->NodeRef()); 569 if (entry != NULL) { 570 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, entry); 571 572 if (source == kTrackerDefault) { 573 // if tracker default, resolved entry is from shared cache 574 // this could be done a little cleaner if entry had a way to 575 // reach the cache it is in 576 *resultingOpenCache = sharedCacheLocker; 577 sharedCacheLocker->Lock(); 578 } 579 580 if (entry->HaveIconBitmap(mode, size)) 581 return entry; 582 } 583 } 584 585 // try getting using the BVolume::GetIcon call; if miss, 586 // go for the default mime based icon 587 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 588 BVolume volume(model->NodeRef()->device); 589 590 if (volume.IsShared()) { 591 // check if it's a network share and give it a special icon 592 BBitmap* bitmap = lazyBitmap->Get(); 593 GetTrackerResources()->GetIconResource(R_ShareIcon, size, bitmap); 594 if (entry == NULL) { 595 PRINT_ADD_ITEM( 596 ("File %s; Line %d # adding entry for model %s\n", 597 __FILE__, __LINE__, model->Name())); 598 entry = fNodeCache.AddItem(model->NodeRef()); 599 } 600 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 601 } else if (volume.GetIcon(lazyBitmap->Get(), size) == B_OK) { 602 // ask the device for an icon 603 BBitmap* bitmap = lazyBitmap->Adopt(); 604 ASSERT(bitmap != NULL); 605 if (entry == NULL) { 606 PRINT_ADD_ITEM( 607 ("File %s; Line %d # adding entry for model %s\n", 608 __FILE__, __LINE__, model->Name())); 609 entry = fNodeCache.AddItem(model->NodeRef()); 610 } 611 ASSERT(entry != NULL); 612 entry->SetIcon(bitmap, kNormalIcon, size); 613 source = kVolume; 614 } else { 615 *resultingOpenCache = sharedCacheLocker; 616 sharedCacheLocker->Lock(); 617 618 // if the volume doesnt have a device it gets the generic icon 619 entry = GetIconFromMetaMime(B_VOLUME_MIMETYPE, mode, 620 size, lazyBitmap, entry); 621 } 622 } 623 624 if (mode != kNormalIcon && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 625 entry->ConstructBitmap(mode, size, lazyBitmap); 626 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 627 } 628 629 return entry; 630 } 631 632 633 IconCacheEntry* 634 IconCache::GetRootIcon(AutoLock<SimpleIconCache>*, 635 AutoLock<SimpleIconCache>* sharedCacheLocker, 636 AutoLock<SimpleIconCache>** resultingOpenCache, 637 Model*, IconSource &source, IconDrawMode mode, 638 icon_size size, LazyBitmapAllocator* lazyBitmap) 639 { 640 *resultingOpenCache = sharedCacheLocker; 641 (*resultingOpenCache)->Lock(); 642 643 source = kTrackerSupplied; 644 645 return GetIconFromMetaMime(B_ROOT_MIMETYPE, mode, size, lazyBitmap, 0); 646 } 647 648 649 IconCacheEntry* 650 IconCache::GetWellKnownIcon(AutoLock<SimpleIconCache>*, 651 AutoLock<SimpleIconCache>* sharedCacheLocker, 652 AutoLock<SimpleIconCache>** resultingOpenCache, 653 Model* model, IconSource &source, IconDrawMode mode, icon_size size, 654 LazyBitmapAllocator* lazyBitmap) 655 { 656 const WellKnowEntryList::WellKnownEntry* wellKnownEntry 657 = WellKnowEntryList::MatchEntry(model->NodeRef()); 658 if (wellKnownEntry == NULL) 659 return NULL; 660 661 BString type("tracker/active_"); 662 type += wellKnownEntry->name; 663 664 *resultingOpenCache = sharedCacheLocker; 665 (*resultingOpenCache)->Lock(); 666 667 source = kTrackerSupplied; 668 669 IconCacheEntry* entry = fSharedCache.FindItem(type.String()); 670 if (entry != NULL) { 671 entry = entry->ResolveIfAlias(&fSharedCache, entry); 672 if (entry->HaveIconBitmap(mode, size)) 673 return entry; 674 } 675 676 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 677 // match up well known entries in the file system with specialized 678 // icons stored in Tracker's resources 679 int32 resourceId = -1; 680 switch ((uint32)wellKnownEntry->which) { 681 case B_BOOT_DISK: 682 resourceId = R_BootVolumeIcon; 683 break; 684 685 case B_BEOS_DIRECTORY: 686 resourceId = R_BeosFolderIcon; 687 break; 688 689 case B_USER_DIRECTORY: 690 resourceId = R_HomeDirIcon; 691 break; 692 693 case B_SYSTEM_FONTS_DIRECTORY: 694 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY: 695 case B_USER_FONTS_DIRECTORY: 696 case B_USER_NONPACKAGED_FONTS_DIRECTORY: 697 resourceId = R_FontDirIcon; 698 break; 699 700 case B_BEOS_APPS_DIRECTORY: 701 case B_APPS_DIRECTORY: 702 case B_USER_DESKBAR_APPS_DIRECTORY: 703 resourceId = R_AppsDirIcon; 704 break; 705 706 case B_BEOS_PREFERENCES_DIRECTORY: 707 case B_PREFERENCES_DIRECTORY: 708 case B_USER_DESKBAR_PREFERENCES_DIRECTORY: 709 resourceId = R_PrefsDirIcon; 710 break; 711 712 case B_USER_MAIL_DIRECTORY: 713 resourceId = R_MailDirIcon; 714 break; 715 716 case B_USER_QUERIES_DIRECTORY: 717 resourceId = R_QueryDirIcon; 718 break; 719 720 case B_SYSTEM_DEVELOP_DIRECTORY: 721 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY: 722 case B_USER_DESKBAR_DEVELOP_DIRECTORY: 723 resourceId = R_DevelopDirIcon; 724 break; 725 726 case B_USER_CONFIG_DIRECTORY: 727 resourceId = R_ConfigDirIcon; 728 break; 729 730 case B_USER_PEOPLE_DIRECTORY: 731 resourceId = R_PersonDirIcon; 732 break; 733 734 case B_USER_DOWNLOADS_DIRECTORY: 735 resourceId = R_DownloadDirIcon; 736 break; 737 738 default: 739 return NULL; 740 } 741 742 entry = fSharedCache.AddItem(type.String()); 743 744 BBitmap* bitmap = lazyBitmap->Get(); 745 GetTrackerResources()->GetIconResource(resourceId, size, bitmap); 746 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 747 } 748 749 if (mode != kNormalIcon 750 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 751 entry->ConstructBitmap(mode, size, lazyBitmap); 752 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 753 } 754 755 ASSERT(entry->HaveIconBitmap(mode, size)); 756 757 return entry; 758 } 759 760 761 IconCacheEntry* 762 IconCache::GetNodeIcon(ModelNodeLazyOpener* modelOpener, 763 AutoLock<SimpleIconCache>* nodeCacheLocker, 764 AutoLock<SimpleIconCache>** resultingOpenCache, 765 Model* model, IconSource& source, 766 IconDrawMode mode, icon_size size, 767 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry, bool permanent) 768 { 769 *resultingOpenCache = nodeCacheLocker; 770 (*resultingOpenCache)->Lock(); 771 772 entry = fNodeCache.FindItem(model->NodeRef()); 773 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 774 modelOpener->OpenNode(); 775 776 BFile* file = NULL; 777 778 // if we are dealing with an application, use the BAppFileInfo 779 // superset of node; this makes GetIcon grab the proper icon for 780 // an app 781 if (model->IsExecutable()) 782 file = dynamic_cast<BFile*>(model->Node()); 783 784 PRINT_DISK_HITS(("File %s; Line %d # hitting disk for node %s\n", 785 __FILE__, __LINE__, model->Name())); 786 787 status_t result = file != NULL 788 ? GetAppIconFromAttr(file, lazyBitmap->Get(), size) 789 : GetFileIconFromAttr(model->Node(), lazyBitmap->Get(), size); 790 791 if (result == B_OK) { 792 // node has its own icon, use it 793 BBitmap* bitmap = lazyBitmap->Adopt(); 794 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for model %s\n", 795 __FILE__, __LINE__, model->Name())); 796 entry = fNodeCache.AddItem(model->NodeRef(), permanent); 797 ASSERT(entry != NULL); 798 entry->SetIcon(bitmap, kNormalIcon, size); 799 if (mode != kNormalIcon) { 800 entry->ConstructBitmap(mode, size, lazyBitmap); 801 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 802 } 803 source = kNode; 804 } 805 } 806 807 if (entry == NULL) { 808 (*resultingOpenCache)->Unlock(); 809 *resultingOpenCache = NULL; 810 } else if (!entry->HaveIconBitmap(mode, size) 811 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 812 entry->ConstructBitmap(mode, size, lazyBitmap); 813 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 814 ASSERT(entry->HaveIconBitmap(mode, size)); 815 } 816 817 return entry; 818 } 819 820 821 IconCacheEntry* 822 IconCache::GetGenericIcon(AutoLock<SimpleIconCache>* sharedCacheLocker, 823 AutoLock<SimpleIconCache>** resultingOpenCache, 824 Model* model, IconSource &source, 825 IconDrawMode mode, icon_size size, 826 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 827 { 828 *resultingOpenCache = sharedCacheLocker; 829 (*resultingOpenCache)->Lock(); 830 831 entry = GetIconFromMetaMime(B_FILE_MIMETYPE, mode, size, lazyBitmap, 0); 832 if (entry == NULL) 833 return NULL; 834 835 // make an aliased entry so that the next time we get a 836 // hit and substitute a generic icon right away 837 PRINT_ADD_ITEM( 838 ("File %s; Line %d # adding entry for preferredApp %s, type %s\n", 839 __FILE__, __LINE__, model->PreferredAppSignature(), 840 model->MimeType())); 841 IconCacheEntry* aliasedEntry = fSharedCache.AddItem( 842 model->MimeType(), model->PreferredAppSignature()); 843 aliasedEntry->SetAliasFor(&fSharedCache, (SharedCacheEntry*)entry); 844 845 source = kMetaMime; 846 847 ASSERT(entry->HaveIconBitmap(mode, size)); 848 849 return entry; 850 } 851 852 853 IconCacheEntry* 854 IconCache::GetFallbackIcon(AutoLock<SimpleIconCache>* sharedCacheLocker, 855 AutoLock<SimpleIconCache>** resultingOpenCache, 856 Model* model, IconDrawMode mode, icon_size size, 857 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 858 { 859 *resultingOpenCache = sharedCacheLocker; 860 (*resultingOpenCache)->Lock(); 861 862 entry = fSharedCache.AddItem(model->MimeType(), 863 model->PreferredAppSignature()); 864 865 BBitmap* bitmap = lazyBitmap->Get(); 866 GetTrackerResources()->GetIconResource(R_FileIcon, size, bitmap); 867 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 868 869 if (mode != kNormalIcon) { 870 entry->ConstructBitmap(mode, size, lazyBitmap); 871 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 872 } 873 874 ASSERT(entry->HaveIconBitmap(mode, size)); 875 876 return entry; 877 } 878 879 880 IconCacheEntry* 881 IconCache::Preload(AutoLock<SimpleIconCache>* nodeCacheLocker, 882 AutoLock<SimpleIconCache>* sharedCacheLocker, 883 AutoLock<SimpleIconCache>** resultingCache, 884 Model* model, IconDrawMode mode, icon_size size, 885 bool permanent) 886 { 887 IconCacheEntry* entry = NULL; 888 889 AutoLock<SimpleIconCache>* resultingOpenCache = NULL; 890 // resultingOpenCache is the locker that points to the cache that 891 // ended with a hit and will be used for the drawing 892 893 { 894 // scope for modelOpener 895 896 ModelNodeLazyOpener modelOpener(model); 897 // this opener takes care of opening the model and possibly 898 // closing it when we are done 899 LazyBitmapAllocator lazyBitmap(size); 900 // lazyBitmap manages bitmap allocation and freeing if needed 901 902 IconSource source = model->IconFrom(); 903 if (source == kUnknownSource || source == kUnknownNotFromNode) { 904 // fish for special first models and handle them appropriately 905 if (model->IsVolume()) { 906 // volume may use specialized icon in the volume node 907 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 908 &resultingOpenCache, model, source, mode, size, 909 &lazyBitmap, entry, permanent); 910 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 911 // look for volume defined icon 912 entry = GetVolumeIcon(nodeCacheLocker, sharedCacheLocker, 913 &resultingOpenCache, model, source, mode, 914 size, &lazyBitmap); 915 } 916 } else if (model->IsRoot()) { 917 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 918 &resultingOpenCache, model, source, mode, size, 919 &lazyBitmap); 920 ASSERT(entry != NULL); 921 } else { 922 if (source == kUnknownSource) { 923 // look for node icons first 924 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 925 &resultingOpenCache, model, source, 926 mode, size, &lazyBitmap, entry, permanent); 927 } 928 929 if (entry == NULL) { 930 // no node icon, look for file type based one 931 modelOpener.OpenNode(); 932 // use file types to get the icon 933 resultingOpenCache = sharedCacheLocker; 934 resultingOpenCache->Lock(); 935 936 entry = GetIconFromFileTypes(&modelOpener, source, mode, 937 size, &lazyBitmap, 0); 938 if (entry == NULL) { 939 // we don't have an icon, go with the generic 940 entry = GetGenericIcon(sharedCacheLocker, 941 &resultingOpenCache, model, source, mode, 942 size, &lazyBitmap, entry); 943 } 944 } 945 } 946 947 // update the icon source 948 model->SetIconFrom(source); 949 } else { 950 // we already know where the icon should come from, 951 // use shortcuts to get it 952 switch (source) { 953 case kNode: 954 resultingOpenCache = nodeCacheLocker; 955 resultingOpenCache->Lock(); 956 957 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 958 &resultingOpenCache, model, source, mode, 959 size, &lazyBitmap, entry, permanent); 960 if (entry != NULL) { 961 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, 962 entry); 963 if (!entry->HaveIconBitmap(mode, size) 964 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 965 entry->ConstructBitmap(mode, size, &lazyBitmap); 966 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 967 } 968 ASSERT(entry->HaveIconBitmap(mode, size)); 969 } 970 break; 971 case kTrackerSupplied: 972 if (model->IsRoot()) { 973 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 974 &resultingOpenCache, model, source, mode, size, 975 &lazyBitmap); 976 break; 977 } else { 978 entry = GetWellKnownIcon(nodeCacheLocker, 979 sharedCacheLocker, &resultingOpenCache, model, 980 source, mode, size, &lazyBitmap); 981 if (entry != NULL) 982 break; 983 } 984 // fall through 985 case kTrackerDefault: 986 case kVolume: 987 if (model->IsVolume()) { 988 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 989 &resultingOpenCache, model, source, 990 mode, size, &lazyBitmap, entry, permanent); 991 if (entry == NULL 992 || !entry->HaveIconBitmap(mode, size)) { 993 entry = GetVolumeIcon(nodeCacheLocker, 994 sharedCacheLocker, &resultingOpenCache, model, 995 source, mode, size, &lazyBitmap); 996 } 997 break; 998 } 999 // fall through 1000 case kMetaMime: 1001 case kPreferredAppForType: 1002 case kPreferredAppForNode: 1003 resultingOpenCache = sharedCacheLocker; 1004 resultingOpenCache->Lock(); 1005 1006 entry = GetIconFromFileTypes(&modelOpener, source, mode, 1007 size, &lazyBitmap, 0); 1008 1009 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1010 // we don't have an icon, go with the generic 1011 entry = GetGenericIcon(sharedCacheLocker, 1012 &resultingOpenCache, model, source, mode, size, 1013 &lazyBitmap, entry); 1014 } 1015 1016 model->SetIconFrom(source); 1017 // The source shouldn't change in this case; if it does 1018 // though we might never be hitting the correct icon and 1019 // instead keep leaking entries after each miss this now 1020 // happens if an app defines an icon but a 1021 // GetIconForType() fails and we fall back to generic 1022 // icon. 1023 // ToDo: fix this and add an assert to the effect 1024 1025 ASSERT(entry != NULL); 1026 ASSERT(entry->HaveIconBitmap(mode, size)); 1027 break; 1028 1029 default: 1030 TRESPASS(); 1031 break; 1032 } 1033 } 1034 1035 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1036 // we don't have an icon, go with the generic 1037 PRINT( 1038 ("icon cache complete miss, falling back on generic icon " 1039 "for %s\n", model->Name())); 1040 entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache, 1041 model, source, mode, size, &lazyBitmap, entry); 1042 1043 // we don't even have generic, something is really broken, 1044 // go with hardcoded generic icon 1045 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1046 PRINT( 1047 ("icon cache complete miss, falling back on generic " 1048 "icon for %s\n", model->Name())); 1049 entry = GetFallbackIcon(sharedCacheLocker, 1050 &resultingOpenCache, model, mode, size, &lazyBitmap, 1051 entry); 1052 } 1053 1054 // force icon pick up next time around because we probably just 1055 // hit a node in transition 1056 model->SetIconFrom(kUnknownSource); 1057 } 1058 } 1059 1060 ASSERT(entry != NULL && entry->HaveIconBitmap(mode, size)); 1061 1062 if (resultingCache != NULL) 1063 *resultingCache = resultingOpenCache; 1064 1065 return entry; 1066 } 1067 1068 1069 void 1070 IconCache::Draw(Model* model, BView* view, BPoint where, IconDrawMode mode, 1071 icon_size size, bool async) 1072 { 1073 // the following does not actually lock the caches, we are using the 1074 // lockLater mode; we will decide which of the two to lock down depending 1075 // on where we get the icon from 1076 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1077 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1078 1079 AutoLock<SimpleIconCache>* resultingCacheLocker; 1080 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1081 &resultingCacheLocker, model, mode, size, false); 1082 // Preload finds/creates the appropriate entry, locking down the 1083 // cache it is in and returns the whole state back to here 1084 1085 if (entry == NULL) 1086 return; 1087 1088 ASSERT(entry != NULL); 1089 ASSERT(entry->HaveIconBitmap(mode, size)); 1090 // got the entry, now draw it 1091 resultingCacheLocker->LockedItem()->Draw(entry, view, where, mode, 1092 size, async); 1093 1094 // either of the two cache lockers that got locked down by this call get 1095 // unlocked at this point 1096 } 1097 1098 1099 void 1100 IconCache::SyncDraw(Model* model, BView* view, BPoint where, 1101 IconDrawMode mode, icon_size size, 1102 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1103 void* passThruState) 1104 { 1105 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1106 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1107 1108 AutoLock<SimpleIconCache>* resultingCacheLocker; 1109 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1110 &resultingCacheLocker, model, mode, size, false); 1111 1112 if (entry == NULL) 1113 return; 1114 1115 ASSERT(entry != NULL); 1116 ASSERT(entry->HaveIconBitmap(mode, size)); 1117 resultingCacheLocker->LockedItem()->Draw(entry, view, where, 1118 mode, size, blitFunc, passThruState); 1119 } 1120 1121 1122 void 1123 IconCache::Preload(Model* model, IconDrawMode mode, icon_size size, 1124 bool permanent) 1125 { 1126 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1127 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1128 1129 Preload(&nodeCacheLocker, &sharedCacheLocker, 0, model, mode, size, 1130 permanent); 1131 } 1132 1133 1134 status_t 1135 IconCache::Preload(const char* fileType, IconDrawMode mode, icon_size size) 1136 { 1137 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache); 1138 LazyBitmapAllocator lazyBitmap(size); 1139 1140 BMimeType mime(fileType); 1141 char preferredAppSig[B_MIME_TYPE_LENGTH]; 1142 status_t result = mime.GetPreferredApp(preferredAppSig); 1143 if (result != B_OK) 1144 return result; 1145 1146 // try getting the icon from the preferred app for the signature 1147 IconCacheEntry* entry = GetIconForPreferredApp(fileType, preferredAppSig, 1148 mode, size, &lazyBitmap, 0); 1149 if (entry != NULL) 1150 return B_OK; 1151 1152 // try getting the icon directly from the metamime 1153 result = mime.GetIcon(lazyBitmap.Get(), size); 1154 1155 if (result != B_OK) 1156 return result; 1157 1158 entry = fSharedCache.AddItem(fileType); 1159 BBitmap* bitmap = lazyBitmap.Adopt(); 1160 entry->SetIcon(bitmap, kNormalIcon, size); 1161 if (mode != kNormalIcon) { 1162 entry->ConstructBitmap(mode, size, &lazyBitmap); 1163 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 1164 } 1165 1166 return B_OK; 1167 } 1168 1169 1170 void 1171 IconCache::Deleting(const Model* model) 1172 { 1173 AutoLock<SimpleIconCache> lock(&fNodeCache); 1174 1175 if (model->IconFrom() == kNode) 1176 fNodeCache.Deleting(model->NodeRef()); 1177 1178 // don't care if the node uses the shared cache 1179 } 1180 1181 1182 void 1183 IconCache::Removing(const Model* model) 1184 { 1185 AutoLock<SimpleIconCache> lock(&fNodeCache); 1186 1187 if (model->IconFrom() == kNode) 1188 fNodeCache.Removing(model->NodeRef()); 1189 } 1190 1191 1192 void 1193 IconCache::Deleting(const BView* view) 1194 { 1195 AutoLock<SimpleIconCache> lock(&fNodeCache); 1196 fNodeCache.Deleting(view); 1197 } 1198 1199 1200 void 1201 IconCache::IconChanged(Model* model) 1202 { 1203 AutoLock<SimpleIconCache> lock(&fNodeCache); 1204 1205 if (model->IconFrom() == kNode || model->IconFrom() == kVolume) 1206 fNodeCache.Deleting(model->NodeRef()); 1207 1208 model->ResetIconFrom(); 1209 } 1210 1211 1212 void 1213 IconCache::IconChanged(const char* mimeType, const char* appSignature) 1214 { 1215 AutoLock<SimpleIconCache> sharedLock(&fSharedCache); 1216 SharedCacheEntry* entry = fSharedCache.FindItem(mimeType, appSignature); 1217 if (entry == NULL) 1218 return; 1219 1220 AutoLock<SimpleIconCache> nodeLock(&fNodeCache); 1221 1222 entry = (SharedCacheEntry*)fSharedCache.ResolveIfAlias(entry); 1223 ASSERT(entry != NULL); 1224 1225 fNodeCache.RemoveAliasesTo(entry); 1226 fSharedCache.RemoveAliasesTo(entry); 1227 1228 fSharedCache.IconChanged(entry); 1229 } 1230 1231 1232 BBitmap* 1233 IconCache::MakeSelectedIcon(const BBitmap* normal, icon_size size, 1234 LazyBitmapAllocator* lazyBitmap) 1235 { 1236 return MakeTransformedIcon(normal, size, fHighlightTable, lazyBitmap); 1237 } 1238 1239 1240 #if xDEBUG 1241 static void 1242 DumpBitmap(const BBitmap* bitmap) 1243 { 1244 if (bitmap == NULL) { 1245 printf("NULL bitmap passed to DumpBitmap\n"); 1246 return; 1247 } 1248 int32 length = bitmap->BitsLength(); 1249 1250 printf("data length %ld \n", length); 1251 1252 int32 columns = (int32)bitmap->Bounds().Width() + 1; 1253 const unsigned char* bitPtr = (const unsigned char*)bitmap->Bits(); 1254 for (; length >= 0; length--) { 1255 for (int32 columnIndex = 0; columnIndex < columns; 1256 columnIndex++, length--) 1257 printf("%c%c", "0123456789ABCDEF"[(*bitPtr)/0x10], 1258 "0123456789ABCDEF"[(*bitPtr++)%0x10]); 1259 1260 printf("\n"); 1261 } 1262 printf("\n"); 1263 } 1264 #endif 1265 1266 1267 void 1268 IconCache::InitHighlightTable() 1269 { 1270 // build the color transform tables for different icon modes 1271 BScreen screen(B_MAIN_SCREEN_ID); 1272 rgb_color color; 1273 for (int32 index = 0; index < kColorTransformTableSize; index++) { 1274 color = screen.ColorForIndex((uchar)index); 1275 fHighlightTable[index] = screen.IndexForColor(tint_color(color, 1.3f)); 1276 } 1277 1278 fHighlightTable[B_TRANSPARENT_8_BIT] = B_TRANSPARENT_8_BIT; 1279 fInitHighlightTable = false; 1280 } 1281 1282 1283 BBitmap* 1284 IconCache::MakeTransformedIcon(const BBitmap* source, icon_size /*size*/, 1285 int32 colorTransformTable[], LazyBitmapAllocator* lazyBitmap) 1286 { 1287 if (fInitHighlightTable) 1288 InitHighlightTable(); 1289 1290 BBitmap* result = lazyBitmap->Get(); 1291 uint8* src = (uint8*)source->Bits(); 1292 uint8* dst = (uint8*)result->Bits(); 1293 1294 // ASSERT(result->ColorSpace() == source->ColorSpace() 1295 // && result->Bounds() == source->Bounds()); 1296 if (result->ColorSpace() != source->ColorSpace() 1297 || result->Bounds() != source->Bounds()) { 1298 printf("IconCache::MakeTransformedIcon() - " 1299 "bitmap format mismatch!\n"); 1300 return NULL; 1301 } 1302 1303 switch (result->ColorSpace()) { 1304 case B_RGB32: 1305 case B_RGBA32: { 1306 uint32 width = source->Bounds().IntegerWidth() + 1; 1307 uint32 height = source->Bounds().IntegerHeight() + 1; 1308 uint32 srcBPR = source->BytesPerRow(); 1309 uint32 dstBPR = result->BytesPerRow(); 1310 for (uint32 y = 0; y < height; y++) { 1311 uint8* d = dst; 1312 uint8* s = src; 1313 for (uint32 x = 0; x < width; x++) { 1314 // 66% brightness 1315 d[0] = (int)s[0] * 168 >> 8; 1316 d[1] = (int)s[1] * 168 >> 8; 1317 d[2] = (int)s[2] * 168 >> 8; 1318 d[3] = s[3]; 1319 d += 4; 1320 s += 4; 1321 } 1322 dst += dstBPR; 1323 src += srcBPR; 1324 } 1325 break; 1326 } 1327 1328 case B_CMAP8: { 1329 int32 bitsLength = result->BitsLength(); 1330 for (int32 i = 0; i < bitsLength; i++) 1331 *dst++ = (uint8)colorTransformTable[*src++]; 1332 break; 1333 } 1334 1335 default: 1336 memset(dst, 0, result->BitsLength()); 1337 // unkown colorspace, no tinting for you 1338 // "black" should make the problem stand out 1339 break; 1340 } 1341 1342 return result; 1343 } 1344 1345 1346 bool 1347 IconCache::IconHitTest(BPoint where, const Model* model, IconDrawMode mode, 1348 icon_size size) 1349 { 1350 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1351 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1352 1353 AutoLock<SimpleIconCache>* resultingCacheLocker; 1354 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1355 &resultingCacheLocker, const_cast<Model*>(model), mode, size, false); 1356 // Preload finds/creates the appropriate entry, locking down the 1357 // cache it is in and returns the whole state back to here 1358 1359 if (entry != NULL) 1360 return entry->IconHitTest(where, mode, size); 1361 1362 return false; 1363 } 1364 1365 1366 void 1367 IconCacheEntry::RetireIcons(BObjectList<BBitmap>* retiredBitmapList) 1368 { 1369 if (fLargeIcon != NULL) { 1370 retiredBitmapList->AddItem(fLargeIcon); 1371 fLargeIcon = NULL; 1372 } 1373 if (fHighlightedLargeIcon != NULL) { 1374 retiredBitmapList->AddItem(fHighlightedLargeIcon); 1375 fHighlightedLargeIcon = NULL; 1376 } 1377 if (fMiniIcon != NULL) { 1378 retiredBitmapList->AddItem(fMiniIcon); 1379 fMiniIcon = NULL; 1380 } 1381 if (fHighlightedMiniIcon != NULL) { 1382 retiredBitmapList->AddItem(fHighlightedMiniIcon); 1383 fHighlightedMiniIcon = NULL; 1384 } 1385 1386 int32 count = retiredBitmapList->CountItems(); 1387 if (count > 10 * 1024) { 1388 PRINT(("nuking old icons from the retired bitmap list\n")); 1389 for (count = 512; count > 0; count--) 1390 delete retiredBitmapList->RemoveItemAt(0); 1391 } 1392 } 1393 1394 1395 // #pragma mark - SharedIconCache 1396 1397 1398 SharedIconCache::SharedIconCache() 1399 : 1400 SimpleIconCache("Tracker shared icon cache"), 1401 fHashTable(), 1402 fRetiredBitmaps(256, true) 1403 { 1404 fHashTable.Init(256); 1405 } 1406 1407 1408 void 1409 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1410 IconDrawMode mode, icon_size size, bool async) 1411 { 1412 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, async); 1413 } 1414 1415 1416 void 1417 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1418 IconDrawMode mode, icon_size size, void (*blitFunc)(BView*, BPoint, 1419 BBitmap*, void*), void* passThruState) 1420 { 1421 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, 1422 blitFunc, passThruState); 1423 } 1424 1425 1426 SharedCacheEntry* 1427 SharedIconCache::FindItem(const char* fileType, 1428 const char* appSignature) const 1429 { 1430 ASSERT(fileType); 1431 if (!fileType) 1432 fileType = B_FILE_MIMETYPE; 1433 1434 return fHashTable.Lookup(SharedCacheEntry::TypeAndSignature(fileType, 1435 appSignature)); 1436 } 1437 1438 1439 SharedCacheEntry* 1440 SharedIconCache::AddItem(const char* fileType, const char* appSignature) 1441 { 1442 ASSERT(fileType != NULL); 1443 if (fileType == NULL) 1444 fileType = B_FILE_MIMETYPE; 1445 1446 SharedCacheEntry* entry = new SharedCacheEntry(fileType, appSignature); 1447 if (fHashTable.Insert(entry) == B_OK) 1448 return entry; 1449 1450 delete entry; 1451 return NULL; 1452 } 1453 1454 1455 void 1456 SharedIconCache::IconChanged(SharedCacheEntry* entry) 1457 { 1458 // by now there should be no aliases to entry, just remove entry 1459 // itself 1460 ASSERT(entry->fAliasForIndex == -1); 1461 entry->RetireIcons(&fRetiredBitmaps); 1462 fHashTable.Remove(entry); 1463 } 1464 1465 1466 void 1467 SharedIconCache::RemoveAliasesTo(SharedCacheEntry* alias) 1468 { 1469 EntryHashTable::Iterator it = fHashTable.GetIterator(); 1470 while (it.HasNext()) { 1471 SharedCacheEntry* entry = it.Next(); 1472 if (entry->fAliasTo == alias) 1473 fHashTable.RemoveUnchecked(entry); 1474 } 1475 } 1476 1477 1478 void 1479 SharedIconCache::SetAliasFor(IconCacheEntry* entry, 1480 const SharedCacheEntry* original) const 1481 { 1482 entry->fAliasTo = original; 1483 } 1484 1485 1486 SharedCacheEntry::SharedCacheEntry() 1487 : 1488 fNext(NULL) 1489 { 1490 } 1491 1492 1493 SharedCacheEntry::SharedCacheEntry(const char* fileType, 1494 const char* appSignature) 1495 : 1496 fNext(NULL), 1497 fFileType(fileType), 1498 fAppSignature(appSignature) 1499 { 1500 } 1501 1502 1503 void 1504 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1505 icon_size size, bool async) 1506 { 1507 BBitmap* bitmap = IconForMode(mode, size); 1508 ASSERT(bitmap != NULL); 1509 1510 drawing_mode oldMode = view->DrawingMode(); 1511 1512 if (bitmap->ColorSpace() == B_RGBA32) { 1513 if (oldMode != B_OP_ALPHA) { 1514 view->SetDrawingMode(B_OP_ALPHA); 1515 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1516 } 1517 } else 1518 view->SetDrawingMode(B_OP_OVER); 1519 1520 if (async) 1521 view->DrawBitmapAsync(bitmap, where); 1522 else 1523 view->DrawBitmap(bitmap, where); 1524 1525 view->SetDrawingMode(oldMode); 1526 } 1527 1528 1529 void 1530 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1531 icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1532 void* passThruState) 1533 { 1534 BBitmap* bitmap = IconForMode(mode, size); 1535 if (bitmap == NULL) 1536 return; 1537 1538 (blitFunc)(view, where, bitmap, passThruState); 1539 } 1540 1541 1542 /* static */ size_t 1543 SharedCacheEntry::Hash(const TypeAndSignature& typeAndSignature) 1544 { 1545 size_t hash = HashString(typeAndSignature.type, 0); 1546 if (typeAndSignature.signature != NULL 1547 && *typeAndSignature.signature != '\0') 1548 hash = HashString(typeAndSignature.signature, hash); 1549 1550 return hash; 1551 } 1552 1553 1554 size_t 1555 SharedCacheEntry::Hash() const 1556 { 1557 return Hash(TypeAndSignature(fFileType.String(), fAppSignature.String())); 1558 } 1559 1560 1561 bool 1562 SharedCacheEntry::operator==(const TypeAndSignature& typeAndSignature) const 1563 { 1564 return fFileType == typeAndSignature.type 1565 && fAppSignature == typeAndSignature.signature; 1566 } 1567 1568 1569 // #pragma mark - NodeCacheEntry 1570 1571 1572 NodeCacheEntry::NodeCacheEntry(bool permanent) 1573 : 1574 fNext(NULL), 1575 fPermanent(permanent) 1576 { 1577 } 1578 1579 1580 NodeCacheEntry::NodeCacheEntry(const node_ref* node, bool permanent) 1581 : 1582 fNext(NULL), 1583 fRef(*node), 1584 fPermanent(permanent) 1585 { 1586 } 1587 1588 1589 void 1590 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1591 icon_size size, bool async) 1592 { 1593 BBitmap* bitmap = IconForMode(mode, size); 1594 if (bitmap == NULL) 1595 return; 1596 1597 drawing_mode oldMode = view->DrawingMode(); 1598 1599 if (bitmap->ColorSpace() == B_RGBA32) { 1600 if (oldMode != B_OP_ALPHA) { 1601 view->SetDrawingMode(B_OP_ALPHA); 1602 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1603 } 1604 } else 1605 view->SetDrawingMode(B_OP_OVER); 1606 1607 if (false && async) { 1608 TRESPASS(); 1609 // need to copy the bits first in here 1610 view->DrawBitmapAsync(bitmap, where); 1611 } else 1612 view->DrawBitmap(bitmap, where); 1613 1614 view->SetDrawingMode(oldMode); 1615 } 1616 1617 1618 void 1619 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1620 icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1621 void* passThruState) 1622 { 1623 BBitmap* bitmap = IconForMode(mode, size); 1624 if (bitmap == NULL) 1625 return; 1626 1627 (blitFunc)(view, where, bitmap, passThruState); 1628 } 1629 1630 1631 const node_ref* 1632 NodeCacheEntry::Node() const 1633 { 1634 return &fRef; 1635 } 1636 1637 1638 size_t 1639 NodeCacheEntry::Hash() const 1640 { 1641 return Hash(&fRef); 1642 } 1643 1644 1645 /* static */ size_t 1646 NodeCacheEntry::Hash(const node_ref* node) 1647 { 1648 return node->device ^ ((uint32*)&node->node)[0] 1649 ^ ((uint32*)&node->node)[1]; 1650 } 1651 1652 1653 bool 1654 NodeCacheEntry::operator==(const node_ref* node) const 1655 { 1656 return fRef == *node; 1657 } 1658 1659 1660 bool 1661 NodeCacheEntry::Permanent() const 1662 { 1663 return fPermanent; 1664 } 1665 1666 1667 // #pragma mark - NodeIconCache 1668 1669 1670 NodeIconCache::NodeIconCache() 1671 : 1672 SimpleIconCache("Tracker node icon cache") 1673 { 1674 fHashTable.Init(100); 1675 } 1676 1677 1678 void 1679 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1680 IconDrawMode mode, icon_size size, bool async) 1681 { 1682 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, async); 1683 } 1684 1685 1686 void 1687 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1688 IconDrawMode mode, icon_size size, 1689 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), void* passThruState) 1690 { 1691 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, 1692 blitFunc, passThruState); 1693 } 1694 1695 1696 NodeCacheEntry* 1697 NodeIconCache::FindItem(const node_ref* node) const 1698 { 1699 return fHashTable.Lookup(node); 1700 } 1701 1702 1703 NodeCacheEntry* 1704 NodeIconCache::AddItem(const node_ref* node, bool permanent) 1705 { 1706 NodeCacheEntry* entry = new NodeCacheEntry(node, permanent); 1707 if (fHashTable.Insert(entry) == B_OK) 1708 return entry; 1709 1710 delete entry; 1711 return NULL; 1712 } 1713 1714 1715 void 1716 NodeIconCache::Deleting(const node_ref* node) 1717 { 1718 NodeCacheEntry* entry = FindItem(node); 1719 ASSERT(entry != NULL); 1720 if (entry == NULL || entry->Permanent()) 1721 return; 1722 1723 fHashTable.Remove(entry); 1724 } 1725 1726 1727 void 1728 NodeIconCache::Removing(const node_ref* node) 1729 { 1730 NodeCacheEntry* entry = FindItem(node); 1731 ASSERT(entry != NULL); 1732 if (entry == NULL) 1733 return; 1734 1735 fHashTable.Remove(entry); 1736 } 1737 1738 1739 void 1740 NodeIconCache::Deleting(const BView*) 1741 { 1742 #ifdef NODE_CACHE_ASYNC_DRAWS 1743 TRESPASS(); 1744 #endif 1745 } 1746 1747 1748 void 1749 NodeIconCache::IconChanged(const Model* model) 1750 { 1751 Deleting(model->NodeRef()); 1752 } 1753 1754 1755 void 1756 NodeIconCache::RemoveAliasesTo(SharedCacheEntry* alias) 1757 { 1758 EntryHashTable::Iterator it = fHashTable.GetIterator(); 1759 while (it.HasNext()) { 1760 NodeCacheEntry* entry = it.Next(); 1761 if (entry->fAliasTo == alias) 1762 fHashTable.RemoveUnchecked(entry); 1763 } 1764 } 1765 1766 1767 // #pragma mark - SimpleIconCache 1768 1769 1770 SimpleIconCache::SimpleIconCache(const char* name) 1771 : 1772 fLock(name) 1773 { 1774 } 1775 1776 1777 void 1778 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1779 icon_size, bool) 1780 { 1781 TRESPASS(); 1782 // pure virtual, do nothing 1783 } 1784 1785 1786 void 1787 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1788 icon_size, void(*)(BView*, BPoint, BBitmap*, void*), void*) 1789 { 1790 TRESPASS(); 1791 // pure virtual, do nothing 1792 } 1793 1794 1795 bool 1796 SimpleIconCache::Lock() 1797 { 1798 return fLock.Lock(); 1799 } 1800 1801 1802 void 1803 SimpleIconCache::Unlock() 1804 { 1805 fLock.Unlock(); 1806 } 1807 1808 1809 bool 1810 SimpleIconCache::IsLocked() const 1811 { 1812 return fLock.IsLocked(); 1813 } 1814 1815 1816 // #pragma mark - LazyBitmapAllocator 1817 1818 1819 LazyBitmapAllocator::LazyBitmapAllocator(icon_size size, 1820 color_space colorSpace, bool preallocate) 1821 : 1822 fBitmap(NULL), 1823 fSize(size), 1824 fColorSpace(colorSpace) 1825 { 1826 if (preallocate) 1827 Get(); 1828 } 1829 1830 1831 LazyBitmapAllocator::~LazyBitmapAllocator() 1832 { 1833 delete fBitmap; 1834 } 1835 1836 1837 BBitmap* 1838 LazyBitmapAllocator::Get() 1839 { 1840 if (fBitmap == NULL) 1841 fBitmap = new BBitmap(BRect(0, 0, fSize - 1, fSize - 1), fColorSpace); 1842 1843 return fBitmap; 1844 } 1845 1846 1847 BBitmap* 1848 LazyBitmapAllocator::Adopt() 1849 { 1850 if (fBitmap == NULL) 1851 Get(); 1852 1853 BBitmap* bitmap = fBitmap; 1854 fBitmap = NULL; 1855 1856 return bitmap; 1857 } 1858 1859 1860 IconCache* IconCache::sIconCache; 1861