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