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