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(fAliasTo != NULL); 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 PRINT_DISK_HITS(("File %s; Line %d # hitting disk for node %s\n", 777 __FILE__, __LINE__, model->Name())); 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 783 BFile* file = NULL; 784 status_t result = B_ERROR; 785 if (model->IsExecutable() 786 && (file = dynamic_cast<BFile*>(model->Node())) != NULL) { 787 result = GetAppIconFromAttr(file, lazyBitmap->Get(), size); 788 } else 789 result = GetFileIconFromAttr(model, 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 } else if (result == B_BUSY) { 805 // still waiting for thumbnail icon to be generated, 806 // provide a hint to come back here for it 807 source = kNode; 808 } 809 } 810 811 if (entry == NULL) { 812 (*resultingOpenCache)->Unlock(); 813 *resultingOpenCache = NULL; 814 } else if (!entry->HaveIconBitmap(mode, size) 815 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 816 entry->ConstructBitmap(mode, size, lazyBitmap); 817 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 818 ASSERT(entry->HaveIconBitmap(mode, size)); 819 } 820 821 return entry; 822 } 823 824 825 IconCacheEntry* 826 IconCache::GetGenericIcon(AutoLock<SimpleIconCache>* sharedCacheLocker, 827 AutoLock<SimpleIconCache>** resultingOpenCache, 828 Model* model, IconSource &source, 829 IconDrawMode mode, icon_size size, 830 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 831 { 832 *resultingOpenCache = sharedCacheLocker; 833 (*resultingOpenCache)->Lock(); 834 835 entry = GetIconFromMetaMime(B_FILE_MIMETYPE, mode, size, lazyBitmap, 0); 836 if (entry == NULL) 837 return NULL; 838 839 // make an aliased entry so that the next time we get a 840 // hit and substitute a generic icon right away 841 PRINT_ADD_ITEM( 842 ("File %s; Line %d # adding entry for preferredApp %s, type %s\n", 843 __FILE__, __LINE__, model->PreferredAppSignature(), 844 model->MimeType())); 845 IconCacheEntry* aliasedEntry = fSharedCache.AddItem( 846 model->MimeType(), model->PreferredAppSignature()); 847 aliasedEntry->SetAliasFor(&fSharedCache, (SharedCacheEntry*)entry); 848 849 source = kMetaMime; 850 851 ASSERT(entry->HaveIconBitmap(mode, size)); 852 853 return entry; 854 } 855 856 857 IconCacheEntry* 858 IconCache::GetFallbackIcon(AutoLock<SimpleIconCache>* sharedCacheLocker, 859 AutoLock<SimpleIconCache>** resultingOpenCache, 860 Model* model, IconDrawMode mode, icon_size size, 861 LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry) 862 { 863 *resultingOpenCache = sharedCacheLocker; 864 (*resultingOpenCache)->Lock(); 865 866 entry = fSharedCache.AddItem(model->MimeType(), 867 model->PreferredAppSignature()); 868 869 BBitmap* bitmap = lazyBitmap->Get(); 870 GetTrackerResources()->GetIconResource(R_FileIcon, size, bitmap); 871 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 872 873 if (mode != kNormalIcon) { 874 entry->ConstructBitmap(mode, size, lazyBitmap); 875 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 876 } 877 878 ASSERT(entry->HaveIconBitmap(mode, size)); 879 880 return entry; 881 } 882 883 884 IconCacheEntry* 885 IconCache::Preload(AutoLock<SimpleIconCache>* nodeCacheLocker, 886 AutoLock<SimpleIconCache>* sharedCacheLocker, 887 AutoLock<SimpleIconCache>** resultingCache, 888 Model* model, IconDrawMode mode, icon_size size, 889 bool permanent) 890 { 891 IconCacheEntry* entry = NULL; 892 893 AutoLock<SimpleIconCache>* resultingOpenCache = NULL; 894 // resultingOpenCache is the locker that points to the cache that 895 // ended with a hit and will be used for the drawing 896 897 { 898 // scope for modelOpener 899 900 ModelNodeLazyOpener modelOpener(model); 901 // this opener takes care of opening the model and possibly 902 // closing it when we are done 903 LazyBitmapAllocator lazyBitmap(size); 904 // lazyBitmap manages bitmap allocation and freeing if needed 905 906 IconSource source = model->IconFrom(); 907 if (source == kUnknownSource || source == kUnknownNotFromNode) { 908 // fish for special first models and handle them appropriately 909 if (model->IsVolume()) { 910 // volume may use specialized icon in the volume node 911 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 912 &resultingOpenCache, model, source, mode, size, 913 &lazyBitmap, entry, permanent); 914 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 915 // look for volume defined icon 916 entry = GetVolumeIcon(nodeCacheLocker, sharedCacheLocker, 917 &resultingOpenCache, model, source, mode, 918 size, &lazyBitmap); 919 } 920 } else if (model->IsRoot()) { 921 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 922 &resultingOpenCache, model, source, mode, size, 923 &lazyBitmap); 924 ASSERT(entry != NULL); 925 } else { 926 if (source == kUnknownSource) { 927 // look for node icons first 928 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 929 &resultingOpenCache, model, source, 930 mode, size, &lazyBitmap, entry, permanent); 931 } 932 933 if (entry == NULL) { 934 // no node icon, look for file type based one 935 modelOpener.OpenNode(); 936 // use file types to get the icon 937 resultingOpenCache = sharedCacheLocker; 938 resultingOpenCache->Lock(); 939 940 entry = GetIconFromFileTypes(&modelOpener, source, mode, 941 size, &lazyBitmap, 0); 942 if (entry == NULL) { 943 // we don't have an icon, go with the generic 944 entry = GetGenericIcon(sharedCacheLocker, 945 &resultingOpenCache, model, source, mode, 946 size, &lazyBitmap, entry); 947 } 948 } 949 } 950 951 // update the icon source 952 model->SetIconFrom(source); 953 } else { 954 // we already know where the icon should come from, 955 // use shortcuts to get it 956 switch (source) { 957 case kNode: 958 resultingOpenCache = nodeCacheLocker; 959 resultingOpenCache->Lock(); 960 961 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 962 &resultingOpenCache, model, source, mode, 963 size, &lazyBitmap, entry, permanent); 964 if (entry != NULL) { 965 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, 966 entry); 967 if (!entry->HaveIconBitmap(mode, size) 968 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 969 entry->ConstructBitmap(mode, size, &lazyBitmap); 970 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 971 } 972 ASSERT(entry->HaveIconBitmap(mode, size)); 973 } 974 break; 975 case kTrackerSupplied: 976 if (model->IsRoot()) { 977 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 978 &resultingOpenCache, model, source, mode, size, 979 &lazyBitmap); 980 break; 981 } else { 982 entry = GetWellKnownIcon(nodeCacheLocker, 983 sharedCacheLocker, &resultingOpenCache, model, 984 source, mode, size, &lazyBitmap); 985 if (entry != NULL) 986 break; 987 } 988 // fall through 989 case kTrackerDefault: 990 case kVolume: 991 if (model->IsVolume()) { 992 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 993 &resultingOpenCache, model, source, 994 mode, size, &lazyBitmap, entry, permanent); 995 if (entry == NULL 996 || !entry->HaveIconBitmap(mode, size)) { 997 entry = GetVolumeIcon(nodeCacheLocker, 998 sharedCacheLocker, &resultingOpenCache, model, 999 source, mode, size, &lazyBitmap); 1000 } 1001 break; 1002 } 1003 // fall through 1004 case kMetaMime: 1005 case kPreferredAppForType: 1006 case kPreferredAppForNode: 1007 resultingOpenCache = sharedCacheLocker; 1008 resultingOpenCache->Lock(); 1009 1010 entry = GetIconFromFileTypes(&modelOpener, source, mode, 1011 size, &lazyBitmap, 0); 1012 1013 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1014 // we don't have an icon, go with the generic 1015 entry = GetGenericIcon(sharedCacheLocker, 1016 &resultingOpenCache, model, source, mode, size, 1017 &lazyBitmap, entry); 1018 } 1019 1020 model->SetIconFrom(source); 1021 // The source shouldn't change in this case; if it does 1022 // though we might never be hitting the correct icon and 1023 // instead keep leaking entries after each miss this now 1024 // happens if an app defines an icon but a 1025 // GetIconForType() fails and we fall back to generic 1026 // icon. 1027 // ToDo: fix this and add an assert to the effect 1028 1029 ASSERT(entry != NULL); 1030 ASSERT(entry->HaveIconBitmap(mode, size)); 1031 break; 1032 1033 default: 1034 TRESPASS(); 1035 break; 1036 } 1037 } 1038 1039 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1040 // we don't have an icon, go with the generic 1041 PRINT( 1042 ("icon cache complete miss, falling back on generic icon " 1043 "for %s\n", model->Name())); 1044 entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache, 1045 model, source, mode, size, &lazyBitmap, entry); 1046 1047 // we don't even have generic, something is really broken, 1048 // go with hardcoded generic icon 1049 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1050 PRINT( 1051 ("icon cache complete miss, falling back on generic " 1052 "icon for %s\n", model->Name())); 1053 entry = GetFallbackIcon(sharedCacheLocker, 1054 &resultingOpenCache, model, mode, size, &lazyBitmap, 1055 entry); 1056 } 1057 1058 // force icon pick up next time around because we probably just 1059 // hit a node in transition 1060 model->SetIconFrom(kUnknownSource); 1061 } 1062 } 1063 1064 ASSERT(entry != NULL && entry->HaveIconBitmap(mode, size)); 1065 1066 if (resultingCache != NULL) 1067 *resultingCache = resultingOpenCache; 1068 1069 return entry; 1070 } 1071 1072 1073 void 1074 IconCache::Draw(Model* model, BView* view, BPoint where, IconDrawMode mode, 1075 icon_size size, bool async) 1076 { 1077 // the following does not actually lock the caches, we are using the 1078 // lockLater mode; we will decide which of the two to lock down depending 1079 // on where we get the icon from 1080 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1081 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1082 1083 AutoLock<SimpleIconCache>* resultingCacheLocker; 1084 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1085 &resultingCacheLocker, model, mode, size, false); 1086 // Preload finds/creates the appropriate entry, locking down the 1087 // cache it is in and returns the whole state back to here 1088 1089 if (entry == NULL) 1090 return; 1091 1092 ASSERT(entry != NULL); 1093 ASSERT(entry->HaveIconBitmap(mode, size)); 1094 // got the entry, now draw it 1095 resultingCacheLocker->LockedItem()->Draw(entry, view, where, mode, 1096 size, async); 1097 1098 // either of the two cache lockers that got locked down by this call get 1099 // unlocked at this point 1100 } 1101 1102 1103 void 1104 IconCache::SyncDraw(Model* model, BView* view, BPoint where, 1105 IconDrawMode mode, icon_size size, 1106 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1107 void* passThruState) 1108 { 1109 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1110 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1111 1112 AutoLock<SimpleIconCache>* resultingCacheLocker; 1113 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1114 &resultingCacheLocker, model, mode, size, false); 1115 1116 if (entry == NULL) 1117 return; 1118 1119 ASSERT(entry != NULL); 1120 ASSERT(entry->HaveIconBitmap(mode, size)); 1121 resultingCacheLocker->LockedItem()->Draw(entry, view, where, 1122 mode, size, blitFunc, passThruState); 1123 } 1124 1125 1126 void 1127 IconCache::Preload(Model* model, IconDrawMode mode, icon_size size, 1128 bool permanent) 1129 { 1130 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1131 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1132 1133 Preload(&nodeCacheLocker, &sharedCacheLocker, 0, model, mode, size, 1134 permanent); 1135 } 1136 1137 1138 status_t 1139 IconCache::Preload(const char* fileType, IconDrawMode mode, icon_size size) 1140 { 1141 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache); 1142 LazyBitmapAllocator lazyBitmap(size); 1143 1144 BMimeType mime(fileType); 1145 char preferredAppSig[B_MIME_TYPE_LENGTH]; 1146 status_t result = mime.GetPreferredApp(preferredAppSig); 1147 if (result != B_OK) 1148 return result; 1149 1150 // try getting the icon from the preferred app for the signature 1151 IconCacheEntry* entry = GetIconForPreferredApp(fileType, preferredAppSig, 1152 mode, size, &lazyBitmap, 0); 1153 if (entry != NULL) 1154 return B_OK; 1155 1156 // try getting the icon directly from the metamime 1157 result = mime.GetIcon(lazyBitmap.Get(), size); 1158 1159 if (result != B_OK) 1160 return result; 1161 1162 entry = fSharedCache.AddItem(fileType); 1163 BBitmap* bitmap = lazyBitmap.Adopt(); 1164 entry->SetIcon(bitmap, kNormalIcon, size); 1165 if (mode != kNormalIcon) { 1166 entry->ConstructBitmap(mode, size, &lazyBitmap); 1167 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 1168 } 1169 1170 return B_OK; 1171 } 1172 1173 1174 void 1175 IconCache::Deleting(const Model* model) 1176 { 1177 AutoLock<SimpleIconCache> lock(&fNodeCache); 1178 1179 if (model->IconFrom() == kNode) 1180 fNodeCache.Deleting(model->NodeRef()); 1181 1182 // don't care if the node uses the shared cache 1183 } 1184 1185 1186 void 1187 IconCache::Removing(const Model* model) 1188 { 1189 AutoLock<SimpleIconCache> lock(&fNodeCache); 1190 1191 if (model->IconFrom() == kNode) 1192 fNodeCache.Removing(model->NodeRef()); 1193 } 1194 1195 1196 void 1197 IconCache::Deleting(const BView* view) 1198 { 1199 AutoLock<SimpleIconCache> lock(&fNodeCache); 1200 fNodeCache.Deleting(view); 1201 } 1202 1203 1204 void 1205 IconCache::IconChanged(Model* model) 1206 { 1207 AutoLock<SimpleIconCache> lock(&fNodeCache); 1208 1209 if (model->IconFrom() == kNode || model->IconFrom() == kVolume) 1210 fNodeCache.Deleting(model->NodeRef()); 1211 1212 model->ResetIconFrom(); 1213 } 1214 1215 1216 void 1217 IconCache::IconChanged(const char* mimeType, const char* appSignature) 1218 { 1219 AutoLock<SimpleIconCache> sharedLock(&fSharedCache); 1220 SharedCacheEntry* entry = fSharedCache.FindItem(mimeType, appSignature); 1221 if (entry == NULL) 1222 return; 1223 1224 AutoLock<SimpleIconCache> nodeLock(&fNodeCache); 1225 1226 entry = (SharedCacheEntry*)fSharedCache.ResolveIfAlias(entry); 1227 ASSERT(entry != NULL); 1228 1229 fNodeCache.RemoveAliasesTo(entry); 1230 fSharedCache.RemoveAliasesTo(entry); 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 SharedIconCache::SharedIconCache() 1403 : 1404 SimpleIconCache("Tracker shared icon cache"), 1405 fHashTable(), 1406 fRetiredBitmaps(256, true) 1407 { 1408 fHashTable.Init(256); 1409 } 1410 1411 1412 void 1413 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1414 IconDrawMode mode, icon_size size, bool async) 1415 { 1416 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, async); 1417 } 1418 1419 1420 void 1421 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1422 IconDrawMode mode, icon_size size, void (*blitFunc)(BView*, BPoint, 1423 BBitmap*, void*), void* passThruState) 1424 { 1425 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, 1426 blitFunc, passThruState); 1427 } 1428 1429 1430 SharedCacheEntry* 1431 SharedIconCache::FindItem(const char* fileType, 1432 const char* appSignature) const 1433 { 1434 ASSERT(fileType); 1435 if (!fileType) 1436 fileType = B_FILE_MIMETYPE; 1437 1438 return fHashTable.Lookup(SharedCacheEntry::TypeAndSignature(fileType, 1439 appSignature)); 1440 } 1441 1442 1443 SharedCacheEntry* 1444 SharedIconCache::AddItem(const char* fileType, const char* appSignature) 1445 { 1446 ASSERT(fileType != NULL); 1447 if (fileType == NULL) 1448 fileType = B_FILE_MIMETYPE; 1449 1450 SharedCacheEntry* entry = new SharedCacheEntry(fileType, appSignature); 1451 if (fHashTable.Insert(entry) == B_OK) 1452 return entry; 1453 1454 delete entry; 1455 return NULL; 1456 } 1457 1458 1459 void 1460 SharedIconCache::IconChanged(SharedCacheEntry* entry) 1461 { 1462 // by now there should be no aliases to entry, just remove entry 1463 // itself 1464 ASSERT(entry->fAliasTo == NULL); 1465 entry->RetireIcons(&fRetiredBitmaps); 1466 fHashTable.Remove(entry); 1467 } 1468 1469 1470 void 1471 SharedIconCache::RemoveAliasesTo(SharedCacheEntry* alias) 1472 { 1473 EntryHashTable::Iterator it = fHashTable.GetIterator(); 1474 while (it.HasNext()) { 1475 SharedCacheEntry* entry = it.Next(); 1476 if (entry->fAliasTo == alias) 1477 fHashTable.RemoveUnchecked(entry); 1478 } 1479 } 1480 1481 1482 void 1483 SharedIconCache::SetAliasFor(IconCacheEntry* entry, 1484 const SharedCacheEntry* original) const 1485 { 1486 entry->fAliasTo = original; 1487 } 1488 1489 1490 SharedCacheEntry::SharedCacheEntry() 1491 : 1492 fNext(NULL) 1493 { 1494 } 1495 1496 1497 SharedCacheEntry::SharedCacheEntry(const char* fileType, 1498 const char* appSignature) 1499 : 1500 fNext(NULL), 1501 fFileType(fileType), 1502 fAppSignature(appSignature) 1503 { 1504 } 1505 1506 1507 void 1508 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1509 icon_size size, bool async) 1510 { 1511 BBitmap* bitmap = IconForMode(mode, size); 1512 ASSERT(bitmap != NULL); 1513 1514 drawing_mode oldMode = view->DrawingMode(); 1515 1516 if (bitmap->ColorSpace() == B_RGBA32) { 1517 if (oldMode != B_OP_ALPHA) { 1518 view->SetDrawingMode(B_OP_ALPHA); 1519 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1520 } 1521 } else 1522 view->SetDrawingMode(B_OP_OVER); 1523 1524 if (async) 1525 view->DrawBitmapAsync(bitmap, where); 1526 else 1527 view->DrawBitmap(bitmap, where); 1528 1529 view->SetDrawingMode(oldMode); 1530 } 1531 1532 1533 void 1534 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1535 icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1536 void* passThruState) 1537 { 1538 BBitmap* bitmap = IconForMode(mode, size); 1539 if (bitmap == NULL) 1540 return; 1541 1542 (blitFunc)(view, where, bitmap, passThruState); 1543 } 1544 1545 1546 /* static */ size_t 1547 SharedCacheEntry::Hash(const TypeAndSignature& typeAndSignature) 1548 { 1549 size_t hash = HashString(typeAndSignature.type, 0); 1550 if (typeAndSignature.signature != NULL 1551 && *typeAndSignature.signature != '\0') 1552 hash = HashString(typeAndSignature.signature, hash); 1553 1554 return hash; 1555 } 1556 1557 1558 size_t 1559 SharedCacheEntry::Hash() const 1560 { 1561 return Hash(TypeAndSignature(fFileType.String(), fAppSignature.String())); 1562 } 1563 1564 1565 bool 1566 SharedCacheEntry::operator==(const TypeAndSignature& typeAndSignature) const 1567 { 1568 return fFileType == typeAndSignature.type 1569 && fAppSignature == typeAndSignature.signature; 1570 } 1571 1572 1573 // #pragma mark - NodeCacheEntry 1574 1575 1576 NodeCacheEntry::NodeCacheEntry(bool permanent) 1577 : 1578 fNext(NULL), 1579 fPermanent(permanent) 1580 { 1581 } 1582 1583 1584 NodeCacheEntry::NodeCacheEntry(const node_ref* node, bool permanent) 1585 : 1586 fNext(NULL), 1587 fRef(*node), 1588 fPermanent(permanent) 1589 { 1590 } 1591 1592 1593 void 1594 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1595 icon_size size, bool async) 1596 { 1597 BBitmap* bitmap = IconForMode(mode, size); 1598 if (bitmap == NULL) 1599 return; 1600 1601 drawing_mode oldMode = view->DrawingMode(); 1602 1603 if (bitmap->ColorSpace() == B_RGBA32) { 1604 if (oldMode != B_OP_ALPHA) { 1605 view->SetDrawingMode(B_OP_ALPHA); 1606 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1607 } 1608 } else 1609 view->SetDrawingMode(B_OP_OVER); 1610 1611 if (false && async) { 1612 TRESPASS(); 1613 // need to copy the bits first in here 1614 view->DrawBitmapAsync(bitmap, where); 1615 } else 1616 view->DrawBitmap(bitmap, where); 1617 1618 view->SetDrawingMode(oldMode); 1619 } 1620 1621 1622 void 1623 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1624 icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1625 void* passThruState) 1626 { 1627 BBitmap* bitmap = IconForMode(mode, size); 1628 if (bitmap == NULL) 1629 return; 1630 1631 (blitFunc)(view, where, bitmap, passThruState); 1632 } 1633 1634 1635 const node_ref* 1636 NodeCacheEntry::Node() const 1637 { 1638 return &fRef; 1639 } 1640 1641 1642 size_t 1643 NodeCacheEntry::Hash() const 1644 { 1645 return Hash(&fRef); 1646 } 1647 1648 1649 /* static */ size_t 1650 NodeCacheEntry::Hash(const node_ref* node) 1651 { 1652 return node->device ^ ((uint32*)&node->node)[0] 1653 ^ ((uint32*)&node->node)[1]; 1654 } 1655 1656 1657 bool 1658 NodeCacheEntry::operator==(const node_ref* node) const 1659 { 1660 return fRef == *node; 1661 } 1662 1663 1664 bool 1665 NodeCacheEntry::Permanent() const 1666 { 1667 return fPermanent; 1668 } 1669 1670 1671 // #pragma mark - NodeIconCache 1672 1673 1674 NodeIconCache::NodeIconCache() 1675 : 1676 SimpleIconCache("Tracker node icon cache") 1677 { 1678 fHashTable.Init(100); 1679 } 1680 1681 1682 void 1683 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1684 IconDrawMode mode, icon_size size, bool async) 1685 { 1686 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, async); 1687 } 1688 1689 1690 void 1691 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1692 IconDrawMode mode, icon_size size, 1693 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), void* passThruState) 1694 { 1695 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, 1696 blitFunc, passThruState); 1697 } 1698 1699 1700 NodeCacheEntry* 1701 NodeIconCache::FindItem(const node_ref* node) const 1702 { 1703 return fHashTable.Lookup(node); 1704 } 1705 1706 1707 NodeCacheEntry* 1708 NodeIconCache::AddItem(const node_ref* node, bool permanent) 1709 { 1710 NodeCacheEntry* entry = new NodeCacheEntry(node, permanent); 1711 if (fHashTable.Insert(entry) == B_OK) 1712 return entry; 1713 1714 delete entry; 1715 return NULL; 1716 } 1717 1718 1719 void 1720 NodeIconCache::Deleting(const node_ref* node) 1721 { 1722 NodeCacheEntry* entry = FindItem(node); 1723 ASSERT(entry != NULL); 1724 if (entry == NULL || entry->Permanent()) 1725 return; 1726 1727 fHashTable.Remove(entry); 1728 } 1729 1730 1731 void 1732 NodeIconCache::Removing(const node_ref* node) 1733 { 1734 NodeCacheEntry* entry = FindItem(node); 1735 ASSERT(entry != NULL); 1736 if (entry == NULL) 1737 return; 1738 1739 fHashTable.Remove(entry); 1740 } 1741 1742 1743 void 1744 NodeIconCache::Deleting(const BView*) 1745 { 1746 #ifdef NODE_CACHE_ASYNC_DRAWS 1747 TRESPASS(); 1748 #endif 1749 } 1750 1751 1752 void 1753 NodeIconCache::IconChanged(const Model* model) 1754 { 1755 Deleting(model->NodeRef()); 1756 } 1757 1758 1759 void 1760 NodeIconCache::RemoveAliasesTo(SharedCacheEntry* alias) 1761 { 1762 EntryHashTable::Iterator it = fHashTable.GetIterator(); 1763 while (it.HasNext()) { 1764 NodeCacheEntry* entry = it.Next(); 1765 if (entry->fAliasTo == alias) 1766 fHashTable.RemoveUnchecked(entry); 1767 } 1768 } 1769 1770 1771 // #pragma mark - SimpleIconCache 1772 1773 1774 SimpleIconCache::SimpleIconCache(const char* name) 1775 : 1776 fLock(name) 1777 { 1778 } 1779 1780 1781 void 1782 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1783 icon_size, bool) 1784 { 1785 TRESPASS(); 1786 // pure virtual, do nothing 1787 } 1788 1789 1790 void 1791 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1792 icon_size, void(*)(BView*, BPoint, BBitmap*, void*), void*) 1793 { 1794 TRESPASS(); 1795 // pure virtual, do nothing 1796 } 1797 1798 1799 bool 1800 SimpleIconCache::Lock() 1801 { 1802 return fLock.Lock(); 1803 } 1804 1805 1806 void 1807 SimpleIconCache::Unlock() 1808 { 1809 fLock.Unlock(); 1810 } 1811 1812 1813 bool 1814 SimpleIconCache::IsLocked() const 1815 { 1816 return fLock.IsLocked(); 1817 } 1818 1819 1820 // #pragma mark - LazyBitmapAllocator 1821 1822 1823 LazyBitmapAllocator::LazyBitmapAllocator(icon_size size, 1824 color_space colorSpace, bool preallocate) 1825 : 1826 fBitmap(NULL), 1827 fSize(size), 1828 fColorSpace(colorSpace) 1829 { 1830 if (preallocate) 1831 Get(); 1832 } 1833 1834 1835 LazyBitmapAllocator::~LazyBitmapAllocator() 1836 { 1837 delete fBitmap; 1838 } 1839 1840 1841 BBitmap* 1842 LazyBitmapAllocator::Get() 1843 { 1844 if (fBitmap == NULL) 1845 fBitmap = new BBitmap(BRect(0, 0, fSize - 1, fSize - 1), fColorSpace); 1846 1847 return fBitmap; 1848 } 1849 1850 1851 BBitmap* 1852 LazyBitmapAllocator::Adopt() 1853 { 1854 if (fBitmap == NULL) 1855 Get(); 1856 1857 BBitmap* bitmap = fBitmap; 1858 fBitmap = NULL; 1859 1860 return bitmap; 1861 } 1862 1863 1864 IconCache* IconCache::sIconCache; 1865