xref: /haiku/src/kits/tracker/IconCache.h (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 #ifndef _NU_ICON_CACHE_H
35 #define _NU_ICON_CACHE_H
36 
37 
38 // Icon cache is used for drawing node icons; it caches icons
39 // and reuses them for successive draws
40 
41 
42 #include <Bitmap.h>
43 #include <ObjectList.h>
44 #include <Mime.h>
45 #include <String.h>
46 
47 #include "AutoLock.h"
48 #include "HashSet.h"
49 #include "Utilities.h"
50 
51 
52 // Icon cache splits icons into two caches - the shared cache, likely to
53 // get the most hits and the node cache. Every icon that is found in a
54 // mime-based structure goes into the shared cache, only files that have
55 // their own private icon use the node cache;
56 // Entries are only deleted from the shared cache if an icon for a mime type
57 // changes, this makes async icon drawing easier. Node cache deletes it's
58 // entries whenever a file gets deleted.
59 
60 // if a view ever uses the cache to draw in async mode, it needs to call
61 // it when it is being destroyed
62 
63 namespace BPrivate {
64 
65 class Model;
66 class ModelNodeLazyOpener;
67 class LazyBitmapAllocator;
68 class SharedIconCache;
69 class SharedCacheEntry;
70 class GenerateThumbnailJob;
71 
72 enum IconDrawMode {
73 	// Different states of icon drawing
74 	kSelected 					= 0x01,
75 	kNotFocused					= 0x02,		// Tracker window
76 	kOpen						= 0x04,		// open folder, trash
77 	kNotEmpty					= 0x08,		// full trash
78 	kDisabled					= 0x10,		// inactive nav menu entry
79 	kActive						= 0x20,		// active home dir, boot volume
80 	kLink						= 0x40,		// symbolic link
81 	kTrackerSpecialized			= 0x80,
82 
83 	// some common combinations
84 	kNormalIcon						= 0,
85 	kSelectedIcon					= kSelected,
86 	kSelectedInBackgroundIcon		= kSelected | kNotFocused,
87 	kOpenIcon						= kOpen,
88 	kOpenSelectedIcon				= kSelected | kOpen,
89 	kOpenSelectedInBackgroundIcon	= kSelected | kNotFocused | kOpen,
90 	kFullIcon						= kNotEmpty,
91 	kFullSelectedIcon				= kNotEmpty | kOpen,
92 	kDimmedIcon
93 };
94 
95 
96 #define NORMAL_ICON_ONLY kNormalIcon
97 	// replace use of these defines with mode once the respective getters
98 	// can get non-plain icons
99 
100 
101 // Where did an icon come from
102 enum IconSource {
103 	kUnknownSource,
104 	kUnknownNotFromNode,	// icon origin not known but determined not
105 							// to be from the node itself
106 	kTrackerDefault,		// file has no type, Tracker provides generic,
107 							// folder, symlink or app
108 	kTrackerSupplied,		// home directory, boot volume, trash, etc.
109 	kMetaMime,				// from BMimeType
110 	kPreferredAppForType,	// have a preferred application for a type,
111 							// has an icon
112 	kPreferredAppForNode,	// have a preferred application for this node,
113 							// has an icon
114 	kVolume,
115 	kNode
116 };
117 
118 
119 template<typename Class>
120 struct SelfHashing {
121 	typedef typename Class::HashKeyType KeyType;
122 	typedef Class ValueType;
123 
124 	size_t HashKey(KeyType key) const
125 	{
126 		return Class::Hash(key);
127 	}
128 
129 	size_t Hash(ValueType* value) const
130 	{
131 		return value->Hash();
132 	}
133 
134 	bool Compare(KeyType key, ValueType* value) const
135 	{
136 		return *value == key;
137 	}
138 
139 	ValueType*& GetLink(ValueType* value) const
140 	{
141 		return value->HashNext();
142 	}
143 };
144 
145 
146 class IconCacheEntry {
147 	// aliased entries don't own their icons, just point
148 	// to some other entry that does
149 
150 	// This is used for icons that are defined by a preferred app for
151 	// a metamime, types that do not have an icon get to point to
152 	// generic, etc.
153 
154 public:
155 	IconCacheEntry();
156 	~IconCacheEntry();
157 
158 	void SetAliasFor(const SharedIconCache* sharedCache,
159 		const SharedCacheEntry* entry);
160 	static IconCacheEntry* ResolveIfAlias(const SharedIconCache* sharedCache,
161 		IconCacheEntry* entry);
162 	IconCacheEntry* ResolveIfAlias(const SharedIconCache* sharedCache);
163 
164 	void SetIcon(BBitmap* bitmap, IconDrawMode mode, icon_size size,
165 		bool create = false);
166 
167 	bool HaveIconBitmap(IconDrawMode mode, icon_size size) const;
168 	bool CanConstructBitmap(IconDrawMode mode, icon_size size) const;
169 	static bool AlternateModeForIconConstructing(IconDrawMode requestedMode,
170 		IconDrawMode &alternate, icon_size size);
171 	BBitmap* ConstructBitmap(BBitmap* constructFrom,
172 		IconDrawMode requestedMode, IconDrawMode constructFromMode,
173 		icon_size size, LazyBitmapAllocator*);
174 	BBitmap* ConstructBitmap(IconDrawMode requestedMode, icon_size size,
175 		LazyBitmapAllocator*);
176 		// same as above, always uses normal icon as source
177 
178 	bool IconHitTest(BPoint, IconDrawMode, icon_size) const;
179 		// given a point, returns true if a non-transparent pixel was hit
180 
181 	void RetireIcons(BObjectList<BBitmap>* retiredBitmapList);
182 		// can't just delete icons, they may be still drawing
183 		// async; instead, put them on the retired list and
184 		// only delete the list if it grows too much, way after
185 		// the icon finishes drawing
186 		//
187 		// This could fail if we retire a lot of icons (10 * 1024)
188 		// while we are drawing them, shouldn't be a practical problem
189 
190 protected:
191 	BBitmap* IconForMode(IconDrawMode mode, icon_size size) const;
192 	void SetIconForMode(BBitmap* bitmap, IconDrawMode mode, icon_size size);
193 
194 	// list of most common icons
195 	BBitmap* fLargeIcon;
196 	BBitmap* fHighlightedLargeIcon;
197 	BBitmap* fMiniIcon;
198 	BBitmap* fHighlightedMiniIcon;
199 
200 	const IconCacheEntry* fAliasTo;
201 
202 	// list of other icon kinds would be added here
203 
204 	friend class SharedIconCache;
205 	friend class NodeIconCache;
206 };
207 
208 
209 class SimpleIconCache {
210 public:
211 	SimpleIconCache(const char*);
212 	virtual ~SimpleIconCache() {}
213 
214 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode mode,
215 		icon_size size, bool async = false) = 0;
216 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
217 		icon_size, void (*)(BView*, BPoint, BBitmap*, void*),
218 		void* = NULL) = 0;
219 
220 	bool Lock();
221 	void Unlock();
222 	bool IsLocked() const;
223 
224 private:
225 	Benaphore fLock;
226 };
227 
228 
229 class SharedCacheEntry : public IconCacheEntry {
230 public:
231 	SharedCacheEntry();
232 	SharedCacheEntry(const char* fileType, const char* appSignature = 0);
233 
234 	void Draw(BView*, BPoint, IconDrawMode mode, icon_size size,
235 		bool async = false);
236 
237 	void Draw(BView*, BPoint, IconDrawMode, icon_size,
238 		void (*)(BView*, BPoint, BBitmap*, void*), void* = NULL);
239 
240 	const char* FileType() const;
241 	const char* AppSignature() const;
242 
243 public:
244 	// hash table support
245 	struct TypeAndSignature {
246 		const char* type, *signature;
247 		TypeAndSignature(const char* t, const char* s)
248 			: type(t), signature(s) {}
249 	};
250 	typedef TypeAndSignature HashKeyType;
251 	static size_t Hash(const TypeAndSignature& typeAndSignature);
252 
253 	size_t Hash() const;
254 	SharedCacheEntry*& HashNext() { return fNext; }
255 	bool operator==(const TypeAndSignature& typeAndSignature) const;
256 
257 private:
258 	SharedCacheEntry* fNext;
259 
260 	BString fFileType;
261 	BString fAppSignature;
262 
263 	friend class SharedIconCache;
264 };
265 
266 
267 class SharedIconCache : public SimpleIconCache {
268 	// SharedIconCache is used for icons that come from the mime database
269 public:
270 	SharedIconCache();
271 
272 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode mode,
273 		icon_size size, bool async = false);
274 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
275 		icon_size, void (*)(BView*, BPoint, BBitmap*, void*), void* = NULL);
276 
277 	SharedCacheEntry* FindItem(const char* fileType,
278 		const char* appSignature = 0) const;
279 	SharedCacheEntry* AddItem(const char* fileType,
280 		const char* appSignature = 0);
281 	void IconChanged(SharedCacheEntry*);
282 
283 	void SetAliasFor(IconCacheEntry* entry,
284 		const SharedCacheEntry* original) const;
285 	IconCacheEntry* ResolveIfAlias(IconCacheEntry* entry) const;
286 
287 	void RemoveAliasesTo(SharedCacheEntry* alias);
288 
289 private:
290 	typedef BOpenHashTable<SelfHashing<SharedCacheEntry> > EntryHashTable;
291 	EntryHashTable fHashTable;
292 
293 	BObjectList<BBitmap> fRetiredBitmaps;
294 		// icons are drawn asynchronously, can't just delete them right away,
295 		// instead have to place them onto the retired bitmap list and wait
296 		// for the next sync to delete them
297 };
298 
299 
300 class NodeCacheEntry : public IconCacheEntry {
301 public:
302 	NodeCacheEntry(bool permanent = false);
303 	NodeCacheEntry(const node_ref*, bool permanent = false);
304 	void Draw(BView*, BPoint, IconDrawMode mode, icon_size size,
305 		bool async = false);
306 
307 	void Draw(BView*, BPoint, IconDrawMode, icon_size,
308 		void (*)(BView*, BPoint, BBitmap*, void*), void* = NULL);
309 
310 	const node_ref* Node() const;
311 
312 	bool Permanent() const;
313 
314 public:
315 	// hash table support
316 	typedef const node_ref* HashKeyType;
317 	static size_t Hash(const node_ref* node);
318 
319 	size_t Hash() const;
320 	NodeCacheEntry*& HashNext() { return fNext; }
321 	bool operator==(const node_ref* ref) const;
322 
323 private:
324 	NodeCacheEntry* fNext;
325 
326 	node_ref fRef;
327 	bool fPermanent;
328 		// special cache entry that has to be deleted explicitly
329 
330 	friend class NodeIconCache;
331 };
332 
333 
334 class NodeIconCache : public SimpleIconCache {
335 	// NodeIconCache is used for nodes that define their own icons
336 public:
337 	NodeIconCache();
338 
339 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
340 		icon_size, bool async = false);
341 
342 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
343 		icon_size, void (*)(BView*, BPoint, BBitmap*, void*), void* = 0);
344 
345 	NodeCacheEntry* FindItem(const node_ref*) const;
346 	NodeCacheEntry* AddItem(const node_ref*, bool permanent = false);
347 	void Deleting(const node_ref*);
348 		// model for this node is getting deleted
349 		// (not necessarily the node itself)
350 	void Removing(const node_ref*);
351 		// used by permanent NodeIconCache entries, when an entry gets deleted
352 	void Deleting(const BView*);
353 	void IconChanged(const Model*);
354 
355 	void RemoveAliasesTo(SharedCacheEntry* alias);
356 
357 private:
358 	typedef BOpenHashTable<SelfHashing<NodeCacheEntry> > EntryHashTable;
359 	EntryHashTable fHashTable;
360 };
361 
362 
363 const int32 kColorTransformTableSize = 256;
364 
365 
366 class IconCache {
367 public:
368 	IconCache();
369 
370 	void Draw(Model*, BView*, BPoint where, IconDrawMode mode,
371 		icon_size size, bool async = false);
372 		// draw an icon for a model, load the icon from the appropriate
373 		// location if not cached already
374 
375 	void SyncDraw(Model*, BView*, BPoint, IconDrawMode,
376 		icon_size, void (*)(BView*, BPoint, BBitmap*, void*),
377 		void* passThruState = 0);
378 		// draw an icon for a model, load the icon from the appropriate
379 		// location if not cached already; only works for sync draws,
380 		// once the call returns, the bitmap may be deleted
381 
382 	// preload calls used to ensure successive cache hit for the respective
383 	// icon, used for common tracker types, etc; Not calling these should only
384 	// cause a slowdown
385 	void Preload(Model*, IconDrawMode mode, icon_size size,
386 		bool permanent = false);
387 	status_t Preload(const char* mimeType, IconDrawMode mode, icon_size size);
388 
389 	void Deleting(const Model*);
390 		// hook to manage unloading icons for nodes that are going away
391 	void Removing(const Model* model);
392 		// used by permanent NodeIconCache entries, when an entry gets
393 		// deleted
394 	void Deleting(const BView*);
395 		// hook to manage deleting draw view caches for views that are
396 		// going away
397 
398 	// icon changed calls, used when a node or a file type has an icon changed
399 	// the icons for the node/file type will be flushed and re-cached during
400 	// the next draw
401 	void IconChanged(Model*);
402 	void IconChanged(const char* mimeType, const char* appSignature);
403 
404 	bool IsIconFrom(const Model*, const char* mimeType,
405 		const char* appSignature) const;
406 		// called when metamime database changed to figure out which models
407 		// to redraw
408 
409 	bool IconHitTest(BPoint, const Model*, IconDrawMode, icon_size);
410 
411 	// utility calls for building specialized icons
412 	BBitmap* MakeSelectedIcon(const BBitmap* normal, icon_size,
413 		LazyBitmapAllocator*);
414 
415 	static bool NeedsDeletionNotification(IconSource);
416 
417 	static IconCache* sIconCache;
418 
419 private:
420 	// shared calls
421 	IconCacheEntry* Preload(AutoLock<SimpleIconCache>* nodeCache,
422 		AutoLock<SimpleIconCache>* sharedCache,
423 		AutoLock<SimpleIconCache>** resultingLockedCache,
424 		Model*, IconDrawMode mode, icon_size size, bool permanent);
425 		// preload uses lazy locking, returning the cache we decided
426 		// to use to get the icon
427 		// <resultingLockedCache> may be null if we don't care
428 
429 	// shared mime-based icon retrieval calls
430 	IconCacheEntry* GetIconForPreferredApp(const char* mimeTypeSignature,
431 		const char* preferredApp, IconDrawMode mode, icon_size size,
432 		 LazyBitmapAllocator*, IconCacheEntry*);
433 	IconCacheEntry* GetIconFromFileTypes(ModelNodeLazyOpener*,
434 		IconSource &source, IconDrawMode mode, icon_size size,
435 		LazyBitmapAllocator*, IconCacheEntry*);
436 	IconCacheEntry* GetIconFromMetaMime(const char* fileType,
437 		IconDrawMode mode, icon_size size, LazyBitmapAllocator*,
438 		IconCacheEntry*);
439 	IconCacheEntry* GetVolumeIcon(AutoLock<SimpleIconCache>* nodeCache,
440 		AutoLock<SimpleIconCache>* sharedCache,
441 		AutoLock<SimpleIconCache>** resultingLockedCache,
442 		Model*, IconSource&, IconDrawMode mode,
443 		icon_size size, LazyBitmapAllocator*);
444 	IconCacheEntry* GetRootIcon(AutoLock<SimpleIconCache>* nodeCache,
445 		AutoLock<SimpleIconCache>* sharedCache,
446 		AutoLock<SimpleIconCache>** resultingLockedCache,
447 		Model*, IconSource&, IconDrawMode mode,
448 		icon_size size, LazyBitmapAllocator*);
449 	IconCacheEntry* GetWellKnownIcon(AutoLock<SimpleIconCache> *nodeCache,
450 		AutoLock<SimpleIconCache>* sharedCache,
451 		AutoLock<SimpleIconCache>** resultingLockedCache,
452 		Model*, IconSource&, IconDrawMode mode,
453 		icon_size size, LazyBitmapAllocator*);
454 	IconCacheEntry* GetNodeIcon(ModelNodeLazyOpener *,
455 		AutoLock<SimpleIconCache>* nodeCache,
456 		AutoLock<SimpleIconCache>** resultingLockedCache,
457 		Model*, IconSource&, IconDrawMode mode,
458 		icon_size size, LazyBitmapAllocator*, IconCacheEntry*,
459 		bool permanent);
460 	IconCacheEntry* GetGenericIcon(AutoLock<SimpleIconCache>* sharedCache,
461 		AutoLock<SimpleIconCache>** resultingLockedCache,
462 		Model*, IconSource&, IconDrawMode mode,
463 		icon_size size, LazyBitmapAllocator*, IconCacheEntry*);
464 	IconCacheEntry* GetFallbackIcon(
465 		AutoLock<SimpleIconCache>* sharedCacheLocker,
466 		AutoLock<SimpleIconCache>** resultingOpenCache,
467 		Model* model, IconDrawMode mode, icon_size size,
468 		LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry);
469 
470 	BBitmap* MakeTransformedIcon(const BBitmap*, icon_size,
471 		int32 colorTransformTable [], LazyBitmapAllocator*);
472 
473 	NodeIconCache fNodeCache;
474 	SharedIconCache fSharedCache;
475 
476 	void InitHighlightTable();
477 
478 	int32 fHighlightTable[kColorTransformTableSize];
479 	bool fInitHighlightTable;
480 		// whether or not we need to initialize the highlight table
481 
482 	friend class BPrivate::GenerateThumbnailJob;
483 };
484 
485 
486 class LazyBitmapAllocator {
487 	// Utility class used when we aren't sure that we will keep a bitmap,
488 	// need a bitmap or be able to construct it properly
489 public:
490 	LazyBitmapAllocator(icon_size size,
491 		color_space colorSpace = kDefaultIconDepth,
492 		bool preallocate = false);
493 	~LazyBitmapAllocator();
494 
495 	BBitmap* Get();
496 	BBitmap* Adopt();
497 
498 private:
499 	BBitmap* fBitmap;
500 	icon_size fSize;
501 	color_space fColorSpace;
502 };
503 
504 
505 // inlines follow
506 
507 inline const char*
508 SharedCacheEntry::FileType() const
509 {
510 	return fFileType.String();
511 }
512 
513 
514 inline const char*
515 SharedCacheEntry::AppSignature() const
516 {
517 	return fAppSignature.String();
518 }
519 
520 
521 inline bool
522 IconCache::NeedsDeletionNotification(IconSource from)
523 {
524 	return from == kNode;
525 }
526 
527 
528 inline IconCacheEntry*
529 SharedIconCache::ResolveIfAlias(IconCacheEntry* entry) const
530 {
531 	if (entry->fAliasTo == NULL)
532 		return entry;
533 
534 	return const_cast<IconCacheEntry*>(entry->fAliasTo);
535 }
536 
537 
538 } // namespace BPrivate
539 
540 using namespace BPrivate;
541 
542 
543 #endif	// _NU_ICON_CACHE_H
544