RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / kits / tracker / IconCache.cpp
blobe09980f96a03df7210e4a08d263a0ce82241a684
1 /*
2 Open Tracker License
4 Terms and Conditions
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.
32 All rights reserved.
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
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
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
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
66 #include <Debug.h>
67 #include <Screen.h>
68 #include <Volume.h>
70 #include <fs_info.h>
72 #include "Bitmaps.h"
73 #include "FSUtils.h"
74 #include "IconCache.h"
75 #include "MimeTypes.h"
76 #include "Model.h"
79 //#if DEBUG
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
85 //#endif
87 // set up a few printing macros to get rid of a ton of debugging ifdefs
88 // in the code
89 #ifdef LOG_DISK_HITS
90 # define PRINT_DISK_HITS(ARGS) _debugPrintf ARGS
91 #else
92 # define PRINT_DISK_HITS(ARGS) (void)0
93 #endif
95 #ifdef LOG_ADD_ITEM
96 # define PRINT_ADD_ITEM(ARGS) _debugPrintf ARGS
97 #else
98 # define PRINT_ADD_ITEM(ARGS) (void)0
99 #endif
101 #undef NODE_CACHE_ASYNC_DRAWS
104 IconCacheEntry::IconCacheEntry()
106 fLargeIcon(NULL),
107 fHighlightedLargeIcon(NULL),
108 fMiniIcon(NULL),
109 fHighlightedMiniIcon(NULL),
110 fAliasForIndex(-1)
115 IconCacheEntry::~IconCacheEntry()
117 if (fAliasForIndex < 0) {
118 delete fLargeIcon;
119 delete fHighlightedLargeIcon;
120 delete fMiniIcon;
121 delete fHighlightedMiniIcon;
123 // clean up a bit to leave the hash table entry in an initialized state
124 fLargeIcon = NULL;
125 fHighlightedLargeIcon = NULL;
126 fMiniIcon = NULL;
127 fHighlightedMiniIcon = NULL;
129 fAliasForIndex = -1;
133 void
134 IconCacheEntry::SetAliasFor(const SharedIconCache* sharedCache,
135 const SharedCacheEntry* entry)
137 sharedCache->SetAliasFor(this, entry);
138 ASSERT(fAliasForIndex >= 0);
142 IconCacheEntry*
143 IconCacheEntry::ResolveIfAlias(const SharedIconCache* sharedCache)
145 return sharedCache->ResolveIfAlias(this);
149 IconCacheEntry*
150 IconCacheEntry::ResolveIfAlias(const SharedIconCache* sharedCache,
151 IconCacheEntry* entry)
153 if (entry == NULL)
154 return NULL;
156 return sharedCache->ResolveIfAlias(entry);
160 bool
161 IconCacheEntry::CanConstructBitmap(IconDrawMode mode, icon_size) const
163 if (mode == kSelected) {
164 // for now only
165 return true;
168 return false;
172 bool
173 IconCacheEntry::HaveIconBitmap(IconDrawMode mode, icon_size size) const
175 ASSERT(mode == kSelected || mode == kNormalIcon);
176 // for now only
178 if (mode == kNormalIcon) {
179 return size == B_MINI_ICON ? fMiniIcon != NULL
180 : fLargeIcon != 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;
188 return false;
192 BBitmap*
193 IconCacheEntry::IconForMode(IconDrawMode mode, icon_size size) const
195 ASSERT(mode == kSelected || mode == kNormalIcon);
196 // for now only
198 if (mode == kNormalIcon) {
199 if (size == B_MINI_ICON)
200 return fMiniIcon;
201 else
202 return fLargeIcon;
203 } else if (mode == kSelected) {
204 if (size == B_MINI_ICON)
205 return fHighlightedMiniIcon;
206 else
207 return fHighlightedLargeIcon;
210 return NULL;
214 bool
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);
220 if (bitmap == NULL)
221 return false;
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))
229 return true;
231 switch (bitmap->ColorSpace()) {
232 case B_RGBA32:
233 // test alpha channel
234 return *(bits + (int32)(floorf(where.y) * bitmap->BytesPerRow()
235 + floorf(where.x) * 4 + 3)) > 20;
237 case B_CMAP8:
238 return *(bits + (int32)(floorf(where.y) * size + where.x))
239 != B_TRANSPARENT_8_BIT;
241 default:
242 return true;
247 BBitmap*
248 IconCacheEntry::ConstructBitmap(BBitmap* constructFrom,
249 IconDrawMode requestedMode, IconDrawMode constructFromMode,
250 icon_size size, LazyBitmapAllocator* lazyBitmap)
252 ASSERT(requestedMode == kSelected && constructFromMode == kNormalIcon);
253 // for now
255 if (requestedMode == kSelected && constructFromMode == kNormalIcon) {
256 return IconCache::sIconCache->MakeSelectedIcon(constructFrom, size,
257 lazyBitmap);
260 return NULL;
264 BBitmap*
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,
272 lazyBitmap);
276 bool
277 IconCacheEntry::AlternateModeForIconConstructing(IconDrawMode requestedMode,
278 IconDrawMode &alternate, icon_size)
280 if ((requestedMode & kSelected) != 0) {
281 // for now
282 alternate = kNormalIcon;
283 return true;
286 return false;
290 void
291 IconCacheEntry::SetIcon(BBitmap* bitmap, IconDrawMode mode, icon_size size,
292 bool /*create*/)
294 if (mode == kNormalIcon) {
295 if (size == B_MINI_ICON)
296 fMiniIcon = bitmap;
297 else
298 fLargeIcon = bitmap;
299 } else if (mode == kSelectedIcon) {
300 if (size == B_MINI_ICON)
301 fHighlightedMiniIcon = bitmap;
302 else
303 fHighlightedLargeIcon = bitmap;
304 } else
305 TRESPASS();
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.
326 IconCacheEntry*
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')
334 return NULL;
336 if (entry == NULL) {
337 entry = fSharedCache.FindItem(fileTypeSignature, preferredApp);
338 if (entry != NULL) {
339 entry = entry->ResolveIfAlias(&fSharedCache, entry);
340 #if xDEBUG
341 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n",
342 __FILE__, __LINE__, preferredApp, fileTypeSignature, entry));
343 #endif
344 if (entry->HaveIconBitmap(mode, size))
345 return entry;
349 if (entry == NULL || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
350 PRINT_DISK_HITS(
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);
356 signature.ToLower();
357 if (preferredAppType.GetIconForType(signature.String(),
358 lazyBitmap->Get(), size) != B_OK) {
359 return NULL;
362 BBitmap* bitmap = lazyBitmap->Adopt();
363 if (entry == NULL) {
364 PRINT_ADD_ITEM(
365 ("File %s; Line %d # adding entry for preferredApp %s, "
366 "type %s\n", __FILE__, __LINE__, preferredApp,
367 fileTypeSignature));
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);
379 return entry;
383 IconCacheEntry*
384 IconCache::GetIconFromMetaMime(const char* fileType, IconDrawMode mode,
385 icon_size size, LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry)
387 ASSERT(fSharedCache.IsLocked());
389 if (entry == NULL)
390 entry = fSharedCache.FindItem(fileType);
392 if (entry != NULL) {
393 entry = entry->ResolveIfAlias(&fSharedCache, entry);
394 // metamime defines an icon and we have it cached
395 if (entry->HaveIconBitmap(mode, size))
396 return entry;
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)
409 return NULL;
411 SharedCacheEntry* aliasTo = NULL;
412 if (entry != NULL) {
413 aliasTo
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);
421 if (aliasTo == NULL)
422 return NULL;
424 // make an aliased entry so that the next time we get a
425 // hit on the first FindItem in here
426 if (entry == NULL) {
427 PRINT_ADD_ITEM(
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));
434 return aliasTo;
437 // at this point, we've found an icon for the MIME type
438 BBitmap* bitmap = lazyBitmap->Adopt();
439 if (entry == NULL) {
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);
455 #if xDEBUG
456 if (!entry->HaveIconBitmap(mode, size))
457 PRINT(("failing on %s, mode %ld, size %ld\n", fileType, mode, size));
458 #endif
460 ASSERT(entry->HaveIconBitmap(mode, size));
462 return entry;
466 IconCacheEntry*
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
481 // there
482 entry = GetIconForPreferredApp(fileType, nodePreferredApp, mode,
483 size, lazyBitmap, entry);
484 #if xDEBUG
485 PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n",
486 __FILE__, __LINE__, nodePreferredApp, fileType, entry));
487 #endif
488 if (entry != NULL) {
489 source = kPreferredAppForNode;
490 ASSERT(entry->HaveIconBitmap(mode, size));
492 return entry;
495 if (source == kPreferredAppForNode)
496 source = kUnknownSource;
499 entry = GetIconFromMetaMime(fileType, mode, size, lazyBitmap, entry);
500 if (entry == NULL) {
501 // Try getting a supertype handler icon
502 BMimeType mime(fileType);
503 if (!mime.IsSupertypeOnly()) {
504 BMimeType superType;
505 mime.GetSupertype(&superType);
506 const char* superTypeFileType = superType.Type();
507 if (superTypeFileType != NULL) {
508 entry = GetIconFromMetaMime(superTypeFileType, mode, size,
509 lazyBitmap, entry);
511 #if DEBUG
512 else {
513 PRINT(("File %s; Line %d # failed to get supertype for "
514 "type %s\n", __FILE__, __LINE__, fileType));
516 #endif
520 ASSERT(entry == NULL || entry->HaveIconBitmap(mode, size));
521 if (entry != NULL) {
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
529 PRINT_ADD_ITEM(
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,
535 nodePreferredApp);
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
543 } else
544 source = kMetaMime;
546 #if DEBUG
547 if (!entry->HaveIconBitmap(mode, size))
548 model->PrintToStream();
549 #endif
550 ASSERT(entry->HaveIconBitmap(mode, size));
553 return entry;
556 IconCacheEntry*
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());
570 if (entry != NULL) {
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))
582 return entry;
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);
595 if (entry == NULL) {
596 PRINT_ADD_ITEM(
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);
606 if (entry == NULL) {
607 PRINT_ADD_ITEM(
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);
614 source = kVolume;
615 } else {
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);
630 return entry;
634 IconCacheEntry*
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);
650 IconCacheEntry*
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)
660 return 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());
673 if (entry != NULL) {
674 entry = entry->ResolveIfAlias(&fSharedCache, entry);
675 if (entry->HaveIconBitmap(mode, size))
676 return entry;
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) {
684 case B_BOOT_DISK:
685 resourceId = R_BootVolumeIcon;
686 break;
688 case B_BEOS_DIRECTORY:
689 resourceId = R_BeosFolderIcon;
690 break;
692 case B_USER_DIRECTORY:
693 resourceId = R_HomeDirIcon;
694 break;
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;
701 break;
703 case B_BEOS_APPS_DIRECTORY:
704 case B_APPS_DIRECTORY:
705 case B_USER_DESKBAR_APPS_DIRECTORY:
706 resourceId = R_AppsDirIcon;
707 break;
709 case B_BEOS_PREFERENCES_DIRECTORY:
710 case B_PREFERENCES_DIRECTORY:
711 case B_USER_DESKBAR_PREFERENCES_DIRECTORY:
712 resourceId = R_PrefsDirIcon;
713 break;
715 case B_USER_MAIL_DIRECTORY:
716 resourceId = R_MailDirIcon;
717 break;
719 case B_USER_QUERIES_DIRECTORY:
720 resourceId = R_QueryDirIcon;
721 break;
723 case B_SYSTEM_DEVELOP_DIRECTORY:
724 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY:
725 case B_USER_DESKBAR_DEVELOP_DIRECTORY:
726 resourceId = R_DevelopDirIcon;
727 break;
729 case B_USER_CONFIG_DIRECTORY:
730 resourceId = R_ConfigDirIcon;
731 break;
733 case B_USER_PEOPLE_DIRECTORY:
734 resourceId = R_PersonDirIcon;
735 break;
737 case B_USER_DOWNLOADS_DIRECTORY:
738 resourceId = R_DownloadDirIcon;
739 break;
741 default:
742 return NULL;
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));
760 return entry;
764 IconCacheEntry*
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();
779 BFile* file = NULL;
781 // if we are dealing with an application, use the BAppFileInfo
782 // superset of node; this makes GetIcon grab the proper icon for
783 // an app
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);
806 source = kNode;
810 if (entry == NULL) {
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));
820 return entry;
824 IconCacheEntry*
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);
835 if (entry == NULL)
836 return NULL;
838 // make an aliased entry so that the next time we get a
839 // hit and substitute a generic icon right away
840 PRINT_ADD_ITEM(
841 ("File %s; Line %d # adding entry for preferredApp %s, type %s\n",
842 __FILE__, __LINE__, model->PreferredAppSignature(),
843 model->MimeType()));
844 IconCacheEntry* aliasedEntry = fSharedCache.AddItem(
845 (SharedCacheEntry**)&entry, model->MimeType(),
846 model->PreferredAppSignature());
847 aliasedEntry->SetAliasFor(&fSharedCache, (SharedCacheEntry*)entry);
849 source = kMetaMime;
851 ASSERT(entry->HaveIconBitmap(mode, size));
853 return entry;
857 IconCacheEntry*
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));
880 return entry;
884 IconCacheEntry*
885 IconCache::Preload(AutoLock<SimpleIconCache>* nodeCacheLocker,
886 AutoLock<SimpleIconCache>* sharedCacheLocker,
887 AutoLock<SimpleIconCache>** resultingCache,
888 Model* model, IconDrawMode mode, icon_size size,
889 bool permanent)
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,
918 size, &lazyBitmap);
920 } else if (model->IsRoot()) {
921 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker,
922 &resultingOpenCache, model, source, mode, size,
923 &lazyBitmap);
924 ASSERT(entry != NULL);
925 } else {
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);
933 if (entry == NULL) {
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);
942 if (entry == NULL) {
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);
953 } else {
954 // we already know where the icon should come from,
955 // use shortcuts to get it
956 switch (source) {
957 case kNode:
958 resultingOpenCache = nodeCacheLocker;
959 resultingOpenCache->Lock();
961 entry = GetNodeIcon(&modelOpener, nodeCacheLocker,
962 &resultingOpenCache, model, source, mode,
963 size, &lazyBitmap, entry, permanent);
964 if (entry != NULL) {
965 entry = IconCacheEntry::ResolveIfAlias(&fSharedCache,
966 entry);
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));
974 break;
975 case kTrackerSupplied:
976 if (model->IsRoot()) {
977 entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker,
978 &resultingOpenCache, model, source, mode, size,
979 &lazyBitmap);
980 break;
981 } else {
982 entry = GetWellKnownIcon(nodeCacheLocker,
983 sharedCacheLocker, &resultingOpenCache, model,
984 source, mode, size, &lazyBitmap);
985 if (entry != NULL)
986 break;
988 // fall through
989 case kTrackerDefault:
990 case kVolume:
991 if (model->IsVolume()) {
992 entry = GetNodeIcon(&modelOpener, nodeCacheLocker,
993 &resultingOpenCache, model, source,
994 mode, size, &lazyBitmap, entry, permanent);
995 if (entry == NULL
996 || !entry->HaveIconBitmap(mode, size)) {
997 entry = GetVolumeIcon(nodeCacheLocker,
998 sharedCacheLocker, &resultingOpenCache, model,
999 source, mode, size, &lazyBitmap);
1001 break;
1003 // fall through
1004 case kMetaMime:
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
1027 // icon.
1028 // ToDo: fix this and add an assert to the effect
1030 ASSERT(entry != NULL);
1031 ASSERT(entry->HaveIconBitmap(mode, size));
1032 break;
1034 default:
1035 TRESPASS();
1036 break;
1040 if (entry == NULL || !entry->HaveIconBitmap(mode, size)) {
1041 // we don't have an icon, go with the generic
1042 PRINT(
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)) {
1051 PRINT(
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,
1056 entry);
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;
1070 return entry;
1074 void
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
1090 if (entry == NULL)
1091 return;
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,
1097 size, async);
1099 // either of the two cache lockers that got locked down by this call get
1100 // unlocked at this point
1104 void
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);
1117 if (entry == NULL)
1118 return;
1120 ASSERT(entry != NULL);
1121 ASSERT(entry->HaveIconBitmap(mode, size));
1122 resultingCacheLocker->LockedItem()->Draw(entry, view, where,
1123 mode, size, blitFunc, passThruState);
1127 void
1128 IconCache::Preload(Model* model, IconDrawMode mode, icon_size size,
1129 bool permanent)
1131 AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false);
1132 AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false);
1134 Preload(&nodeCacheLocker, &sharedCacheLocker, 0, model, mode, size,
1135 permanent);
1139 status_t
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);
1148 if (result != B_OK)
1149 return result;
1151 // try getting the icon from the preferred app for the signature
1152 IconCacheEntry* entry = GetIconForPreferredApp(fileType, preferredAppSig,
1153 mode, size, &lazyBitmap, 0);
1154 if (entry != NULL)
1155 return B_OK;
1157 // try getting the icon directly from the metamime
1158 result = mime.GetIcon(lazyBitmap.Get(), size);
1160 if (result != B_OK)
1161 return result;
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);
1171 return B_OK;
1175 void
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
1187 void
1188 IconCache::Removing(const Model* model)
1190 AutoLock<SimpleIconCache> lock(&fNodeCache);
1192 if (model->IconFrom() == kNode)
1193 fNodeCache.Removing(model->NodeRef());
1197 void
1198 IconCache::Deleting(const BView* view)
1200 AutoLock<SimpleIconCache> lock(&fNodeCache);
1201 fNodeCache.Deleting(view);
1205 void
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();
1217 void
1218 IconCache::IconChanged(const char* mimeType, const char* appSignature)
1220 AutoLock<SimpleIconCache> sharedLock(&fSharedCache);
1221 SharedCacheEntry* entry = fSharedCache.FindItem(mimeType, appSignature);
1222 if (entry == NULL)
1223 return;
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);
1238 BBitmap*
1239 IconCache::MakeSelectedIcon(const BBitmap* normal, icon_size size,
1240 LazyBitmapAllocator* lazyBitmap)
1242 return MakeTransformedIcon(normal, size, fHighlightTable, lazyBitmap);
1246 #if xDEBUG
1247 static void
1248 DumpBitmap(const BBitmap* bitmap)
1250 if (bitmap == NULL) {
1251 printf("NULL bitmap passed to DumpBitmap\n");
1252 return;
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]);
1266 printf("\n");
1268 printf("\n");
1270 #endif
1273 void
1274 IconCache::InitHighlightTable()
1276 // build the color transform tables for different icon modes
1277 BScreen screen(B_MAIN_SCREEN_ID);
1278 rgb_color color;
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;
1289 BBitmap*
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");
1306 return NULL;
1309 switch (result->ColorSpace()) {
1310 case B_RGB32:
1311 case B_RGBA32: {
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++) {
1317 uint8* d = dst;
1318 uint8* s = src;
1319 for (uint32 x = 0; x < width; x++) {
1320 // 66% brightness
1321 d[0] = (int)s[0] * 168 >> 8;
1322 d[1] = (int)s[1] * 168 >> 8;
1323 d[2] = (int)s[2] * 168 >> 8;
1324 d[3] = s[3];
1325 d += 4;
1326 s += 4;
1328 dst += dstBPR;
1329 src += srcBPR;
1331 break;
1334 case B_CMAP8: {
1335 int32 bitsLength = result->BitsLength();
1336 for (int32 i = 0; i < bitsLength; i++)
1337 *dst++ = (uint8)colorTransformTable[*src++];
1338 break;
1341 default:
1342 memset(dst, 0, result->BitsLength());
1343 // unkown colorspace, no tinting for you
1344 // "black" should make the problem stand out
1345 break;
1348 return result;
1352 bool
1353 IconCache::IconHitTest(BPoint where, const Model* model, IconDrawMode mode,
1354 icon_size size)
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
1365 if (entry != NULL)
1366 return entry->IconHitTest(where, mode, size);
1368 return false;
1372 void
1373 IconCacheEntry::RetireIcons(BObjectList<BBitmap>* retiredBitmapList)
1375 if (fLargeIcon != NULL) {
1376 retiredBitmapList->AddItem(fLargeIcon);
1377 fLargeIcon = NULL;
1379 if (fHighlightedLargeIcon != NULL) {
1380 retiredBitmapList->AddItem(fHighlightedLargeIcon);
1381 fHighlightedLargeIcon = NULL;
1383 if (fMiniIcon != NULL) {
1384 retiredBitmapList->AddItem(fMiniIcon);
1385 fMiniIcon = NULL;
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()
1409 #if DEBUG
1410 SimpleIconCache("Shared icon cache aka \"The Dead-Locker\""),
1411 fElementArray(20),
1412 fHashTable(20),
1413 fRetiredBitmaps(20, true)
1414 #else
1415 SimpleIconCache("Tracker shared icon cache"),
1416 fElementArray(1024),
1417 fHashTable(1000),
1418 fRetiredBitmaps(256, true)
1419 #endif
1421 fHashTable.SetElementVector(&fElementArray);
1425 void
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);
1433 void
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);
1443 SharedCacheEntry*
1444 SharedIconCache::FindItem(const char* fileType,
1445 const char* appSignature) const
1447 ASSERT(fileType);
1448 if (!fileType)
1449 fileType = B_FILE_MIMETYPE;
1451 SharedCacheEntry* result
1452 = fHashTable.FindFirst(SharedCacheEntry::Hash(fileType,
1453 appSignature));
1455 if (result == NULL)
1456 return NULL;
1458 for(;;) {
1459 if (result->fFileType == fileType
1460 && result->fAppSignature == appSignature) {
1461 return result;
1464 if (result->fNext < 0)
1465 break;
1467 result = const_cast<SharedCacheEntry*>(&fElementArray.At(
1468 result->fNext));
1471 return NULL;
1475 SharedCacheEntry*
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,
1483 appSignature));
1484 result->SetTo(fileType, appSignature);
1486 return result;
1490 SharedCacheEntry*
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,
1502 appSignature));
1503 result->SetTo(fileType, appSignature);
1504 *outstandingEntry = fHashTable.ElementAt(entryToken);
1506 return result;
1510 void
1511 SharedIconCache::IconChanged(SharedCacheEntry* entry)
1513 // by now there should be no aliases to entry, just remove entry
1514 // itself
1515 ASSERT(entry->fAliasForIndex == -1);
1516 entry->RetireIcons(&fRetiredBitmaps);
1517 fHashTable.Remove(entry);
1521 void
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);
1533 void
1534 SharedIconCache::SetAliasFor(IconCacheEntry* entry,
1535 const SharedCacheEntry* original) const
1537 entry->fAliasForIndex = fHashTable.ElementIndex(original);
1541 SharedCacheEntry::SharedCacheEntry()
1543 fNext(-1)
1548 SharedCacheEntry::SharedCacheEntry(const char* fileType,
1549 const char* appSignature)
1551 fNext(-1),
1552 fFileType(fileType),
1553 fAppSignature(appSignature)
1558 void
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);
1572 } else
1573 view->SetDrawingMode(B_OP_OVER);
1575 if (async)
1576 view->DrawBitmapAsync(bitmap, where);
1577 else
1578 view->DrawBitmap(bitmap, where);
1580 view->SetDrawingMode(oldMode);
1584 void
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);
1590 if (bitmap == NULL)
1591 return;
1593 (blitFunc)(view, where, bitmap, passThruState);
1597 uint32
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);
1604 return hash;
1608 uint32
1609 SharedCacheEntry::Hash() const
1611 uint32 hash = HashString(fFileType.String(), 0);
1612 if (fAppSignature.Length() > 0)
1613 hash = HashString(fAppSignature.String(), hash);
1615 return hash;
1619 bool
1620 SharedCacheEntry::operator==(const SharedCacheEntry &entry) const
1622 return fFileType == entry.FileType()
1623 && fAppSignature == entry.AppSignature();
1627 void
1628 SharedCacheEntry::SetTo(const char* fileType, const char* appSignature)
1630 fFileType = fileType;
1631 fAppSignature = appSignature;
1635 SharedCacheEntryArray::SharedCacheEntryArray(int32 initialSize)
1637 OpenHashElementArray<SharedCacheEntry>(initialSize)
1642 SharedCacheEntry*
1643 SharedCacheEntryArray::Add()
1645 return OpenHashElementArray<SharedCacheEntry>::Add();
1649 // #pragma mark - NodeCacheEntry
1652 NodeCacheEntry::NodeCacheEntry(bool permanent)
1654 fNext(-1),
1655 fPermanent(permanent)
1660 NodeCacheEntry::NodeCacheEntry(const node_ref* node, bool permanent)
1662 fNext(-1),
1663 fRef(*node),
1664 fPermanent(permanent)
1669 void
1670 NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode,
1671 icon_size size, bool async)
1673 BBitmap* bitmap = IconForMode(mode, size);
1674 if (bitmap == NULL)
1675 return;
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);
1684 } else
1685 view->SetDrawingMode(B_OP_OVER);
1687 if (false && async) {
1688 TRESPASS();
1689 // need to copy the bits first in here
1690 view->DrawBitmapAsync(bitmap, where);
1691 } else
1692 view->DrawBitmap(bitmap, where);
1694 view->SetDrawingMode(oldMode);
1698 void
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);
1704 if (bitmap == NULL)
1705 return;
1707 (blitFunc)(view, where, bitmap, passThruState);
1711 const node_ref*
1712 NodeCacheEntry::Node() const
1714 return &fRef;
1718 uint32
1719 NodeCacheEntry::Hash() const
1721 return Hash(&fRef);
1725 uint32
1726 NodeCacheEntry::Hash(const node_ref* node)
1728 return node->device ^ ((uint32*)&node->node)[0]
1729 ^ ((uint32*)&node->node)[1];
1733 bool
1734 NodeCacheEntry::operator==(const NodeCacheEntry &entry) const
1736 return fRef == entry.fRef;
1740 void
1741 NodeCacheEntry::SetTo(const node_ref* node)
1743 fRef = *node;
1747 bool
1748 NodeCacheEntry::Permanent() const
1750 return fPermanent;
1754 void
1755 NodeCacheEntry::MakePermanent()
1757 fPermanent = true;
1761 // #pragma mark - NodeIconCache
1764 NodeIconCache::NodeIconCache()
1766 #if DEBUG
1767 SimpleIconCache("Node icon cache aka \"The Dead-Locker\""),
1768 fElementArray(20),
1769 fHashTable(20)
1770 #else
1771 SimpleIconCache("Tracker node icon cache"),
1772 fElementArray(100),
1773 fHashTable(100)
1774 #endif
1776 fHashTable.SetElementVector(&fElementArray);
1780 void
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);
1788 void
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);
1798 NodeCacheEntry*
1799 NodeIconCache::FindItem(const node_ref* node) const
1801 NodeCacheEntry* entry = fHashTable.FindFirst(NodeCacheEntry::Hash(node));
1802 if (entry == NULL)
1803 return NULL;
1805 for(;;) {
1806 if (*entry->Node() == *node)
1807 return entry;
1809 if (entry->fNext < 0)
1810 break;
1812 entry = const_cast<NodeCacheEntry*>(&fElementArray.At(entry->fNext));
1815 return NULL;
1819 NodeCacheEntry*
1820 NodeIconCache::AddItem(const node_ref* node, bool permanent)
1822 NodeCacheEntry* entry = fHashTable.Add(NodeCacheEntry::Hash(node));
1823 entry->SetTo(node);
1824 if (permanent)
1825 entry->MakePermanent();
1827 return entry;
1831 NodeCacheEntry*
1832 NodeIconCache::AddItem(NodeCacheEntry** outstandingEntry,
1833 const node_ref* node)
1835 int32 entryToken = fHashTable.ElementIndex(*outstandingEntry);
1837 NodeCacheEntry* entry = fHashTable.Add(NodeCacheEntry::Hash(node));
1838 entry->SetTo(node);
1839 *outstandingEntry = fHashTable.ElementAt(entryToken);
1841 return entry;
1845 void
1846 NodeIconCache::Deleting(const node_ref* node)
1848 NodeCacheEntry* entry = FindItem(node);
1849 ASSERT(entry != NULL);
1850 if (entry == NULL || entry->Permanent())
1851 return;
1853 fHashTable.Remove(entry);
1857 void
1858 NodeIconCache::Removing(const node_ref* node)
1860 NodeCacheEntry* entry = FindItem(node);
1861 ASSERT(entry != NULL);
1862 if (entry == NULL)
1863 return;
1865 fHashTable.Remove(entry);
1869 void
1870 NodeIconCache::Deleting(const BView*)
1872 #ifdef NODE_CACHE_ASYNC_DRAWS
1873 TRESPASS();
1874 #endif
1878 void
1879 NodeIconCache::IconChanged(const Model* model)
1881 Deleting(model->NodeRef());
1885 void
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)
1907 NodeCacheEntry*
1908 NodeCacheEntryArray::Add()
1910 return OpenHashElementArray<NodeCacheEntry>::Add();
1914 // #pragma mark - SimpleIconCache
1917 SimpleIconCache::SimpleIconCache(const char* name)
1919 fLock(name)
1924 void
1925 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
1926 icon_size, bool)
1928 TRESPASS();
1929 // pure virtual, do nothing
1933 void
1934 SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
1935 icon_size, void(*)(BView*, BPoint, BBitmap*, void*), void*)
1937 TRESPASS();
1938 // pure virtual, do nothing
1942 bool
1943 SimpleIconCache::Lock()
1945 return fLock.Lock();
1949 void
1950 SimpleIconCache::Unlock()
1952 fLock.Unlock();
1956 bool
1957 SimpleIconCache::IsLocked() const
1959 return fLock.IsLocked();
1963 // #pragma mark - LazyBitmapAllocator
1966 LazyBitmapAllocator::LazyBitmapAllocator(icon_size size,
1967 color_space colorSpace, bool preallocate)
1969 fBitmap(NULL),
1970 fSize(size),
1971 fColorSpace(colorSpace)
1973 if (preallocate)
1974 Get();
1978 LazyBitmapAllocator::~LazyBitmapAllocator()
1980 delete fBitmap;
1984 BBitmap*
1985 LazyBitmapAllocator::Get()
1987 if (fBitmap == NULL)
1988 fBitmap = new BBitmap(BRect(0, 0, fSize - 1, fSize - 1), fColorSpace);
1990 return fBitmap;
1994 BBitmap*
1995 LazyBitmapAllocator::Adopt()
1997 if (fBitmap == NULL)
1998 Get();
2000 BBitmap* bitmap = fBitmap;
2001 fBitmap = NULL;
2003 return bitmap;
2007 IconCache* IconCache::sIconCache;