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