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 { 889 // scope for modelOpener 890 891 ModelNodeLazyOpener modelOpener(model); 892 // this opener takes care of opening the model and possibly 893 // closing it when we are done 894 LazyBitmapAllocator lazyBitmap(size); 895 // lazyBitmap manages bitmap allocation and freeing if needed 896 897 IconSource source = model->IconFrom(); 898 if (source == kUnknownSource || source == kUnknownNotFromNode) { 899 900 // fish for special first models and handle them appropriately 901 if (model->IsVolume()) { 902 // volume may use specialized icon in the volume node 903 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 904 &resultingOpenCache, model, source, mode, size, 905 &lazyBitmap, entry, permanent); 906 907 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 908 // look for volume defined icon 909 entry = GetVolumeIcon(nodeCacheLocker, sharedCacheLocker, 910 &resultingOpenCache, model, source, mode, 911 size, &lazyBitmap); 912 } 913 } else if (model->IsRoot()) { 914 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 915 &resultingOpenCache, model, source, mode, size, 916 &lazyBitmap); 917 ASSERT(entry != NULL); 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 == NULL) { 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, 934 size, &lazyBitmap, 0); 935 936 if (entry == NULL) { 937 // we don't have an icon, go with the generic 938 entry = GetGenericIcon(sharedCacheLocker, 939 &resultingOpenCache, model, source, mode, 940 size, &lazyBitmap, entry); 941 } 942 } 943 } 944 945 // update the icon source 946 model->SetIconFrom(source); 947 } else { 948 // we already know where the icon should come from, 949 // use shortcuts to get it 950 switch (source) { 951 case kNode: 952 resultingOpenCache = nodeCacheLocker; 953 resultingOpenCache->Lock(); 954 955 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 956 &resultingOpenCache, model, source, mode, 957 size, &lazyBitmap, entry, permanent); 958 959 if (entry != NULL) { 960 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, 961 entry); 962 if (!entry->HaveIconBitmap(mode, size) 963 && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) { 964 entry->ConstructBitmap(mode, size, &lazyBitmap); 965 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 966 } 967 ASSERT(entry->HaveIconBitmap(mode, size)); 968 } 969 break; 970 case kTrackerSupplied: 971 if (model->IsRoot()) { 972 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker, 973 &resultingOpenCache, model, source, mode, size, 974 &lazyBitmap); 975 break; 976 } else { 977 entry = GetWellKnownIcon(nodeCacheLocker, 978 sharedCacheLocker, &resultingOpenCache, model, 979 source, mode, size, &lazyBitmap); 980 981 if (entry != NULL) 982 break; 983 } 984 // fall through 985 case kTrackerDefault: 986 case kVolume: 987 if (model->IsVolume()) { 988 entry = GetNodeIcon(&modelOpener, nodeCacheLocker, 989 &resultingOpenCache, model, source, 990 mode, size, &lazyBitmap, entry, permanent); 991 if (entry == NULL 992 || !entry->HaveIconBitmap(mode, size)) { 993 entry = GetVolumeIcon(nodeCacheLocker, 994 sharedCacheLocker, &resultingOpenCache, model, 995 source, mode, size, &lazyBitmap); 996 } 997 break; 998 } 999 // fall through 1000 case kMetaMime: 1001 case kPreferredAppForType: 1002 case kPreferredAppForNode: 1003 resultingOpenCache = sharedCacheLocker; 1004 resultingOpenCache->Lock(); 1005 1006 entry = GetIconFromFileTypes(&modelOpener, source, mode, 1007 size, &lazyBitmap, 0); 1008 ASSERT(entry != NULL || entry->HaveIconBitmap(mode, size)); 1009 1010 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1011 // we don't have an icon, go with the generic 1012 entry = GetGenericIcon(sharedCacheLocker, 1013 &resultingOpenCache, model, source, mode, size, 1014 &lazyBitmap, entry); 1015 } 1016 1017 model->SetIconFrom(source); 1018 // The source shouldn't change in this case; if it does 1019 // though we might never be hitting the correct icon and 1020 // instead keep leaking entries after each miss this now 1021 // happens if an app defines an icon but a 1022 // GetIconForType() fails and we fall back to generic 1023 // icon. 1024 // ToDo: fix this and add an assert to the effect 1025 1026 ASSERT(entry != NULL); 1027 ASSERT(entry->HaveIconBitmap(mode, size)); 1028 break; 1029 1030 default: 1031 TRESPASS(); 1032 break; 1033 } 1034 } 1035 1036 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1037 // we don't have an icon, go with the generic 1038 PRINT( 1039 ("icon cache complete miss, falling back on generic icon " 1040 "for %s\n", model->Name())); 1041 entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache, 1042 model, source, mode, size, &lazyBitmap, entry); 1043 1044 // we don't even have generic, something is really broken, 1045 // go with hardcoded generic icon 1046 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) { 1047 PRINT( 1048 ("icon cache complete miss, falling back on generic " 1049 "icon for %s\n", model->Name())); 1050 entry = GetFallbackIcon(sharedCacheLocker, 1051 &resultingOpenCache, model, mode, size, &lazyBitmap, 1052 entry); 1053 } 1054 1055 // force icon pick up next time around because we probably just 1056 // hit a node in transition 1057 model->SetIconFrom(kUnknownSource); 1058 } 1059 } 1060 1061 ASSERT(entry != NULL && entry->HaveIconBitmap(mode, size)); 1062 1063 if (resultingCache != NULL) 1064 *resultingCache = resultingOpenCache; 1065 1066 return entry; 1067 } 1068 1069 1070 void 1071 IconCache::Draw(Model* model, BView* view, BPoint where, IconDrawMode mode, 1072 icon_size size, bool async) 1073 { 1074 // the following does not actually lock the caches, we are using the 1075 // lockLater mode; we will decide which of the two to lock down depending 1076 // on where we get the icon from 1077 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1078 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1079 1080 AutoLock<SimpleIconCache>* resultingCacheLocker; 1081 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1082 &resultingCacheLocker, model, mode, size, false); 1083 // Preload finds/creates the appropriate entry, locking down the 1084 // cache it is in and returns the whole state back to here 1085 1086 if (entry == NULL) 1087 return; 1088 1089 ASSERT(entry != NULL); 1090 ASSERT(entry->HaveIconBitmap(mode, size)); 1091 // got the entry, now draw it 1092 resultingCacheLocker->LockedItem()->Draw(entry, view, where, mode, 1093 size, async); 1094 1095 // either of the two cache lockers that got locked down by this call get 1096 // unlocked at this point 1097 } 1098 1099 1100 void 1101 IconCache::SyncDraw(Model* model, BView* view, BPoint where, 1102 IconDrawMode mode, icon_size size, 1103 void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1104 void* passThruState) 1105 { 1106 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1107 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1108 1109 AutoLock<SimpleIconCache>* resultingCacheLocker; 1110 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1111 &resultingCacheLocker, model, mode, size, false); 1112 1113 if (entry == NULL) 1114 return; 1115 1116 ASSERT(entry != NULL); 1117 ASSERT(entry->HaveIconBitmap(mode, size)); 1118 resultingCacheLocker->LockedItem()->Draw(entry, view, where, 1119 mode, size, blitFunc, passThruState); 1120 } 1121 1122 1123 void 1124 IconCache::Preload(Model* model, IconDrawMode mode, icon_size size, 1125 bool permanent) 1126 { 1127 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1128 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1129 1130 Preload(&nodeCacheLocker, &sharedCacheLocker, 0, model, mode, size, 1131 permanent); 1132 } 1133 1134 1135 status_t 1136 IconCache::Preload(const char* fileType, IconDrawMode mode, icon_size size) 1137 { 1138 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache); 1139 LazyBitmapAllocator lazyBitmap(size); 1140 1141 BMimeType mime(fileType); 1142 char preferredAppSig[B_MIME_TYPE_LENGTH]; 1143 status_t result = mime.GetPreferredApp(preferredAppSig); 1144 if (result != B_OK) 1145 return result; 1146 1147 // try getting the icon from the preferred app for the signature 1148 IconCacheEntry* entry = GetIconForPreferredApp(fileType, preferredAppSig, 1149 mode, size, &lazyBitmap, 0); 1150 if (entry != NULL) 1151 return B_OK; 1152 1153 // try getting the icon directly from the metamime 1154 result = mime.GetIcon(lazyBitmap.Get(), size); 1155 1156 if (result != B_OK) 1157 return result; 1158 1159 entry = fSharedCache.AddItem(fileType); 1160 BBitmap* bitmap = lazyBitmap.Adopt(); 1161 entry->SetIcon(bitmap, kNormalIcon, size); 1162 if (mode != kNormalIcon) { 1163 entry->ConstructBitmap(mode, size, &lazyBitmap); 1164 entry->SetIcon(lazyBitmap.Adopt(), mode, size); 1165 } 1166 1167 return B_OK; 1168 } 1169 1170 1171 void 1172 IconCache::Deleting(const Model* model) 1173 { 1174 AutoLock<SimpleIconCache> lock(&fNodeCache); 1175 1176 if (model->IconFrom() == kNode) 1177 fNodeCache.Deleting(model->NodeRef()); 1178 1179 // don't care if the node uses the shared cache 1180 } 1181 1182 1183 void 1184 IconCache::Removing(const Model* model) 1185 { 1186 AutoLock<SimpleIconCache> lock(&fNodeCache); 1187 1188 if (model->IconFrom() == kNode) 1189 fNodeCache.Removing(model->NodeRef()); 1190 } 1191 1192 1193 void 1194 IconCache::Deleting(const BView* view) 1195 { 1196 AutoLock<SimpleIconCache> lock(&fNodeCache); 1197 fNodeCache.Deleting(view); 1198 } 1199 1200 1201 void 1202 IconCache::IconChanged(Model* model) 1203 { 1204 AutoLock<SimpleIconCache> lock(&fNodeCache); 1205 1206 if (model->IconFrom() == kNode || model->IconFrom() == kVolume) 1207 fNodeCache.Deleting(model->NodeRef()); 1208 1209 model->ResetIconFrom(); 1210 } 1211 1212 1213 void 1214 IconCache::IconChanged(const char* mimeType, const char* appSignature) 1215 { 1216 AutoLock<SimpleIconCache> sharedLock(&fSharedCache); 1217 SharedCacheEntry* entry = fSharedCache.FindItem(mimeType, appSignature); 1218 if (entry == NULL) 1219 return; 1220 1221 AutoLock<SimpleIconCache> nodeLock(&fNodeCache); 1222 1223 entry = (SharedCacheEntry*)fSharedCache.ResolveIfAlias(entry); 1224 ASSERT(entry != NULL); 1225 int32 index = fSharedCache.EntryIndex(entry); 1226 1227 fNodeCache.RemoveAliasesTo(index); 1228 fSharedCache.RemoveAliasesTo(index); 1229 1230 fSharedCache.IconChanged(entry); 1231 } 1232 1233 1234 BBitmap* 1235 IconCache::MakeSelectedIcon(const BBitmap* normal, icon_size size, 1236 LazyBitmapAllocator* lazyBitmap) 1237 { 1238 return MakeTransformedIcon(normal, size, fHiliteTable, lazyBitmap); 1239 } 1240 1241 #if xDEBUG 1242 1243 static void 1244 DumpBitmap(const BBitmap* bitmap) 1245 { 1246 if (!bitmap){ 1247 printf("NULL bitmap passed to DumpBitmap\n"); 1248 return; 1249 } 1250 int32 length = bitmap->BitsLength(); 1251 1252 printf("data length %ld \n", length); 1253 1254 int32 columns = (int32)bitmap->Bounds().Width() + 1; 1255 const unsigned char* bitPtr = (const unsigned char*)bitmap->Bits(); 1256 for (; length >= 0; length--) { 1257 for (int32 columnIndex = 0; columnIndex < columns; 1258 columnIndex++, length--) 1259 printf("%c%c", "0123456789ABCDEF"[(*bitPtr)/0x10], 1260 "0123456789ABCDEF"[(*bitPtr++)%0x10]); 1261 1262 printf("\n"); 1263 } 1264 printf("\n"); 1265 } 1266 1267 #endif 1268 1269 void 1270 IconCache::InitHiliteTable() 1271 { 1272 // build the color transform tables for different icon modes 1273 BScreen screen(B_MAIN_SCREEN_ID); 1274 rgb_color color; 1275 for (int32 index = 0; index < kColorTransformTableSize; index++) { 1276 color = screen.ColorForIndex((uchar)index); 1277 fHiliteTable[index] = screen.IndexForColor(tint_color(color, 1.3f)); 1278 } 1279 1280 fHiliteTable[B_TRANSPARENT_8_BIT] = B_TRANSPARENT_8_BIT; 1281 fInitHiliteTable = false; 1282 } 1283 1284 1285 BBitmap* 1286 IconCache::MakeTransformedIcon(const BBitmap* source, icon_size /*size*/, 1287 int32 colorTransformTable[], LazyBitmapAllocator* lazyBitmap) 1288 { 1289 if (fInitHiliteTable) 1290 InitHiliteTable(); 1291 1292 BBitmap* result = lazyBitmap->Get(); 1293 uint8* src = (uint8*)source->Bits(); 1294 uint8* dst = (uint8*)result->Bits(); 1295 1296 // ASSERT(result->ColorSpace() == source->ColorSpace() 1297 // && result->Bounds() == source->Bounds()); 1298 if (result->ColorSpace() != source->ColorSpace() 1299 || result->Bounds() != source->Bounds()) { 1300 printf("IconCache::MakeTransformedIcon() - " 1301 "bitmap format mismatch!\n"); 1302 return NULL; 1303 } 1304 1305 switch (result->ColorSpace()) { 1306 case B_RGB32: 1307 case B_RGBA32: { 1308 uint32 width = source->Bounds().IntegerWidth() + 1; 1309 uint32 height = source->Bounds().IntegerHeight() + 1; 1310 uint32 srcBPR = source->BytesPerRow(); 1311 uint32 dstBPR = result->BytesPerRow(); 1312 for (uint32 y = 0; y < height; y++) { 1313 uint8* d = dst; 1314 uint8* s = src; 1315 for (uint32 x = 0; x < width; x++) { 1316 // 66% brightness 1317 d[0] = (int)s[0] * 168 >> 8; 1318 d[1] = (int)s[1] * 168 >> 8; 1319 d[2] = (int)s[2] * 168 >> 8; 1320 d[3] = s[3]; 1321 d += 4; 1322 s += 4; 1323 } 1324 dst += dstBPR; 1325 src += srcBPR; 1326 } 1327 break; 1328 } 1329 1330 case B_CMAP8: { 1331 int32 bitsLength = result->BitsLength(); 1332 for (int32 i = 0; i < bitsLength; i++) 1333 *dst++ = (uint8)colorTransformTable[*src++]; 1334 break; 1335 } 1336 1337 default: 1338 memset(dst, 0, result->BitsLength()); 1339 // unkown colorspace, no tinting for you 1340 // "black" should make the problem stand out 1341 break; 1342 } 1343 1344 return result; 1345 } 1346 1347 1348 bool 1349 IconCache::IconHitTest(BPoint where, const Model* model, IconDrawMode mode, 1350 icon_size size) 1351 { 1352 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false); 1353 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false); 1354 1355 AutoLock<SimpleIconCache>* resultingCacheLocker; 1356 IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker, 1357 &resultingCacheLocker, const_cast<Model*>(model), mode, size, false); 1358 // Preload finds/creates the appropriate entry, locking down the 1359 // cache it is in and returns the whole state back to here 1360 1361 if (entry != NULL) 1362 return entry->IconHitTest(where, mode, size); 1363 1364 return false; 1365 } 1366 1367 1368 void 1369 IconCacheEntry::RetireIcons(BObjectList<BBitmap>* retiredBitmapList) 1370 { 1371 if (fLargeIcon) { 1372 retiredBitmapList->AddItem(fLargeIcon); 1373 fLargeIcon = NULL; 1374 } 1375 if (fMiniIcon) { 1376 retiredBitmapList->AddItem(fMiniIcon); 1377 fMiniIcon = NULL; 1378 } 1379 if (fHilitedLargeIcon) { 1380 retiredBitmapList->AddItem(fHilitedLargeIcon); 1381 fHilitedLargeIcon = NULL; 1382 } 1383 if (fHilitedMiniIcon) { 1384 retiredBitmapList->AddItem(fHilitedMiniIcon); 1385 fHilitedMiniIcon = NULL; 1386 } 1387 1388 int32 count = retiredBitmapList->CountItems(); 1389 if (count > 10 * 1024) { 1390 PRINT(("nuking old icons from the retired bitmap list\n")); 1391 for (count = 512; count > 0; count--) 1392 delete retiredBitmapList->RemoveItemAt(0); 1393 } 1394 } 1395 1396 1397 // #pragma mark - 1398 1399 1400 // In debug mode keep the hash table sizes small so that they grow a lot and 1401 // execercise the resizing code a lot. In release mode allocate them large 1402 // up-front for better performance 1403 SharedIconCache::SharedIconCache() 1404 #if DEBUG 1405 : SimpleIconCache("Shared Icon cache aka \"The Dead-Locker\""), 1406 fHashTable(20), 1407 fElementArray(20), 1408 fRetiredBitmaps(20, true) 1409 #else 1410 : SimpleIconCache("Tracker shared icon cache"), 1411 fHashTable(1000), 1412 fElementArray(1024), 1413 fRetiredBitmaps(256, true) 1414 #endif 1415 { 1416 fHashTable.SetElementVector(&fElementArray); 1417 } 1418 1419 1420 void 1421 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1422 IconDrawMode mode, icon_size size, bool async) 1423 { 1424 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, async); 1425 } 1426 1427 1428 void 1429 SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1430 IconDrawMode mode, icon_size size, void (*blitFunc)(BView*, BPoint, 1431 BBitmap*, void*), void* passThruState) 1432 { 1433 ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, 1434 blitFunc, passThruState); 1435 } 1436 1437 1438 SharedCacheEntry* 1439 SharedIconCache::FindItem(const char* fileType, 1440 const char* appSignature) const 1441 { 1442 ASSERT(fileType); 1443 if (!fileType) 1444 fileType = B_FILE_MIMETYPE; 1445 1446 SharedCacheEntry* result 1447 = fHashTable.FindFirst(SharedCacheEntry::Hash(fileType, 1448 appSignature)); 1449 1450 if (!result) 1451 return NULL; 1452 1453 for(;;) { 1454 if (result->fFileType == fileType 1455 && result->fAppSignature == appSignature) { 1456 return result; 1457 } 1458 1459 if (result->fNext < 0) 1460 break; 1461 1462 result 1463 = const_cast<SharedCacheEntry*>(&fElementArray.At(result->fNext)); 1464 } 1465 1466 return NULL; 1467 } 1468 1469 1470 SharedCacheEntry* 1471 SharedIconCache::AddItem(const char* fileType, const char* appSignature) 1472 { 1473 ASSERT(fileType); 1474 if (!fileType) 1475 fileType = B_FILE_MIMETYPE; 1476 1477 SharedCacheEntry* result = fHashTable.Add(SharedCacheEntry::Hash(fileType, 1478 appSignature)); 1479 result->SetTo(fileType, appSignature); 1480 return result; 1481 } 1482 1483 1484 SharedCacheEntry* 1485 SharedIconCache::AddItem(SharedCacheEntry** outstandingEntry, 1486 const char* fileType, const char* appSignature) 1487 { 1488 int32 entryToken = fHashTable.ElementIndex(*outstandingEntry); 1489 ASSERT(entryToken >= 0); 1490 1491 ASSERT(fileType); 1492 if (!fileType) 1493 fileType = B_FILE_MIMETYPE; 1494 1495 SharedCacheEntry* result = fHashTable.Add(SharedCacheEntry::Hash(fileType, 1496 appSignature)); 1497 result->SetTo(fileType, appSignature); 1498 *outstandingEntry = fHashTable.ElementAt(entryToken); 1499 1500 return result; 1501 } 1502 1503 1504 void 1505 SharedIconCache::IconChanged(SharedCacheEntry* entry) 1506 { 1507 // by now there should be no aliases to entry, just remove entry 1508 // itself 1509 ASSERT(entry->fAliasForIndex == -1); 1510 entry->RetireIcons(&fRetiredBitmaps); 1511 fHashTable.Remove(entry); 1512 } 1513 1514 1515 void 1516 SharedIconCache::RemoveAliasesTo(int32 aliasIndex) 1517 { 1518 int32 count = fHashTable.VectorSize(); 1519 for (int32 index = 0; index < count; index++) { 1520 SharedCacheEntry* entry = fHashTable.ElementAt(index); 1521 if (entry->fAliasForIndex == aliasIndex) 1522 fHashTable.Remove(entry); 1523 } 1524 } 1525 1526 1527 void 1528 SharedIconCache::SetAliasFor(IconCacheEntry* alias, 1529 const SharedCacheEntry* original) const 1530 { 1531 alias->fAliasForIndex = fHashTable.ElementIndex(original); 1532 } 1533 1534 1535 SharedCacheEntry::SharedCacheEntry() 1536 : fNext(-1) 1537 { 1538 } 1539 1540 1541 SharedCacheEntry::SharedCacheEntry(const char* fileType, 1542 const char* appSignature) 1543 : fNext(-1), 1544 fFileType(fileType), 1545 fAppSignature(appSignature) 1546 { 1547 } 1548 1549 1550 void 1551 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1552 icon_size size, bool async) 1553 { 1554 BBitmap* bitmap = IconForMode(mode, size); 1555 ASSERT(bitmap); 1556 1557 drawing_mode oldMode = view->DrawingMode(); 1558 1559 if (bitmap->ColorSpace() == B_RGBA32) { 1560 if (oldMode != B_OP_ALPHA) { 1561 view->SetDrawingMode(B_OP_ALPHA); 1562 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1563 } 1564 } else { 1565 view->SetDrawingMode(B_OP_OVER); 1566 } 1567 1568 if (async) 1569 view->DrawBitmapAsync(bitmap, where); 1570 else 1571 view->DrawBitmap(bitmap, where); 1572 1573 view->SetDrawingMode(oldMode); 1574 } 1575 1576 1577 void 1578 SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1579 icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1580 void* passThruState) 1581 { 1582 BBitmap* bitmap = IconForMode(mode, size); 1583 if (!bitmap) 1584 return; 1585 1586 // if (bitmap->ColorSpace() == B_RGBA32) { 1587 // view->SetDrawingMode(B_OP_ALPHA); 1588 // view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1589 // } else { 1590 // view->SetDrawingMode(B_OP_OVER); 1591 // } 1592 1593 (blitFunc)(view, where, bitmap, passThruState); 1594 } 1595 1596 1597 uint32 1598 SharedCacheEntry::Hash(const char* fileType, const char* appSignature) 1599 { 1600 uint32 hash = HashString(fileType, 0); 1601 if (appSignature && appSignature[0]) 1602 hash = HashString(appSignature, hash); 1603 1604 return hash; 1605 } 1606 1607 1608 uint32 1609 SharedCacheEntry::Hash() const 1610 { 1611 uint32 hash = HashString(fFileType.String(), 0); 1612 if (fAppSignature.Length()) 1613 hash = HashString(fAppSignature.String(), hash); 1614 1615 return hash; 1616 } 1617 1618 1619 bool 1620 SharedCacheEntry::operator==(const SharedCacheEntry &entry) const 1621 { 1622 return fFileType == entry.FileType() 1623 && fAppSignature == entry.AppSignature(); 1624 } 1625 1626 1627 void 1628 SharedCacheEntry::SetTo(const char* fileType, const char* appSignature) 1629 { 1630 fFileType = fileType; 1631 fAppSignature = appSignature; 1632 } 1633 1634 1635 SharedCacheEntryArray::SharedCacheEntryArray(int32 initialSize) 1636 : OpenHashElementArray<SharedCacheEntry>(initialSize) 1637 { 1638 } 1639 1640 1641 SharedCacheEntry* 1642 SharedCacheEntryArray::Add() 1643 { 1644 return OpenHashElementArray<SharedCacheEntry>::Add(); 1645 } 1646 1647 1648 // #pragma mark - 1649 1650 1651 NodeCacheEntry::NodeCacheEntry(bool permanent) 1652 : fNext(-1), 1653 fPermanent(permanent) 1654 { 1655 } 1656 1657 1658 NodeCacheEntry::NodeCacheEntry(const node_ref* node, bool permanent) 1659 : fNext(-1), 1660 fRef(*node), 1661 fPermanent(permanent) 1662 { 1663 } 1664 1665 1666 void 1667 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1668 icon_size size, bool async) 1669 { 1670 BBitmap* bitmap = IconForMode(mode, size); 1671 if (!bitmap) 1672 return; 1673 1674 drawing_mode oldMode = view->DrawingMode(); 1675 1676 if (bitmap->ColorSpace() == B_RGBA32) { 1677 if (oldMode != B_OP_ALPHA) { 1678 view->SetDrawingMode(B_OP_ALPHA); 1679 view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1680 } 1681 } else { 1682 view->SetDrawingMode(B_OP_OVER); 1683 } 1684 1685 if (false && async) { 1686 TRESPASS(); 1687 // need to copy the bits first in here 1688 view->DrawBitmapAsync(bitmap, where); 1689 } else 1690 view->DrawBitmap(bitmap, where); 1691 1692 view->SetDrawingMode(oldMode); 1693 } 1694 1695 1696 void 1697 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, 1698 icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*), 1699 void* passThruState) 1700 { 1701 BBitmap* bitmap = IconForMode(mode, size); 1702 if (!bitmap) 1703 return; 1704 1705 // if (bitmap->ColorSpace() == B_RGBA32) { 1706 // view->SetDrawingMode(B_OP_ALPHA); 1707 // view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 1708 // } else { 1709 // view->SetDrawingMode(B_OP_OVER); 1710 // } 1711 1712 (blitFunc)(view, where, bitmap, passThruState); 1713 } 1714 1715 1716 const node_ref* 1717 NodeCacheEntry::Node() const 1718 { 1719 return &fRef; 1720 } 1721 1722 1723 uint32 1724 NodeCacheEntry::Hash() const 1725 { 1726 return Hash(&fRef); 1727 } 1728 1729 1730 uint32 1731 NodeCacheEntry::Hash(const node_ref* node) 1732 { 1733 return node->device ^ ((uint32*)&node->node)[0] 1734 ^ ((uint32*)&node->node)[1]; 1735 } 1736 1737 1738 bool 1739 NodeCacheEntry::operator==(const NodeCacheEntry &entry) const 1740 { 1741 return fRef == entry.fRef; 1742 } 1743 1744 1745 void 1746 NodeCacheEntry::SetTo(const node_ref* node) 1747 { 1748 fRef = *node; 1749 } 1750 1751 1752 bool 1753 NodeCacheEntry::Permanent() const 1754 { 1755 return fPermanent; 1756 } 1757 1758 1759 void 1760 NodeCacheEntry::MakePermanent() 1761 { 1762 fPermanent = true; 1763 } 1764 1765 1766 // #pragma mark - 1767 1768 1769 NodeIconCache::NodeIconCache() 1770 #if DEBUG 1771 : SimpleIconCache("Node Icon cache aka \"The Dead-Locker\""), 1772 fHashTable(20), 1773 fElementArray(20) 1774 #else 1775 : SimpleIconCache("Tracker node icon cache"), 1776 fHashTable(100), 1777 fElementArray(100) 1778 #endif 1779 { 1780 fHashTable.SetElementVector(&fElementArray); 1781 } 1782 1783 1784 void 1785 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1786 IconDrawMode mode, icon_size size, bool async) 1787 { 1788 1789 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, async); 1790 } 1791 1792 1793 void 1794 NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where, 1795 IconDrawMode mode, icon_size size, void (*blitFunc)(BView*, BPoint, 1796 BBitmap*, void*), void* passThruState) 1797 { 1798 ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, 1799 blitFunc, passThruState); 1800 } 1801 1802 1803 NodeCacheEntry* 1804 NodeIconCache::FindItem(const node_ref* node) const 1805 { 1806 NodeCacheEntry* result = fHashTable.FindFirst(NodeCacheEntry::Hash(node)); 1807 1808 if (!result) 1809 return NULL; 1810 1811 for(;;) { 1812 if (*result->Node() == *node) 1813 return result; 1814 1815 if (result->fNext < 0) 1816 break; 1817 1818 result 1819 = const_cast<NodeCacheEntry*>(&fElementArray.At(result->fNext)); 1820 } 1821 1822 return NULL; 1823 } 1824 1825 1826 NodeCacheEntry* 1827 NodeIconCache::AddItem(const node_ref* node, bool permanent) 1828 { 1829 NodeCacheEntry* result = fHashTable.Add(NodeCacheEntry::Hash(node)); 1830 result->SetTo(node); 1831 if (permanent) 1832 result->MakePermanent(); 1833 1834 return result; 1835 } 1836 1837 1838 NodeCacheEntry* 1839 NodeIconCache::AddItem(NodeCacheEntry** outstandingEntry, 1840 const node_ref* node) 1841 { 1842 int32 entryToken = fHashTable.ElementIndex(*outstandingEntry); 1843 1844 NodeCacheEntry* result = fHashTable.Add(NodeCacheEntry::Hash(node)); 1845 result->SetTo(node); 1846 *outstandingEntry = fHashTable.ElementAt(entryToken); 1847 1848 return result; 1849 } 1850 1851 1852 void 1853 NodeIconCache::Deleting(const node_ref* node) 1854 { 1855 NodeCacheEntry* entry = FindItem(node); 1856 ASSERT(entry); 1857 if (!entry || entry->Permanent()) 1858 return; 1859 1860 fHashTable.Remove(entry); 1861 } 1862 1863 1864 void 1865 NodeIconCache::Removing(const node_ref* node) 1866 { 1867 NodeCacheEntry* entry = FindItem(node); 1868 ASSERT(entry); 1869 if (!entry) 1870 return; 1871 1872 fHashTable.Remove(entry); 1873 } 1874 1875 1876 void 1877 NodeIconCache::Deleting(const BView*) 1878 { 1879 #ifdef NODE_CACHE_ASYNC_DRAWS 1880 TRESPASS(); 1881 #endif 1882 } 1883 1884 1885 void 1886 NodeIconCache::IconChanged(const Model* model) 1887 { 1888 Deleting(model->NodeRef()); 1889 } 1890 1891 1892 void 1893 NodeIconCache::RemoveAliasesTo(int32 aliasIndex) 1894 { 1895 int32 count = fHashTable.VectorSize(); 1896 for (int32 index = 0; index < count; index++) { 1897 NodeCacheEntry* entry = fHashTable.ElementAt(index); 1898 if (entry->fAliasForIndex == aliasIndex) 1899 fHashTable.Remove(entry); 1900 } 1901 } 1902 1903 1904 // #pragma mark - 1905 1906 1907 NodeCacheEntryArray::NodeCacheEntryArray(int32 initialSize) 1908 : OpenHashElementArray<NodeCacheEntry>(initialSize) 1909 { 1910 } 1911 1912 1913 NodeCacheEntry* 1914 NodeCacheEntryArray::Add() 1915 { 1916 return OpenHashElementArray<NodeCacheEntry>::Add(); 1917 } 1918 1919 1920 // #pragma mark - 1921 1922 1923 SimpleIconCache::SimpleIconCache(const char* name) 1924 : fLock(name) 1925 { 1926 } 1927 1928 1929 void 1930 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1931 icon_size, bool) 1932 { 1933 TRESPASS(); 1934 // pure virtual, do nothing 1935 } 1936 1937 1938 void 1939 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode, 1940 icon_size, void(*)(BView*, BPoint, BBitmap*, void*), void*) 1941 { 1942 TRESPASS(); 1943 // pure virtual, do nothing 1944 } 1945 1946 1947 bool 1948 SimpleIconCache::Lock() 1949 { 1950 return fLock.Lock(); 1951 } 1952 1953 1954 void 1955 SimpleIconCache::Unlock() 1956 { 1957 fLock.Unlock(); 1958 } 1959 1960 1961 bool 1962 SimpleIconCache::IsLocked() const 1963 { 1964 return fLock.IsLocked(); 1965 } 1966 1967 1968 // #pragma mark - 1969 1970 1971 LazyBitmapAllocator::LazyBitmapAllocator(icon_size size, 1972 color_space colorSpace, bool preallocate) 1973 : fBitmap(NULL), 1974 fSize(size), 1975 fColorSpace(colorSpace) 1976 { 1977 if (preallocate) 1978 Get(); 1979 } 1980 1981 1982 LazyBitmapAllocator::~LazyBitmapAllocator() 1983 { 1984 delete fBitmap; 1985 } 1986 1987 1988 BBitmap* 1989 LazyBitmapAllocator::Get() 1990 { 1991 if (!fBitmap) 1992 fBitmap = new BBitmap(BRect(0, 0, fSize - 1, fSize - 1), fColorSpace); 1993 1994 return fBitmap; 1995 } 1996 1997 1998 BBitmap* 1999 LazyBitmapAllocator::Adopt() 2000 { 2001 if (!fBitmap) 2002 Get(); 2003 2004 BBitmap* result = fBitmap; 2005 fBitmap = NULL; 2006 return result; 2007 } 2008 2009 2010 IconCache* IconCache::sIconCache; 2011