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