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