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