6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
35 // Icon cache is used for drawing node icons; it caches icons
36 // and reuses them for successive draws
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
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
50 // Use lazily allocated bitmap arrays for every view for node icon cache
52 // Have an overflow list for deleting shared icons, delete from the list
56 // Actual icon lookup sequence:
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
74 #include "IconCache.h"
75 #include "MimeTypes.h"
80 //# define LOG_DISK_HITS
81 // the LOG_DISK_HITS define is used to check that the disk is not hit more
82 // than needed - enable it, open a window with a bunch of poses, force
83 // it to redraw, shouldn't recache
84 //# define LOG_ADD_ITEM
87 // set up a few printing macros to get rid of a ton of debugging ifdefs
90 # define PRINT_DISK_HITS(ARGS) _debugPrintf ARGS
92 # define PRINT_DISK_HITS(ARGS) (void)0
96 # define PRINT_ADD_ITEM(ARGS) _debugPrintf ARGS
98 # define PRINT_ADD_ITEM(ARGS) (void)0
101 #undef NODE_CACHE_ASYNC_DRAWS
104 IconCacheEntry::IconCacheEntry()
107 fHighlightedLargeIcon(NULL
),
109 fHighlightedMiniIcon(NULL
),
115 IconCacheEntry::~IconCacheEntry()
117 if (fAliasForIndex
< 0) {
119 delete fHighlightedLargeIcon
;
121 delete fHighlightedMiniIcon
;
123 // clean up a bit to leave the hash table entry in an initialized state
125 fHighlightedLargeIcon
= NULL
;
127 fHighlightedMiniIcon
= NULL
;
134 IconCacheEntry::SetAliasFor(const SharedIconCache
* sharedCache
,
135 const SharedCacheEntry
* entry
)
137 sharedCache
->SetAliasFor(this, entry
);
138 ASSERT(fAliasForIndex
>= 0);
143 IconCacheEntry::ResolveIfAlias(const SharedIconCache
* sharedCache
)
145 return sharedCache
->ResolveIfAlias(this);
150 IconCacheEntry::ResolveIfAlias(const SharedIconCache
* sharedCache
,
151 IconCacheEntry
* entry
)
156 return sharedCache
->ResolveIfAlias(entry
);
161 IconCacheEntry::CanConstructBitmap(IconDrawMode mode
, icon_size
) const
163 if (mode
== kSelected
) {
173 IconCacheEntry::HaveIconBitmap(IconDrawMode mode
, icon_size size
) const
175 ASSERT(mode
== kSelected
|| mode
== kNormalIcon
);
178 if (mode
== kNormalIcon
) {
179 return size
== B_MINI_ICON
? fMiniIcon
!= NULL
181 && fLargeIcon
->Bounds().IntegerWidth() + 1 == size
;
182 } else if (mode
== kSelected
) {
183 return size
== B_MINI_ICON
? fHighlightedMiniIcon
!= NULL
184 : fHighlightedLargeIcon
!= NULL
185 && fHighlightedLargeIcon
->Bounds().IntegerWidth() + 1 == size
;
193 IconCacheEntry::IconForMode(IconDrawMode mode
, icon_size size
) const
195 ASSERT(mode
== kSelected
|| mode
== kNormalIcon
);
198 if (mode
== kNormalIcon
) {
199 if (size
== B_MINI_ICON
)
203 } else if (mode
== kSelected
) {
204 if (size
== B_MINI_ICON
)
205 return fHighlightedMiniIcon
;
207 return fHighlightedLargeIcon
;
215 IconCacheEntry::IconHitTest(BPoint where
, IconDrawMode mode
,
216 icon_size size
) const
218 ASSERT(where
.x
< size
&& where
.y
< size
);
219 BBitmap
* bitmap
= IconForMode(mode
, size
);
223 uchar
* bits
= (uchar
*)bitmap
->Bits();
224 ASSERT(bits
!= NULL
);
226 BRect
bounds(bitmap
->Bounds());
227 bounds
.InsetBy((bounds
.Width() + 1.0) / 8.0, (bounds
.Height() + 1.0) / 8.0);
228 if (bounds
.Contains(where
))
231 switch (bitmap
->ColorSpace()) {
233 // test alpha channel
234 return *(bits
+ (int32
)(floorf(where
.y
) * bitmap
->BytesPerRow()
235 + floorf(where
.x
) * 4 + 3)) > 20;
238 return *(bits
+ (int32
)(floorf(where
.y
) * size
+ where
.x
))
239 != B_TRANSPARENT_8_BIT
;
248 IconCacheEntry::ConstructBitmap(BBitmap
* constructFrom
,
249 IconDrawMode requestedMode
, IconDrawMode constructFromMode
,
250 icon_size size
, LazyBitmapAllocator
* lazyBitmap
)
252 ASSERT(requestedMode
== kSelected
&& constructFromMode
== kNormalIcon
);
255 if (requestedMode
== kSelected
&& constructFromMode
== kNormalIcon
) {
256 return IconCache::sIconCache
->MakeSelectedIcon(constructFrom
, size
,
265 IconCacheEntry::ConstructBitmap(IconDrawMode requestedMode
, icon_size size
,
266 LazyBitmapAllocator
* lazyBitmap
)
268 BBitmap
* source
= (size
== B_MINI_ICON
) ? fMiniIcon
: fLargeIcon
;
269 ASSERT(source
!= NULL
);
271 return ConstructBitmap(source
, requestedMode
, kNormalIcon
, size
,
277 IconCacheEntry::AlternateModeForIconConstructing(IconDrawMode requestedMode
,
278 IconDrawMode
&alternate
, icon_size
)
280 if ((requestedMode
& kSelected
) != 0) {
282 alternate
= kNormalIcon
;
291 IconCacheEntry::SetIcon(BBitmap
* bitmap
, IconDrawMode mode
, icon_size size
,
294 if (mode
== kNormalIcon
) {
295 if (size
== B_MINI_ICON
)
299 } else if (mode
== kSelectedIcon
) {
300 if (size
== B_MINI_ICON
)
301 fHighlightedMiniIcon
= bitmap
;
303 fHighlightedLargeIcon
= bitmap
;
309 IconCache::IconCache()
311 fInitHighlightTable(true)
313 InitHighlightTable();
317 // The following calls use the icon lookup sequence node-prefered app for
318 // node-metamime-preferred app for metamime to find an icon;
319 // if we are trying to get a specialized icon, we will first look for a normal
320 // icon in each of the locations, if we get a hit, we look for the
321 // specialized, if we don't find one, we try to auto-construct one, if we
322 // can't we assume the icon is not available for now the code only looks for
323 // normal icons, selected icons are auto-generated.
327 IconCache::GetIconForPreferredApp(const char* fileTypeSignature
,
328 const char* preferredApp
, IconDrawMode mode
, icon_size size
,
329 LazyBitmapAllocator
* lazyBitmap
, IconCacheEntry
* entry
)
331 ASSERT(fSharedCache
.IsLocked());
333 if (preferredApp
== NULL
|| *preferredApp
== '\0')
337 entry
= fSharedCache
.FindItem(fileTypeSignature
, preferredApp
);
339 entry
= entry
->ResolveIfAlias(&fSharedCache
, entry
);
341 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n",
342 __FILE__
, __LINE__
, preferredApp
, fileTypeSignature
, entry
));
344 if (entry
->HaveIconBitmap(mode
, size
))
349 if (entry
== NULL
|| !entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
351 ("File %s; Line %d # hitting disk for preferredApp %s, type %s\n",
352 __FILE__
, __LINE__
, preferredApp
, fileTypeSignature
));
354 BMimeType
preferredAppType(preferredApp
);
355 BString
signature(fileTypeSignature
);
357 if (preferredAppType
.GetIconForType(signature
.String(),
358 lazyBitmap
->Get(), size
) != B_OK
) {
362 BBitmap
* bitmap
= lazyBitmap
->Adopt();
365 ("File %s; Line %d # adding entry for preferredApp %s, "
366 "type %s\n", __FILE__
, __LINE__
, preferredApp
,
368 entry
= fSharedCache
.AddItem(fileTypeSignature
, preferredApp
);
370 entry
->SetIcon(bitmap
, kNormalIcon
, size
);
373 if (mode
!= kNormalIcon
374 && entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
375 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
376 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
384 IconCache::GetIconFromMetaMime(const char* fileType
, IconDrawMode mode
,
385 icon_size size
, LazyBitmapAllocator
* lazyBitmap
, IconCacheEntry
* entry
)
387 ASSERT(fSharedCache
.IsLocked());
390 entry
= fSharedCache
.FindItem(fileType
);
393 entry
= entry
->ResolveIfAlias(&fSharedCache
, entry
);
394 // metamime defines an icon and we have it cached
395 if (entry
->HaveIconBitmap(mode
, size
))
399 if (entry
== NULL
|| !entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
400 PRINT_DISK_HITS(("File %s; Line %d # hitting disk for metamime %s\n",
401 __FILE__
, __LINE__
, fileType
));
403 BMimeType
mime(fileType
);
404 // try getting the icon directly from the metamime
405 if (mime
.GetIcon(lazyBitmap
->Get(), size
) != B_OK
) {
406 // try getting it from the preferred app of this type
407 char preferredAppSig
[B_MIME_TYPE_LENGTH
];
408 if (mime
.GetPreferredApp(preferredAppSig
) != B_OK
)
411 SharedCacheEntry
* aliasTo
= NULL
;
414 = (SharedCacheEntry
*)entry
->ResolveIfAlias(&fSharedCache
);
417 // look for icon defined by preferred app from metamime
418 aliasTo
= (SharedCacheEntry
*)GetIconForPreferredApp(fileType
,
419 preferredAppSig
, mode
, size
, lazyBitmap
, aliasTo
);
424 // make an aliased entry so that the next time we get a
425 // hit on the first FindItem in here
428 ("File %s; Line %d # adding entry as alias for type %s\n",
429 __FILE__
, __LINE__
, fileType
));
430 entry
= fSharedCache
.AddItem(&aliasTo
, fileType
);
431 entry
->SetAliasFor(&fSharedCache
, aliasTo
);
433 ASSERT(aliasTo
->HaveIconBitmap(mode
, size
));
437 // at this point, we've found an icon for the MIME type
438 BBitmap
* bitmap
= lazyBitmap
->Adopt();
440 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for type %s\n",
441 __FILE__
, __LINE__
, fileType
));
442 entry
= fSharedCache
.AddItem(fileType
);
444 entry
->SetIcon(bitmap
, kNormalIcon
, size
);
447 ASSERT(entry
!= NULL
);
449 if (mode
!= kNormalIcon
450 && entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
451 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
452 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
456 if (!entry
->HaveIconBitmap(mode
, size
))
457 PRINT(("failing on %s, mode %ld, size %ld\n", fileType
, mode
, size
));
460 ASSERT(entry
->HaveIconBitmap(mode
, size
));
467 IconCache::GetIconFromFileTypes(ModelNodeLazyOpener
* modelOpener
,
468 IconSource
&source
, IconDrawMode mode
, icon_size size
,
469 LazyBitmapAllocator
* lazyBitmap
, IconCacheEntry
* entry
)
471 ASSERT(fSharedCache
.IsLocked());
472 // use file types to get the icon
473 Model
* model
= modelOpener
->TargetModel();
475 const char* fileType
= model
->MimeType();
476 const char* nodePreferredApp
= model
->PreferredAppSignature();
477 if (source
== kUnknownSource
|| source
== kUnknownNotFromNode
478 || source
== kPreferredAppForNode
) {
479 if (nodePreferredApp
[0]) {
480 // file has a locally set preferred app, try getting an icon from
482 entry
= GetIconForPreferredApp(fileType
, nodePreferredApp
, mode
,
483 size
, lazyBitmap
, entry
);
485 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n",
486 __FILE__
, __LINE__
, nodePreferredApp
, fileType
, entry
));
489 source
= kPreferredAppForNode
;
490 ASSERT(entry
->HaveIconBitmap(mode
, size
));
495 if (source
== kPreferredAppForNode
)
496 source
= kUnknownSource
;
499 entry
= GetIconFromMetaMime(fileType
, mode
, size
, lazyBitmap
, entry
);
501 // Try getting a supertype handler icon
502 BMimeType
mime(fileType
);
503 if (!mime
.IsSupertypeOnly()) {
505 mime
.GetSupertype(&superType
);
506 const char* superTypeFileType
= superType
.Type();
507 if (superTypeFileType
!= NULL
) {
508 entry
= GetIconFromMetaMime(superTypeFileType
, mode
, size
,
513 PRINT(("File %s; Line %d # failed to get supertype for "
514 "type %s\n", __FILE__
, __LINE__
, fileType
));
520 ASSERT(entry
== NULL
|| entry
->HaveIconBitmap(mode
, size
));
522 if (nodePreferredApp
!= NULL
&& *nodePreferredApp
!= '\0') {
523 // we got a miss using GetIconForPreferredApp before, cache this
524 // fileType/preferredApp combo with an aliased entry
526 // make an aliased entry so that the next time we get a
527 // hit and substitute a generic icon right away
530 ("File %s; Line %d # adding entry as alias for "
531 "preferredApp %s, type %s\n",
532 __FILE__
, __LINE__
, nodePreferredApp
, fileType
));
533 IconCacheEntry
* aliasedEntry
534 = fSharedCache
.AddItem((SharedCacheEntry
**)&entry
, fileType
,
536 aliasedEntry
->SetAliasFor(&fSharedCache
,
537 (SharedCacheEntry
*)entry
);
538 // OK to cast here, have a runtime check
539 source
= kPreferredAppForNode
;
540 // set source as preferred for node, so that next time we
541 // get a hit in the initial find that uses
542 // GetIconForPreferredApp
547 if (!entry
->HaveIconBitmap(mode
, size
))
548 model
->PrintToStream();
550 ASSERT(entry
->HaveIconBitmap(mode
, size
));
557 IconCache::GetVolumeIcon(AutoLock
<SimpleIconCache
>*nodeCacheLocker
,
558 AutoLock
<SimpleIconCache
>* sharedCacheLocker
,
559 AutoLock
<SimpleIconCache
>** resultingOpenCache
,
560 Model
* model
, IconSource
&source
,
561 IconDrawMode mode
, icon_size size
, LazyBitmapAllocator
* lazyBitmap
)
563 *resultingOpenCache
= nodeCacheLocker
;
564 nodeCacheLocker
->Lock();
566 IconCacheEntry
* entry
= 0;
567 if (source
!= kUnknownSource
) {
568 // cached in the node cache
569 entry
= fNodeCache
.FindItem(model
->NodeRef());
571 entry
= IconCacheEntry::ResolveIfAlias(&fSharedCache
, entry
);
573 if (source
== kTrackerDefault
) {
574 // if tracker default, resolved entry is from shared cache
575 // this could be done a little cleaner if entry had a way to
576 // reach the cache it is in
577 *resultingOpenCache
= sharedCacheLocker
;
578 sharedCacheLocker
->Lock();
581 if (entry
->HaveIconBitmap(mode
, size
))
586 // try getting using the BVolume::GetIcon call; if miss,
587 // go for the default mime based icon
588 if (entry
== NULL
|| !entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
589 BVolume
volume(model
->NodeRef()->device
);
591 if (volume
.IsShared()) {
592 // check if it's a network share and give it a special icon
593 BBitmap
* bitmap
= lazyBitmap
->Get();
594 GetTrackerResources()->GetIconResource(R_ShareIcon
, size
, bitmap
);
597 ("File %s; Line %d # adding entry for model %s\n",
598 __FILE__
, __LINE__
, model
->Name()));
599 entry
= fNodeCache
.AddItem(model
->NodeRef());
601 entry
->SetIcon(lazyBitmap
->Adopt(), kNormalIcon
, size
);
602 } else if (volume
.GetIcon(lazyBitmap
->Get(), size
) == B_OK
) {
603 // ask the device for an icon
604 BBitmap
* bitmap
= lazyBitmap
->Adopt();
605 ASSERT(bitmap
!= NULL
);
608 ("File %s; Line %d # adding entry for model %s\n",
609 __FILE__
, __LINE__
, model
->Name()));
610 entry
= fNodeCache
.AddItem(model
->NodeRef());
612 ASSERT(entry
!= NULL
);
613 entry
->SetIcon(bitmap
, kNormalIcon
, size
);
616 *resultingOpenCache
= sharedCacheLocker
;
617 sharedCacheLocker
->Lock();
619 // if the volume doesnt have a device it gets the generic icon
620 entry
= GetIconFromMetaMime(B_VOLUME_MIMETYPE
, mode
,
621 size
, lazyBitmap
, entry
);
625 if (mode
!= kNormalIcon
&& entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
626 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
627 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
635 IconCache::GetRootIcon(AutoLock
<SimpleIconCache
>*,
636 AutoLock
<SimpleIconCache
>* sharedCacheLocker
,
637 AutoLock
<SimpleIconCache
>** resultingOpenCache
,
638 Model
*, IconSource
&source
, IconDrawMode mode
,
639 icon_size size
, LazyBitmapAllocator
* lazyBitmap
)
641 *resultingOpenCache
= sharedCacheLocker
;
642 (*resultingOpenCache
)->Lock();
644 source
= kTrackerSupplied
;
646 return GetIconFromMetaMime(B_ROOT_MIMETYPE
, mode
, size
, lazyBitmap
, 0);
651 IconCache::GetWellKnownIcon(AutoLock
<SimpleIconCache
>*,
652 AutoLock
<SimpleIconCache
>* sharedCacheLocker
,
653 AutoLock
<SimpleIconCache
>** resultingOpenCache
,
654 Model
* model
, IconSource
&source
, IconDrawMode mode
, icon_size size
,
655 LazyBitmapAllocator
* lazyBitmap
)
657 const WellKnowEntryList::WellKnownEntry
* wellKnownEntry
658 = WellKnowEntryList::MatchEntry(model
->NodeRef());
659 if (wellKnownEntry
== NULL
)
662 IconCacheEntry
* entry
= NULL
;
664 BString
type("tracker/active_");
665 type
+= wellKnownEntry
->name
;
667 *resultingOpenCache
= sharedCacheLocker
;
668 (*resultingOpenCache
)->Lock();
670 source
= kTrackerSupplied
;
672 entry
= fSharedCache
.FindItem(type
.String());
674 entry
= entry
->ResolveIfAlias(&fSharedCache
, entry
);
675 if (entry
->HaveIconBitmap(mode
, size
))
679 if (entry
== NULL
|| !entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
680 // match up well known entries in the file system with specialized
681 // icons stored in Tracker's resources
682 int32 resourceId
= -1;
683 switch ((uint32
)wellKnownEntry
->which
) {
685 resourceId
= R_BootVolumeIcon
;
688 case B_BEOS_DIRECTORY
:
689 resourceId
= R_BeosFolderIcon
;
692 case B_USER_DIRECTORY
:
693 resourceId
= R_HomeDirIcon
;
696 case B_SYSTEM_FONTS_DIRECTORY
:
697 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY
:
698 case B_USER_FONTS_DIRECTORY
:
699 case B_USER_NONPACKAGED_FONTS_DIRECTORY
:
700 resourceId
= R_FontDirIcon
;
703 case B_BEOS_APPS_DIRECTORY
:
704 case B_APPS_DIRECTORY
:
705 case B_USER_DESKBAR_APPS_DIRECTORY
:
706 resourceId
= R_AppsDirIcon
;
709 case B_BEOS_PREFERENCES_DIRECTORY
:
710 case B_PREFERENCES_DIRECTORY
:
711 case B_USER_DESKBAR_PREFERENCES_DIRECTORY
:
712 resourceId
= R_PrefsDirIcon
;
715 case B_USER_MAIL_DIRECTORY
:
716 resourceId
= R_MailDirIcon
;
719 case B_USER_QUERIES_DIRECTORY
:
720 resourceId
= R_QueryDirIcon
;
723 case B_SYSTEM_DEVELOP_DIRECTORY
:
724 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY
:
725 case B_USER_DESKBAR_DEVELOP_DIRECTORY
:
726 resourceId
= R_DevelopDirIcon
;
729 case B_USER_CONFIG_DIRECTORY
:
730 resourceId
= R_ConfigDirIcon
;
733 case B_USER_PEOPLE_DIRECTORY
:
734 resourceId
= R_PersonDirIcon
;
737 case B_USER_DOWNLOADS_DIRECTORY
:
738 resourceId
= R_DownloadDirIcon
;
745 entry
= fSharedCache
.AddItem(type
.String());
747 BBitmap
* bitmap
= lazyBitmap
->Get();
748 GetTrackerResources()->GetIconResource(resourceId
, size
, bitmap
);
749 entry
->SetIcon(lazyBitmap
->Adopt(), kNormalIcon
, size
);
752 if (mode
!= kNormalIcon
753 && entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
754 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
755 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
758 ASSERT(entry
->HaveIconBitmap(mode
, size
));
765 IconCache::GetNodeIcon(ModelNodeLazyOpener
* modelOpener
,
766 AutoLock
<SimpleIconCache
>* nodeCacheLocker
,
767 AutoLock
<SimpleIconCache
>** resultingOpenCache
,
768 Model
* model
, IconSource
& source
,
769 IconDrawMode mode
, icon_size size
,
770 LazyBitmapAllocator
* lazyBitmap
, IconCacheEntry
* entry
, bool permanent
)
772 *resultingOpenCache
= nodeCacheLocker
;
773 (*resultingOpenCache
)->Lock();
775 entry
= fNodeCache
.FindItem(model
->NodeRef());
776 if (entry
== NULL
|| !entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
777 modelOpener
->OpenNode();
781 // if we are dealing with an application, use the BAppFileInfo
782 // superset of node; this makes GetIcon grab the proper icon for
784 if (model
->IsExecutable())
785 file
= dynamic_cast<BFile
*>(model
->Node());
787 PRINT_DISK_HITS(("File %s; Line %d # hitting disk for node %s\n",
788 __FILE__
, __LINE__
, model
->Name()));
790 status_t result
= file
!= NULL
791 ? GetAppIconFromAttr(file
, lazyBitmap
->Get(), size
)
792 : GetFileIconFromAttr(model
->Node(), lazyBitmap
->Get(), size
);
794 if (result
== B_OK
) {
795 // node has its own icon, use it
796 BBitmap
* bitmap
= lazyBitmap
->Adopt();
797 PRINT_ADD_ITEM(("File %s; Line %d # adding entry for model %s\n",
798 __FILE__
, __LINE__
, model
->Name()));
799 entry
= fNodeCache
.AddItem(model
->NodeRef(), permanent
);
800 ASSERT(entry
!= NULL
);
801 entry
->SetIcon(bitmap
, kNormalIcon
, size
);
802 if (mode
!= kNormalIcon
) {
803 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
804 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
811 (*resultingOpenCache
)->Unlock();
812 *resultingOpenCache
= NULL
;
813 } else if (!entry
->HaveIconBitmap(mode
, size
)
814 && entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
815 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
816 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
817 ASSERT(entry
->HaveIconBitmap(mode
, size
));
825 IconCache::GetGenericIcon(AutoLock
<SimpleIconCache
>* sharedCacheLocker
,
826 AutoLock
<SimpleIconCache
>** resultingOpenCache
,
827 Model
* model
, IconSource
&source
,
828 IconDrawMode mode
, icon_size size
,
829 LazyBitmapAllocator
* lazyBitmap
, IconCacheEntry
* entry
)
831 *resultingOpenCache
= sharedCacheLocker
;
832 (*resultingOpenCache
)->Lock();
834 entry
= GetIconFromMetaMime(B_FILE_MIMETYPE
, mode
, size
, lazyBitmap
, 0);
838 // make an aliased entry so that the next time we get a
839 // hit and substitute a generic icon right away
841 ("File %s; Line %d # adding entry for preferredApp %s, type %s\n",
842 __FILE__
, __LINE__
, model
->PreferredAppSignature(),
844 IconCacheEntry
* aliasedEntry
= fSharedCache
.AddItem(
845 (SharedCacheEntry
**)&entry
, model
->MimeType(),
846 model
->PreferredAppSignature());
847 aliasedEntry
->SetAliasFor(&fSharedCache
, (SharedCacheEntry
*)entry
);
851 ASSERT(entry
->HaveIconBitmap(mode
, size
));
858 IconCache::GetFallbackIcon(AutoLock
<SimpleIconCache
>* sharedCacheLocker
,
859 AutoLock
<SimpleIconCache
>** resultingOpenCache
,
860 Model
* model
, IconDrawMode mode
, icon_size size
,
861 LazyBitmapAllocator
* lazyBitmap
, IconCacheEntry
* entry
)
863 *resultingOpenCache
= sharedCacheLocker
;
864 (*resultingOpenCache
)->Lock();
866 entry
= fSharedCache
.AddItem(model
->MimeType(),
867 model
->PreferredAppSignature());
869 BBitmap
* bitmap
= lazyBitmap
->Get();
870 GetTrackerResources()->GetIconResource(R_FileIcon
, size
, bitmap
);
871 entry
->SetIcon(lazyBitmap
->Adopt(), kNormalIcon
, size
);
873 if (mode
!= kNormalIcon
) {
874 entry
->ConstructBitmap(mode
, size
, lazyBitmap
);
875 entry
->SetIcon(lazyBitmap
->Adopt(), mode
, size
);
878 ASSERT(entry
->HaveIconBitmap(mode
, size
));
885 IconCache::Preload(AutoLock
<SimpleIconCache
>* nodeCacheLocker
,
886 AutoLock
<SimpleIconCache
>* sharedCacheLocker
,
887 AutoLock
<SimpleIconCache
>** resultingCache
,
888 Model
* model
, IconDrawMode mode
, icon_size size
,
891 IconCacheEntry
* entry
= NULL
;
893 AutoLock
<SimpleIconCache
>* resultingOpenCache
= NULL
;
894 // resultingOpenCache is the locker that points to the cache that
895 // ended with a hit and will be used for the drawing
898 // scope for modelOpener
900 ModelNodeLazyOpener
modelOpener(model
);
901 // this opener takes care of opening the model and possibly
902 // closing it when we are done
903 LazyBitmapAllocator
lazyBitmap(size
);
904 // lazyBitmap manages bitmap allocation and freeing if needed
906 IconSource source
= model
->IconFrom();
907 if (source
== kUnknownSource
|| source
== kUnknownNotFromNode
) {
908 // fish for special first models and handle them appropriately
909 if (model
->IsVolume()) {
910 // volume may use specialized icon in the volume node
911 entry
= GetNodeIcon(&modelOpener
, nodeCacheLocker
,
912 &resultingOpenCache
, model
, source
, mode
, size
,
913 &lazyBitmap
, entry
, permanent
);
914 if (entry
== NULL
|| !entry
->HaveIconBitmap(mode
, size
)) {
915 // look for volume defined icon
916 entry
= GetVolumeIcon(nodeCacheLocker
, sharedCacheLocker
,
917 &resultingOpenCache
, model
, source
, mode
,
920 } else if (model
->IsRoot()) {
921 entry
= GetRootIcon(nodeCacheLocker
, sharedCacheLocker
,
922 &resultingOpenCache
, model
, source
, mode
, size
,
924 ASSERT(entry
!= NULL
);
926 if (source
== kUnknownSource
) {
927 // look for node icons first
928 entry
= GetNodeIcon(&modelOpener
, nodeCacheLocker
,
929 &resultingOpenCache
, model
, source
,
930 mode
, size
, &lazyBitmap
, entry
, permanent
);
934 // no node icon, look for file type based one
935 modelOpener
.OpenNode();
936 // use file types to get the icon
937 resultingOpenCache
= sharedCacheLocker
;
938 resultingOpenCache
->Lock();
940 entry
= GetIconFromFileTypes(&modelOpener
, source
, mode
,
941 size
, &lazyBitmap
, 0);
943 // we don't have an icon, go with the generic
944 entry
= GetGenericIcon(sharedCacheLocker
,
945 &resultingOpenCache
, model
, source
, mode
,
946 size
, &lazyBitmap
, entry
);
951 // update the icon source
952 model
->SetIconFrom(source
);
954 // we already know where the icon should come from,
955 // use shortcuts to get it
958 resultingOpenCache
= nodeCacheLocker
;
959 resultingOpenCache
->Lock();
961 entry
= GetNodeIcon(&modelOpener
, nodeCacheLocker
,
962 &resultingOpenCache
, model
, source
, mode
,
963 size
, &lazyBitmap
, entry
, permanent
);
965 entry
= IconCacheEntry::ResolveIfAlias(&fSharedCache
,
967 if (!entry
->HaveIconBitmap(mode
, size
)
968 && entry
->HaveIconBitmap(NORMAL_ICON_ONLY
, size
)) {
969 entry
->ConstructBitmap(mode
, size
, &lazyBitmap
);
970 entry
->SetIcon(lazyBitmap
.Adopt(), mode
, size
);
972 ASSERT(entry
->HaveIconBitmap(mode
, size
));
975 case kTrackerSupplied
:
976 if (model
->IsRoot()) {
977 entry
= GetRootIcon(nodeCacheLocker
, sharedCacheLocker
,
978 &resultingOpenCache
, model
, source
, mode
, size
,
982 entry
= GetWellKnownIcon(nodeCacheLocker
,
983 sharedCacheLocker
, &resultingOpenCache
, model
,
984 source
, mode
, size
, &lazyBitmap
);
989 case kTrackerDefault
:
991 if (model
->IsVolume()) {
992 entry
= GetNodeIcon(&modelOpener
, nodeCacheLocker
,
993 &resultingOpenCache
, model
, source
,
994 mode
, size
, &lazyBitmap
, entry
, permanent
);
996 || !entry
->HaveIconBitmap(mode
, size
)) {
997 entry
= GetVolumeIcon(nodeCacheLocker
,
998 sharedCacheLocker
, &resultingOpenCache
, model
,
999 source
, mode
, size
, &lazyBitmap
);
1005 case kPreferredAppForType
:
1006 case kPreferredAppForNode
:
1007 resultingOpenCache
= sharedCacheLocker
;
1008 resultingOpenCache
->Lock();
1010 entry
= GetIconFromFileTypes(&modelOpener
, source
, mode
,
1011 size
, &lazyBitmap
, 0);
1012 ASSERT(entry
!= NULL
|| entry
->HaveIconBitmap(mode
, size
));
1014 if (entry
== NULL
|| !entry
->HaveIconBitmap(mode
, size
)) {
1015 // we don't have an icon, go with the generic
1016 entry
= GetGenericIcon(sharedCacheLocker
,
1017 &resultingOpenCache
, model
, source
, mode
, size
,
1018 &lazyBitmap
, entry
);
1021 model
->SetIconFrom(source
);
1022 // The source shouldn't change in this case; if it does
1023 // though we might never be hitting the correct icon and
1024 // instead keep leaking entries after each miss this now
1025 // happens if an app defines an icon but a
1026 // GetIconForType() fails and we fall back to generic
1028 // ToDo: fix this and add an assert to the effect
1030 ASSERT(entry
!= NULL
);
1031 ASSERT(entry
->HaveIconBitmap(mode
, size
));
1040 if (entry
== NULL
|| !entry
->HaveIconBitmap(mode
, size
)) {
1041 // we don't have an icon, go with the generic
1043 ("icon cache complete miss, falling back on generic icon "
1044 "for %s\n", model
->Name()));
1045 entry
= GetGenericIcon(sharedCacheLocker
, &resultingOpenCache
,
1046 model
, source
, mode
, size
, &lazyBitmap
, entry
);
1048 // we don't even have generic, something is really broken,
1049 // go with hardcoded generic icon
1050 if (entry
== NULL
|| !entry
->HaveIconBitmap(mode
, size
)) {
1052 ("icon cache complete miss, falling back on generic "
1053 "icon for %s\n", model
->Name()));
1054 entry
= GetFallbackIcon(sharedCacheLocker
,
1055 &resultingOpenCache
, model
, mode
, size
, &lazyBitmap
,
1059 // force icon pick up next time around because we probably just
1060 // hit a node in transition
1061 model
->SetIconFrom(kUnknownSource
);
1065 ASSERT(entry
!= NULL
&& entry
->HaveIconBitmap(mode
, size
));
1067 if (resultingCache
!= NULL
)
1068 *resultingCache
= resultingOpenCache
;
1075 IconCache::Draw(Model
* model
, BView
* view
, BPoint where
, IconDrawMode mode
,
1076 icon_size size
, bool async
)
1078 // the following does not actually lock the caches, we are using the
1079 // lockLater mode; we will decide which of the two to lock down depending
1080 // on where we get the icon from
1081 AutoLock
<SimpleIconCache
> nodeCacheLocker(&fNodeCache
, false);
1082 AutoLock
<SimpleIconCache
> sharedCacheLocker(&fSharedCache
, false);
1084 AutoLock
<SimpleIconCache
>* resultingCacheLocker
;
1085 IconCacheEntry
* entry
= Preload(&nodeCacheLocker
, &sharedCacheLocker
,
1086 &resultingCacheLocker
, model
, mode
, size
, false);
1087 // Preload finds/creates the appropriate entry, locking down the
1088 // cache it is in and returns the whole state back to here
1093 ASSERT(entry
!= NULL
);
1094 ASSERT(entry
->HaveIconBitmap(mode
, size
));
1095 // got the entry, now draw it
1096 resultingCacheLocker
->LockedItem()->Draw(entry
, view
, where
, mode
,
1099 // either of the two cache lockers that got locked down by this call get
1100 // unlocked at this point
1105 IconCache::SyncDraw(Model
* model
, BView
* view
, BPoint where
,
1106 IconDrawMode mode
, icon_size size
,
1107 void (*blitFunc
)(BView
*, BPoint
, BBitmap
*, void*),
1108 void* passThruState
)
1110 AutoLock
<SimpleIconCache
> nodeCacheLocker(&fNodeCache
, false);
1111 AutoLock
<SimpleIconCache
> sharedCacheLocker(&fSharedCache
, false);
1113 AutoLock
<SimpleIconCache
>* resultingCacheLocker
;
1114 IconCacheEntry
* entry
= Preload(&nodeCacheLocker
, &sharedCacheLocker
,
1115 &resultingCacheLocker
, model
, mode
, size
, false);
1120 ASSERT(entry
!= NULL
);
1121 ASSERT(entry
->HaveIconBitmap(mode
, size
));
1122 resultingCacheLocker
->LockedItem()->Draw(entry
, view
, where
,
1123 mode
, size
, blitFunc
, passThruState
);
1128 IconCache::Preload(Model
* model
, IconDrawMode mode
, icon_size size
,
1131 AutoLock
<SimpleIconCache
> nodeCacheLocker(&fNodeCache
, false);
1132 AutoLock
<SimpleIconCache
> sharedCacheLocker(&fSharedCache
, false);
1134 Preload(&nodeCacheLocker
, &sharedCacheLocker
, 0, model
, mode
, size
,
1140 IconCache::Preload(const char* fileType
, IconDrawMode mode
, icon_size size
)
1142 AutoLock
<SimpleIconCache
> sharedCacheLocker(&fSharedCache
);
1143 LazyBitmapAllocator
lazyBitmap(size
);
1145 BMimeType
mime(fileType
);
1146 char preferredAppSig
[B_MIME_TYPE_LENGTH
];
1147 status_t result
= mime
.GetPreferredApp(preferredAppSig
);
1151 // try getting the icon from the preferred app for the signature
1152 IconCacheEntry
* entry
= GetIconForPreferredApp(fileType
, preferredAppSig
,
1153 mode
, size
, &lazyBitmap
, 0);
1157 // try getting the icon directly from the metamime
1158 result
= mime
.GetIcon(lazyBitmap
.Get(), size
);
1163 entry
= fSharedCache
.AddItem(fileType
);
1164 BBitmap
* bitmap
= lazyBitmap
.Adopt();
1165 entry
->SetIcon(bitmap
, kNormalIcon
, size
);
1166 if (mode
!= kNormalIcon
) {
1167 entry
->ConstructBitmap(mode
, size
, &lazyBitmap
);
1168 entry
->SetIcon(lazyBitmap
.Adopt(), mode
, size
);
1176 IconCache::Deleting(const Model
* model
)
1178 AutoLock
<SimpleIconCache
> lock(&fNodeCache
);
1180 if (model
->IconFrom() == kNode
)
1181 fNodeCache
.Deleting(model
->NodeRef());
1183 // don't care if the node uses the shared cache
1188 IconCache::Removing(const Model
* model
)
1190 AutoLock
<SimpleIconCache
> lock(&fNodeCache
);
1192 if (model
->IconFrom() == kNode
)
1193 fNodeCache
.Removing(model
->NodeRef());
1198 IconCache::Deleting(const BView
* view
)
1200 AutoLock
<SimpleIconCache
> lock(&fNodeCache
);
1201 fNodeCache
.Deleting(view
);
1206 IconCache::IconChanged(Model
* model
)
1208 AutoLock
<SimpleIconCache
> lock(&fNodeCache
);
1210 if (model
->IconFrom() == kNode
|| model
->IconFrom() == kVolume
)
1211 fNodeCache
.Deleting(model
->NodeRef());
1213 model
->ResetIconFrom();
1218 IconCache::IconChanged(const char* mimeType
, const char* appSignature
)
1220 AutoLock
<SimpleIconCache
> sharedLock(&fSharedCache
);
1221 SharedCacheEntry
* entry
= fSharedCache
.FindItem(mimeType
, appSignature
);
1225 AutoLock
<SimpleIconCache
> nodeLock(&fNodeCache
);
1227 entry
= (SharedCacheEntry
*)fSharedCache
.ResolveIfAlias(entry
);
1228 ASSERT(entry
!= NULL
);
1229 int32 index
= fSharedCache
.EntryIndex(entry
);
1231 fNodeCache
.RemoveAliasesTo(index
);
1232 fSharedCache
.RemoveAliasesTo(index
);
1234 fSharedCache
.IconChanged(entry
);
1239 IconCache::MakeSelectedIcon(const BBitmap
* normal
, icon_size size
,
1240 LazyBitmapAllocator
* lazyBitmap
)
1242 return MakeTransformedIcon(normal
, size
, fHighlightTable
, lazyBitmap
);
1248 DumpBitmap(const BBitmap
* bitmap
)
1250 if (bitmap
== NULL
) {
1251 printf("NULL bitmap passed to DumpBitmap\n");
1254 int32 length
= bitmap
->BitsLength();
1256 printf("data length %ld \n", length
);
1258 int32 columns
= (int32
)bitmap
->Bounds().Width() + 1;
1259 const unsigned char* bitPtr
= (const unsigned char*)bitmap
->Bits();
1260 for (; length
>= 0; length
--) {
1261 for (int32 columnIndex
= 0; columnIndex
< columns
;
1262 columnIndex
++, length
--)
1263 printf("%c%c", "0123456789ABCDEF"[(*bitPtr
)/0x10],
1264 "0123456789ABCDEF"[(*bitPtr
++)%0x10]);
1274 IconCache::InitHighlightTable()
1276 // build the color transform tables for different icon modes
1277 BScreen
screen(B_MAIN_SCREEN_ID
);
1279 for (int32 index
= 0; index
< kColorTransformTableSize
; index
++) {
1280 color
= screen
.ColorForIndex((uchar
)index
);
1281 fHighlightTable
[index
] = screen
.IndexForColor(tint_color(color
, 1.3f
));
1284 fHighlightTable
[B_TRANSPARENT_8_BIT
] = B_TRANSPARENT_8_BIT
;
1285 fInitHighlightTable
= false;
1290 IconCache::MakeTransformedIcon(const BBitmap
* source
, icon_size
/*size*/,
1291 int32 colorTransformTable
[], LazyBitmapAllocator
* lazyBitmap
)
1293 if (fInitHighlightTable
)
1294 InitHighlightTable();
1296 BBitmap
* result
= lazyBitmap
->Get();
1297 uint8
* src
= (uint8
*)source
->Bits();
1298 uint8
* dst
= (uint8
*)result
->Bits();
1300 // ASSERT(result->ColorSpace() == source->ColorSpace()
1301 // && result->Bounds() == source->Bounds());
1302 if (result
->ColorSpace() != source
->ColorSpace()
1303 || result
->Bounds() != source
->Bounds()) {
1304 printf("IconCache::MakeTransformedIcon() - "
1305 "bitmap format mismatch!\n");
1309 switch (result
->ColorSpace()) {
1312 uint32 width
= source
->Bounds().IntegerWidth() + 1;
1313 uint32 height
= source
->Bounds().IntegerHeight() + 1;
1314 uint32 srcBPR
= source
->BytesPerRow();
1315 uint32 dstBPR
= result
->BytesPerRow();
1316 for (uint32 y
= 0; y
< height
; y
++) {
1319 for (uint32 x
= 0; x
< width
; x
++) {
1321 d
[0] = (int)s
[0] * 168 >> 8;
1322 d
[1] = (int)s
[1] * 168 >> 8;
1323 d
[2] = (int)s
[2] * 168 >> 8;
1335 int32 bitsLength
= result
->BitsLength();
1336 for (int32 i
= 0; i
< bitsLength
; i
++)
1337 *dst
++ = (uint8
)colorTransformTable
[*src
++];
1342 memset(dst
, 0, result
->BitsLength());
1343 // unkown colorspace, no tinting for you
1344 // "black" should make the problem stand out
1353 IconCache::IconHitTest(BPoint where
, const Model
* model
, IconDrawMode mode
,
1356 AutoLock
<SimpleIconCache
> nodeCacheLocker(&fNodeCache
, false);
1357 AutoLock
<SimpleIconCache
> sharedCacheLocker(&fSharedCache
, false);
1359 AutoLock
<SimpleIconCache
>* resultingCacheLocker
;
1360 IconCacheEntry
* entry
= Preload(&nodeCacheLocker
, &sharedCacheLocker
,
1361 &resultingCacheLocker
, const_cast<Model
*>(model
), mode
, size
, false);
1362 // Preload finds/creates the appropriate entry, locking down the
1363 // cache it is in and returns the whole state back to here
1366 return entry
->IconHitTest(where
, mode
, size
);
1373 IconCacheEntry::RetireIcons(BObjectList
<BBitmap
>* retiredBitmapList
)
1375 if (fLargeIcon
!= NULL
) {
1376 retiredBitmapList
->AddItem(fLargeIcon
);
1379 if (fHighlightedLargeIcon
!= NULL
) {
1380 retiredBitmapList
->AddItem(fHighlightedLargeIcon
);
1381 fHighlightedLargeIcon
= NULL
;
1383 if (fMiniIcon
!= NULL
) {
1384 retiredBitmapList
->AddItem(fMiniIcon
);
1387 if (fHighlightedMiniIcon
!= NULL
) {
1388 retiredBitmapList
->AddItem(fHighlightedMiniIcon
);
1389 fHighlightedMiniIcon
= NULL
;
1392 int32 count
= retiredBitmapList
->CountItems();
1393 if (count
> 10 * 1024) {
1394 PRINT(("nuking old icons from the retired bitmap list\n"));
1395 for (count
= 512; count
> 0; count
--)
1396 delete retiredBitmapList
->RemoveItemAt(0);
1401 // #pragma mark - SharedIconCache
1404 // In debug mode keep the hash table sizes small so that they grow a lot and
1405 // execercise the resizing code a lot. In release mode allocate them large
1406 // up-front for better performance
1407 SharedIconCache::SharedIconCache()
1410 SimpleIconCache("Shared icon cache aka \"The Dead-Locker\""),
1413 fRetiredBitmaps(20, true)
1415 SimpleIconCache("Tracker shared icon cache"),
1416 fElementArray(1024),
1418 fRetiredBitmaps(256, true)
1421 fHashTable
.SetElementVector(&fElementArray
);
1426 SharedIconCache::Draw(IconCacheEntry
* entry
, BView
* view
, BPoint where
,
1427 IconDrawMode mode
, icon_size size
, bool async
)
1429 ((SharedCacheEntry
*)entry
)->Draw(view
, where
, mode
, size
, async
);
1434 SharedIconCache::Draw(IconCacheEntry
* entry
, BView
* view
, BPoint where
,
1435 IconDrawMode mode
, icon_size size
, void (*blitFunc
)(BView
*, BPoint
,
1436 BBitmap
*, void*), void* passThruState
)
1438 ((SharedCacheEntry
*)entry
)->Draw(view
, where
, mode
, size
,
1439 blitFunc
, passThruState
);
1444 SharedIconCache::FindItem(const char* fileType
,
1445 const char* appSignature
) const
1449 fileType
= B_FILE_MIMETYPE
;
1451 SharedCacheEntry
* result
1452 = fHashTable
.FindFirst(SharedCacheEntry::Hash(fileType
,
1459 if (result
->fFileType
== fileType
1460 && result
->fAppSignature
== appSignature
) {
1464 if (result
->fNext
< 0)
1467 result
= const_cast<SharedCacheEntry
*>(&fElementArray
.At(
1476 SharedIconCache::AddItem(const char* fileType
, const char* appSignature
)
1478 ASSERT(fileType
!= NULL
);
1479 if (fileType
== NULL
)
1480 fileType
= B_FILE_MIMETYPE
;
1482 SharedCacheEntry
* result
= fHashTable
.Add(SharedCacheEntry::Hash(fileType
,
1484 result
->SetTo(fileType
, appSignature
);
1491 SharedIconCache::AddItem(SharedCacheEntry
** outstandingEntry
,
1492 const char* fileType
, const char* appSignature
)
1494 int32 entryToken
= fHashTable
.ElementIndex(*outstandingEntry
);
1495 ASSERT(entryToken
>= 0);
1497 ASSERT(fileType
!= NULL
);
1498 if (fileType
== NULL
)
1499 fileType
= B_FILE_MIMETYPE
;
1501 SharedCacheEntry
* result
= fHashTable
.Add(SharedCacheEntry::Hash(fileType
,
1503 result
->SetTo(fileType
, appSignature
);
1504 *outstandingEntry
= fHashTable
.ElementAt(entryToken
);
1511 SharedIconCache::IconChanged(SharedCacheEntry
* entry
)
1513 // by now there should be no aliases to entry, just remove entry
1515 ASSERT(entry
->fAliasForIndex
== -1);
1516 entry
->RetireIcons(&fRetiredBitmaps
);
1517 fHashTable
.Remove(entry
);
1522 SharedIconCache::RemoveAliasesTo(int32 aliasIndex
)
1524 int32 count
= fHashTable
.VectorSize();
1525 for (int32 index
= 0; index
< count
; index
++) {
1526 SharedCacheEntry
* entry
= fHashTable
.ElementAt(index
);
1527 if (entry
->fAliasForIndex
== aliasIndex
)
1528 fHashTable
.Remove(entry
);
1534 SharedIconCache::SetAliasFor(IconCacheEntry
* entry
,
1535 const SharedCacheEntry
* original
) const
1537 entry
->fAliasForIndex
= fHashTable
.ElementIndex(original
);
1541 SharedCacheEntry::SharedCacheEntry()
1548 SharedCacheEntry::SharedCacheEntry(const char* fileType
,
1549 const char* appSignature
)
1552 fFileType(fileType
),
1553 fAppSignature(appSignature
)
1559 SharedCacheEntry::Draw(BView
* view
, BPoint where
, IconDrawMode mode
,
1560 icon_size size
, bool async
)
1562 BBitmap
* bitmap
= IconForMode(mode
, size
);
1563 ASSERT(bitmap
!= NULL
);
1565 drawing_mode oldMode
= view
->DrawingMode();
1567 if (bitmap
->ColorSpace() == B_RGBA32
) {
1568 if (oldMode
!= B_OP_ALPHA
) {
1569 view
->SetDrawingMode(B_OP_ALPHA
);
1570 view
->SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_OVERLAY
);
1573 view
->SetDrawingMode(B_OP_OVER
);
1576 view
->DrawBitmapAsync(bitmap
, where
);
1578 view
->DrawBitmap(bitmap
, where
);
1580 view
->SetDrawingMode(oldMode
);
1585 SharedCacheEntry::Draw(BView
* view
, BPoint where
, IconDrawMode mode
,
1586 icon_size size
, void (*blitFunc
)(BView
*, BPoint
, BBitmap
*, void*),
1587 void* passThruState
)
1589 BBitmap
* bitmap
= IconForMode(mode
, size
);
1593 (blitFunc
)(view
, where
, bitmap
, passThruState
);
1598 SharedCacheEntry::Hash(const char* fileType
, const char* appSignature
)
1600 uint32 hash
= HashString(fileType
, 0);
1601 if (appSignature
!= NULL
&& *appSignature
!= '\0')
1602 hash
= HashString(appSignature
, hash
);
1609 SharedCacheEntry::Hash() const
1611 uint32 hash
= HashString(fFileType
.String(), 0);
1612 if (fAppSignature
.Length() > 0)
1613 hash
= HashString(fAppSignature
.String(), hash
);
1620 SharedCacheEntry::operator==(const SharedCacheEntry
&entry
) const
1622 return fFileType
== entry
.FileType()
1623 && fAppSignature
== entry
.AppSignature();
1628 SharedCacheEntry::SetTo(const char* fileType
, const char* appSignature
)
1630 fFileType
= fileType
;
1631 fAppSignature
= appSignature
;
1635 SharedCacheEntryArray::SharedCacheEntryArray(int32 initialSize
)
1637 OpenHashElementArray
<SharedCacheEntry
>(initialSize
)
1643 SharedCacheEntryArray::Add()
1645 return OpenHashElementArray
<SharedCacheEntry
>::Add();
1649 // #pragma mark - NodeCacheEntry
1652 NodeCacheEntry::NodeCacheEntry(bool permanent
)
1655 fPermanent(permanent
)
1660 NodeCacheEntry::NodeCacheEntry(const node_ref
* node
, bool permanent
)
1664 fPermanent(permanent
)
1670 NodeCacheEntry::Draw(BView
* view
, BPoint where
, IconDrawMode mode
,
1671 icon_size size
, bool async
)
1673 BBitmap
* bitmap
= IconForMode(mode
, size
);
1677 drawing_mode oldMode
= view
->DrawingMode();
1679 if (bitmap
->ColorSpace() == B_RGBA32
) {
1680 if (oldMode
!= B_OP_ALPHA
) {
1681 view
->SetDrawingMode(B_OP_ALPHA
);
1682 view
->SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_OVERLAY
);
1685 view
->SetDrawingMode(B_OP_OVER
);
1687 if (false && async
) {
1689 // need to copy the bits first in here
1690 view
->DrawBitmapAsync(bitmap
, where
);
1692 view
->DrawBitmap(bitmap
, where
);
1694 view
->SetDrawingMode(oldMode
);
1699 NodeCacheEntry::Draw(BView
* view
, BPoint where
, IconDrawMode mode
,
1700 icon_size size
, void (*blitFunc
)(BView
*, BPoint
, BBitmap
*, void*),
1701 void* passThruState
)
1703 BBitmap
* bitmap
= IconForMode(mode
, size
);
1707 (blitFunc
)(view
, where
, bitmap
, passThruState
);
1712 NodeCacheEntry::Node() const
1719 NodeCacheEntry::Hash() const
1726 NodeCacheEntry::Hash(const node_ref
* node
)
1728 return node
->device
^ ((uint32
*)&node
->node
)[0]
1729 ^ ((uint32
*)&node
->node
)[1];
1734 NodeCacheEntry::operator==(const NodeCacheEntry
&entry
) const
1736 return fRef
== entry
.fRef
;
1741 NodeCacheEntry::SetTo(const node_ref
* node
)
1748 NodeCacheEntry::Permanent() const
1755 NodeCacheEntry::MakePermanent()
1761 // #pragma mark - NodeIconCache
1764 NodeIconCache::NodeIconCache()
1767 SimpleIconCache("Node icon cache aka \"The Dead-Locker\""),
1771 SimpleIconCache("Tracker node icon cache"),
1776 fHashTable
.SetElementVector(&fElementArray
);
1781 NodeIconCache::Draw(IconCacheEntry
* entry
, BView
* view
, BPoint where
,
1782 IconDrawMode mode
, icon_size size
, bool async
)
1784 ((NodeCacheEntry
*)entry
)->Draw(view
, where
, mode
, size
, async
);
1789 NodeIconCache::Draw(IconCacheEntry
* entry
, BView
* view
, BPoint where
,
1790 IconDrawMode mode
, icon_size size
,
1791 void (*blitFunc
)(BView
*, BPoint
, BBitmap
*, void*), void* passThruState
)
1793 ((NodeCacheEntry
*)entry
)->Draw(view
, where
, mode
, size
,
1794 blitFunc
, passThruState
);
1799 NodeIconCache::FindItem(const node_ref
* node
) const
1801 NodeCacheEntry
* entry
= fHashTable
.FindFirst(NodeCacheEntry::Hash(node
));
1806 if (*entry
->Node() == *node
)
1809 if (entry
->fNext
< 0)
1812 entry
= const_cast<NodeCacheEntry
*>(&fElementArray
.At(entry
->fNext
));
1820 NodeIconCache::AddItem(const node_ref
* node
, bool permanent
)
1822 NodeCacheEntry
* entry
= fHashTable
.Add(NodeCacheEntry::Hash(node
));
1825 entry
->MakePermanent();
1832 NodeIconCache::AddItem(NodeCacheEntry
** outstandingEntry
,
1833 const node_ref
* node
)
1835 int32 entryToken
= fHashTable
.ElementIndex(*outstandingEntry
);
1837 NodeCacheEntry
* entry
= fHashTable
.Add(NodeCacheEntry::Hash(node
));
1839 *outstandingEntry
= fHashTable
.ElementAt(entryToken
);
1846 NodeIconCache::Deleting(const node_ref
* node
)
1848 NodeCacheEntry
* entry
= FindItem(node
);
1849 ASSERT(entry
!= NULL
);
1850 if (entry
== NULL
|| entry
->Permanent())
1853 fHashTable
.Remove(entry
);
1858 NodeIconCache::Removing(const node_ref
* node
)
1860 NodeCacheEntry
* entry
= FindItem(node
);
1861 ASSERT(entry
!= NULL
);
1865 fHashTable
.Remove(entry
);
1870 NodeIconCache::Deleting(const BView
*)
1872 #ifdef NODE_CACHE_ASYNC_DRAWS
1879 NodeIconCache::IconChanged(const Model
* model
)
1881 Deleting(model
->NodeRef());
1886 NodeIconCache::RemoveAliasesTo(int32 aliasIndex
)
1888 int32 count
= fHashTable
.VectorSize();
1889 for (int32 index
= 0; index
< count
; index
++) {
1890 NodeCacheEntry
* entry
= fHashTable
.ElementAt(index
);
1891 if (entry
->fAliasForIndex
== aliasIndex
)
1892 fHashTable
.Remove(entry
);
1897 // #pragma mark - NodeCacheEntryArray
1900 NodeCacheEntryArray::NodeCacheEntryArray(int32 initialSize
)
1902 OpenHashElementArray
<NodeCacheEntry
>(initialSize
)
1908 NodeCacheEntryArray::Add()
1910 return OpenHashElementArray
<NodeCacheEntry
>::Add();
1914 // #pragma mark - SimpleIconCache
1917 SimpleIconCache::SimpleIconCache(const char* name
)
1925 SimpleIconCache::Draw(IconCacheEntry
*, BView
*, BPoint
, IconDrawMode
,
1929 // pure virtual, do nothing
1934 SimpleIconCache::Draw(IconCacheEntry
*, BView
*, BPoint
, IconDrawMode
,
1935 icon_size
, void(*)(BView
*, BPoint
, BBitmap
*, void*), void*)
1938 // pure virtual, do nothing
1943 SimpleIconCache::Lock()
1945 return fLock
.Lock();
1950 SimpleIconCache::Unlock()
1957 SimpleIconCache::IsLocked() const
1959 return fLock
.IsLocked();
1963 // #pragma mark - LazyBitmapAllocator
1966 LazyBitmapAllocator::LazyBitmapAllocator(icon_size size
,
1967 color_space colorSpace
, bool preallocate
)
1971 fColorSpace(colorSpace
)
1978 LazyBitmapAllocator::~LazyBitmapAllocator()
1985 LazyBitmapAllocator::Get()
1987 if (fBitmap
== NULL
)
1988 fBitmap
= new BBitmap(BRect(0, 0, fSize
- 1, fSize
- 1), fColorSpace
);
1995 LazyBitmapAllocator::Adopt()
1997 if (fBitmap
== NULL
)
2000 BBitmap
* bitmap
= fBitmap
;
2007 IconCache
* IconCache::sIconCache
;