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