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
35//	NodePreloader manages caching up icons from apps and prefs folder for
36//	fast display
37//
38
39#include <Debug.h>
40#include <Directory.h>
41#include <Entry.h>
42#include <FindDirectory.h>
43#include <Node.h>
44#include <NodeMonitor.h>
45#include <Path.h>
46
47#include "AutoLock.h"
48#include "IconCache.h"
49#include "NodePreloader.h"
50#include "Thread.h"
51#include "Tracker.h"
52
53
54NodePreloader*
55NodePreloader::InstallNodePreloader(const char* name, BLooper* host)
56{
57	NodePreloader* result = new NodePreloader(name);
58	{
59		AutoLock<BLooper> lock(host);
60		if (!lock) {
61			delete result;
62			return NULL;
63		}
64
65		host->AddHandler(result);
66	}
67	result->Run();
68
69	return result;
70}
71
72
73NodePreloader::NodePreloader(const char* name)
74	:
75	BHandler(name),
76	fModelList(20, true),
77	fQuitRequested(false)
78{
79}
80
81
82NodePreloader::~NodePreloader()
83{
84	// block deletion while we are locked
85	fQuitRequested = true;
86	fLock.Lock();
87}
88
89
90void
91NodePreloader::Run()
92{
93	fLock.Lock();
94	Thread::Launch(NewMemberFunctionObject(&NodePreloader::Preload, this));
95}
96
97
98Model*
99NodePreloader::FindModel(node_ref itemNode) const
100{
101	for (int32 count = fModelList.CountItems() - 1; count >= 0; count--) {
102		Model* model = fModelList.ItemAt(count);
103		if (*model->NodeRef() == itemNode)
104			return model;
105	}
106
107	return NULL;
108}
109
110
111void
112NodePreloader::MessageReceived(BMessage* message)
113{
114	// respond to node monitor notifications
115
116	node_ref itemNode;
117	switch (message->what) {
118		case B_NODE_MONITOR:
119		{
120			switch (message->FindInt32("opcode")) {
121				case B_ENTRY_REMOVED:
122				{
123					AutoLock<Benaphore> locker(fLock);
124					message->FindInt32("device", &itemNode.device);
125					message->FindInt64("node", &itemNode.node);
126					Model* model = FindModel(itemNode);
127					if (model == NULL)
128						break;
129
130					//PRINT(("preloader removing file %s\n", model->Name()));
131					IconCache::sIconCache->Removing(model);
132					fModelList.RemoveItem(model);
133					break;
134				}
135
136				case B_ATTR_CHANGED:
137				case B_STAT_CHANGED:
138				{
139					AutoLock<Benaphore> locker(fLock);
140					message->FindInt32("device", &itemNode.device);
141					message->FindInt64("node", &itemNode.node);
142
143					const char* attrName;
144					message->FindString("attr", &attrName);
145					Model* model = FindModel(itemNode);
146					if (model == NULL)
147						break;
148
149					BModelOpener opener(model);
150					IconCache::sIconCache->IconChanged(model->ResolveIfLink());
151					//PRINT(("preloader updating file %s\n", model->Name()));
152					break;
153				}
154			}
155			break;
156		}
157
158		default:
159			_inherited::MessageReceived(message);
160			break;
161	}
162}
163
164
165void
166NodePreloader::PreloadOne(const char* dirPath)
167{
168	//PRINT(("preloading directory %s\n", dirPath));
169	BDirectory dir(dirPath);
170	if (dir.InitCheck() != B_OK)
171		return;
172
173	node_ref nodeRef;
174	dir.GetNodeRef(&nodeRef);
175
176	// have to node monitor the whole directory
177	TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, this);
178
179	dir.Rewind();
180	for (;;) {
181		entry_ref ref;
182		if (dir.GetNextRef(&ref) != B_OK)
183			break;
184
185		BEntry entry(&ref);
186		if (!entry.IsFile())
187			// only interrested in files
188			continue;
189
190		Model* model = new Model(&ref, true);
191		if (model->InitCheck() == B_OK && model->IconFrom() == kUnknownSource) {
192			TTracker::WatchNode(model->NodeRef(),
193				B_WATCH_STAT | B_WATCH_ATTR, this);
194			IconCache::sIconCache->Preload(model, kNormalIcon, B_MINI_ICON,
195				true);
196			fModelList.AddItem(model);
197			model->CloseNode();
198		} else
199			delete model;
200	}
201}
202
203
204void
205NodePreloader::Preload()
206{
207	for (int32 count = 100; count >= 0; count--) {
208		// wait for a little bit before going ahead to reduce disk access
209		// contention
210		snooze(100000);
211		if (fQuitRequested) {
212			fLock.Unlock();
213			return;
214		}
215	}
216
217	BMessenger messenger(kTrackerSignature);
218	if (!messenger.IsValid()) {
219		// put out some message here!
220		return;
221	}
222
223	ASSERT(fLock.IsLocked());
224	BPath path;
225	if (find_directory(B_BEOS_APPS_DIRECTORY, &path) == B_OK)
226		PreloadOne(path.Path());
227
228	if (find_directory(B_BEOS_PREFERENCES_DIRECTORY, &path) == B_OK)
229		PreloadOne(path.Path());
230
231	fLock.Unlock();
232}
233