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