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