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 // try getting the icon directly from the metamime 390 if (mime.GetIcon(lazyBitmap->Get(), size) != B_OK) { 391 // try getting it from the preferred app of this type 392 char preferredAppSig[B_MIME_TYPE_LENGTH]; 393 if (mime.GetPreferredApp(preferredAppSig) != B_OK) 394 return NULL; 395 396 SharedCacheEntry *aliasTo = NULL; 397 if (entry) 398 aliasTo = (SharedCacheEntry *)entry->ResolveIfAlias(&fSharedCache); 399 400 // look for icon defined by preferred app from metamime 401 aliasTo = (SharedCacheEntry *)GetIconForPreferredApp(fileType, 402 preferredAppSig, mode, size, lazyBitmap, aliasTo); 403 404 if (aliasTo == NULL) 405 return NULL; 406 407 // make an aliased entry so that the next time we get a 408 // hit on the first FindItem in here 409 if (!entry) { 410 PRINT_ADD_ITEM(("File %s; Line %d # adding entry as alias for type %s\n", 411 __FILE__, __LINE__, fileType)); 412 entry = fSharedCache.AddItem(&aliasTo, fileType); 413 entry->SetAliasFor(&fSharedCache, aliasTo); 414 } 415 ASSERT(aliasTo->HaveIconBitmap(mode, size)); 416 return aliasTo; 417 } 418 419 // at this point, we've found an icon for the MIME type 420 BBitmap *bitmap = lazyBitmap->Adopt(); 421 if (!entry) { 422 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for type %s\n", 423 __FILE__, __LINE__, fileType)); 424 entry = fSharedCache.AddItem(fileType); 425 } 426 entry->SetIcon(bitmap, kNormalIcon, size); 427 } 428 429 ASSERT(entry); 430 if (mode != kNormalIcon 431 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 432 entry->ConstructBitmap(mode, size, lazyBitmap); 433 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 434 } 435 436 #if xDEBUG 437 if (!entry->HaveIconBitmap(mode, size)) 438 PRINT(("failing on %s, mode %ld, size %ld\n", fileType, mode, size)); 439 #endif 440 441 ASSERT(entry->HaveIconBitmap(mode, size)); 442 return entry; 443 } 444 445 446 IconCacheEntry * 447 IconCache::GetIconFromFileTypes(ModelNodeLazyOpener *modelOpener, 448 IconSource &source, IconDrawMode mode, icon_size size, 449 LazyBitmapAllocator *lazyBitmap, IconCacheEntry *entry) 450 { 451 ASSERT(fSharedCache.IsLocked()); 452 // use file types to get the icon 453 Model *model = modelOpener->TargetModel(); 454 455 const char *fileType = model->MimeType(); 456 const char *nodePreferredApp = model->PreferredAppSignature(); 457 if (source == kUnknownSource || source == kUnknownNotFromNode 458 || source == kPreferredAppForNode) { 459 460 if (nodePreferredApp[0]) { 461 // file has a locally set preferred app, try getting an icon from 462 // there 463 entry = GetIconForPreferredApp(fileType, nodePreferredApp, mode, 464 size, lazyBitmap, entry); 465 #if xDEBUG 466 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n", 467 __FILE__, __LINE__, nodePreferredApp, fileType, entry)); 468 #endif 469 if (entry) { 470 source = kPreferredAppForNode; 471 ASSERT(entry->HaveIconBitmap(mode, size)); 472 return entry; 473 } 474 } 475 if (source == kPreferredAppForNode) 476 source = kUnknownSource; 477 } 478 479 entry = GetIconFromMetaMime(fileType, mode, size, lazyBitmap, entry); 480 if (!entry) { 481 // Try getting a supertype handler icon 482 BMimeType mime(fileType); 483 if (!mime.IsSupertypeOnly()) { 484 BMimeType superType; 485 mime.GetSupertype(&superType); 486 const char *superTypeFileType = superType.Type(); 487 if (superTypeFileType) 488 entry = GetIconFromMetaMime(superTypeFileType, mode, size, 489 lazyBitmap, entry); 490 #if DEBUG 491 else 492 PRINT(("File %s; Line %d # failed to get supertype for type %s\n", 493 __FILE__, __LINE__, fileType)); 494 #endif 495 } 496 } 497 ASSERT(!entry || entry->HaveIconBitmap(mode, size)); 498 if (entry) { 499 if (nodePreferredApp[0]) { 500 // we got a miss using GetIconForPreferredApp before, cache this 501 // fileType/preferredApp combo with an aliased entry 502 503 // make an aliased entry so that the next time we get a 504 // hit and substitute a generic icon right away 505 506 PRINT_ADD_ITEM(("File %s; Line %d # adding entry as alias for preferredApp %s, type %s\n", 507 __FILE__, __LINE__, nodePreferredApp, fileType)); 508 IconCacheEntry *aliasedEntry = fSharedCache.AddItem((SharedCacheEntry **)&entry, 509 fileType, nodePreferredApp); 510 aliasedEntry->SetAliasFor(&fSharedCache, (SharedCacheEntry *)entry); 511 // OK to cast here, have a runtime check 512 source = kPreferredAppForNode; 513 // set source as preferred for node, so that next time we get a hit in 514 // the initial find that uses GetIconForPreferredApp 515 } else 516 source = kMetaMime; 517 #if DEBUG 518 if (!entry->HaveIconBitmap(mode, size)) 519 model->PrintToStream(); 520 #endif 521 ASSERT(entry->HaveIconBitmap(mode, size)); 522 } 523 return entry; 524 } 525 526 IconCacheEntry * 527 IconCache::GetVolumeIcon(AutoLock<SimpleIconCache> *nodeCacheLocker, 528 AutoLock<SimpleIconCache> *sharedCacheLocker, 529 AutoLock<SimpleIconCache> **resultingOpenCache, 530 Model *model, IconSource &source, 531 IconDrawMode mode, icon_size size, LazyBitmapAllocator *lazyBitmap) 532 { 533 *resultingOpenCache = nodeCacheLocker; 534 nodeCacheLocker->Lock(); 535 536 IconCacheEntry *entry = 0; 537 if (source != kUnknownSource) { 538 // cached in the node cache 539 entry = fNodeCache.FindItem(model->NodeRef()); 540 if (entry) { 541 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, entry); 542 543 if (source == kTrackerDefault) { 544 // if tracker default, resolved entry is from shared cache 545 // this could be done a little cleaner if entry had a way to reach 546 // the cache it is in 547 *resultingOpenCache = sharedCacheLocker; 548 sharedCacheLocker->Lock(); 549 } 550 551 if (entry->HaveIconBitmap(mode, size)) 552 return entry; 553 } 554 } 555 556 // try getting using the BVolume::GetIcon call; if miss, 557 // go for the default mime based icon 558 if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 559 BVolume volume(model->NodeRef()->device); 560 561 if (volume.IsShared()) { 562 // Check if it's a network share and give it a special icon 563 BBitmap *bitmap = lazyBitmap->Get(); 564 GetTrackerResources()->GetIconResource(kResShareIcon, size, bitmap); 565 if (!entry) { 566 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for model %s\n", 567 __FILE__, __LINE__, model->Name())); 568 entry = fNodeCache.AddItem(model->NodeRef()); 569 } 570 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 571 } else if (volume.GetIcon(lazyBitmap->Get(), size) == B_OK) { 572 // Ask the device for an icon 573 BBitmap *bitmap = lazyBitmap->Adopt(); 574 ASSERT(bitmap); 575 if (!entry) { 576 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for model %s\n", 577 __FILE__, __LINE__, model->Name())); 578 entry = fNodeCache.AddItem(model->NodeRef()); 579 } 580 ASSERT(entry); 581 entry->SetIcon(bitmap, kNormalIcon, size); 582 source = kVolume; 583 } else { 584 *resultingOpenCache = sharedCacheLocker; 585 sharedCacheLocker->Lock(); 586 587 // If the volume doesnt have a device it should have the generic icon 588 entry = GetIconFromMetaMime(B_VOLUME_MIMETYPE, mode, 589 size, lazyBitmap, entry); 590 } 591 } 592 593 if (mode != kNormalIcon 594 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 595 entry->ConstructBitmap(mode, size, lazyBitmap); 596 entry->SetIcon(lazyBitmap->Adopt(), mode, size); 597 } 598 return entry; 599 } 600 601 602 IconCacheEntry * 603 IconCache::GetRootIcon(AutoLock<SimpleIconCache> *, 604 AutoLock<SimpleIconCache> *sharedCacheLocker, 605 AutoLock<SimpleIconCache> **resultingOpenCache, 606 Model *, IconSource &source, IconDrawMode mode, 607 icon_size size, LazyBitmapAllocator *lazyBitmap) 608 { 609 *resultingOpenCache = sharedCacheLocker; 610 (*resultingOpenCache)->Lock(); 611 612 source = kTrackerSupplied; 613 return GetIconFromMetaMime(B_ROOT_MIMETYPE, mode, size, lazyBitmap, 0); 614 } 615 616 617 IconCacheEntry * 618 IconCache::GetWellKnownIcon(AutoLock<SimpleIconCache> *, 619 AutoLock<SimpleIconCache> *sharedCacheLocker, 620 AutoLock<SimpleIconCache> **resultingOpenCache, 621 Model *model, IconSource &source, IconDrawMode mode, icon_size size, 622 LazyBitmapAllocator *lazyBitmap) 623 { 624 const WellKnowEntryList::WellKnownEntry *wellKnownEntry 625 = WellKnowEntryList::MatchEntry(model->NodeRef()); 626 if (!wellKnownEntry) 627 return NULL; 628 629 IconCacheEntry *entry = NULL; 630 631 BString type("tracker/active_"); 632 type += wellKnownEntry->name; 633 634 *resultingOpenCache = sharedCacheLocker; 635 (*resultingOpenCache)->Lock(); 636 637 source = kTrackerSupplied; 638 639 entry = fSharedCache.FindItem(type.String()); 640 if (entry) { 641 entry = entry->ResolveIfAlias(&fSharedCache, entry); 642 if (entry->HaveIconBitmap(mode, size)) 643 return entry; 644 } 645 646 if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 647 // match up well known entries in the file system with specialized 648 // icons stored in Tracker's resources 649 int32 resid = -1; 650 switch (wellKnownEntry->which) { 651 case B_BOOT_DISK: 652 resid = kResBootVolumeIcon; 653 break; 654 655 case B_BEOS_DIRECTORY: 656 resid = kResBeosFolderIcon; 657 break; 658 659 case B_USER_DIRECTORY: 660 resid = kResHomeDirIcon; 661 break; 662 663 case B_BEOS_FONTS_DIRECTORY: 664 case B_COMMON_FONTS_DIRECTORY: 665 case B_USER_FONTS_DIRECTORY: 666 resid = kResFontDirIcon; 667 break; 668 669 case B_BEOS_APPS_DIRECTORY: 670 case B_APPS_DIRECTORY: 671 case B_USER_DESKBAR_APPS_DIRECTORY: 672 resid = kResAppsDirIcon; 673 break; 674 675 case B_BEOS_PREFERENCES_DIRECTORY: 676 case B_PREFERENCES_DIRECTORY: 677 case B_USER_DESKBAR_PREFERENCES_DIRECTORY: 678 resid = kResPrefsDirIcon; 679 break; 680 681 case B_USER_MAIL_DIRECTORY: 682 resid = kResMailDirIcon; 683 break; 684 685 case B_USER_QUERIES_DIRECTORY: 686 resid = kResQueryDirIcon; 687 break; 688 689 case B_COMMON_DEVELOP_DIRECTORY: 690 case B_USER_DESKBAR_DEVELOP_DIRECTORY: 691 resid = kResDevelopDirIcon; 692 break; 693 694 case B_USER_CONFIG_DIRECTORY: 695 resid = kResConfigDirIcon; 696 break; 697 698 case B_USER_PEOPLE_DIRECTORY: 699 resid = kResPersonDirIcon; 700 break; 701 702 case B_USER_DOWNLOADS_DIRECTORY: 703 resid = kResDownloadDirIcon; 704 break; 705 706 default: 707 return NULL; 708 } 709 710 entry = fSharedCache.AddItem(type.String()); 711 712 BBitmap *bitmap = lazyBitmap->Get(); 713 GetTrackerResources()->GetIconResource(resid, size, bitmap); 714 entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size); 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