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