#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Node.h>
#include <NodeMonitor.h>
#include <Path.h>
#include "AutoLock.h"
#include "IconCache.h"
#include "NodePreloader.h"
#include "Thread.h"
#include "Tracker.h"
NodePreloader*
NodePreloader::InstallNodePreloader(const char* name, BLooper* host)
{
NodePreloader* result = new NodePreloader(name);
{
AutoLock<BLooper> lock(host);
if (!lock) {
delete result;
return NULL;
}
host->AddHandler(result);
}
result->Run();
return result;
}
NodePreloader::NodePreloader(const char* name)
:
BHandler(name),
fModelList(20),
fQuitRequested(false)
{
}
NodePreloader::~NodePreloader()
{
fQuitRequested = true;
fLock.Lock();
}
void
NodePreloader::Run()
{
fLock.Lock();
Thread::Launch(NewMemberFunctionObject(&NodePreloader::Preload, this));
}
Model*
NodePreloader::FindModel(node_ref itemNode) const
{
for (int32 count = fModelList.CountItems() - 1; count >= 0; count--) {
Model* model = fModelList.ItemAt(count);
if (*model->NodeRef() == itemNode)
return model;
}
return NULL;
}
void
NodePreloader::MessageReceived(BMessage* message)
{
node_ref itemNode;
switch (message->what) {
case B_NODE_MONITOR:
{
switch (message->GetInt32("opcode", 0)) {
case B_ENTRY_REMOVED:
{
AutoLock<Benaphore> locker(fLock);
message->FindInt32("device", &itemNode.device);
message->FindInt64("node", &itemNode.node);
Model* model = FindModel(itemNode);
if (model == NULL)
break;
IconCache::sIconCache->Removing(model);
fModelList.RemoveItem(model);
break;
}
case B_ATTR_CHANGED:
case B_STAT_CHANGED:
{
AutoLock<Benaphore> locker(fLock);
message->FindInt32("device", &itemNode.device);
message->FindInt64("node", &itemNode.node);
const char* attrName;
message->FindString("attr", &attrName);
Model* model = FindModel(itemNode);
if (model == NULL)
break;
BModelOpener opener(model);
IconCache::sIconCache->IconChanged(model->ResolveIfLink());
break;
}
}
break;
}
default:
_inherited::MessageReceived(message);
break;
}
}
void
NodePreloader::PreloadOne(const char* dirPath)
{
BDirectory dir(dirPath);
if (dir.InitCheck() != B_OK)
return;
node_ref nodeRef;
dir.GetNodeRef(&nodeRef);
TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, this);
dir.Rewind();
for (;;) {
entry_ref ref;
if (dir.GetNextRef(&ref) != B_OK)
break;
BEntry entry(&ref);
if (!entry.IsFile())
continue;
Model* model = new Model(&ref, true);
if (model->InitCheck() == B_OK && model->IconFrom() == kUnknownSource) {
TTracker::WatchNode(model->NodeRef(),
B_WATCH_STAT | B_WATCH_ATTR, this);
IconCache::sIconCache->Preload(model, kNormalIcon,
IconCache::sMiniIconSize, true);
fModelList.AddItem(model);
model->CloseNode();
} else
delete model;
}
}
void
NodePreloader::Preload()
{
for (int32 count = 100; count >= 0; count--) {
snooze(100000);
if (fQuitRequested) {
fLock.Unlock();
return;
}
}
BMessenger messenger(kTrackerSignature);
if (!messenger.IsValid()) {
return;
}
ASSERT(fLock.IsLocked());
BPath path;
if (find_directory(B_BEOS_APPS_DIRECTORY, &path) == B_OK)
PreloadOne(path.Path());
if (find_directory(B_BEOS_PREFERENCES_DIRECTORY, &path) == B_OK)
PreloadOne(path.Path());
fLock.Unlock();
}