#include "TrashWatcher.h"
#include <string.h>
#include <Debug.h>
#include <Directory.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Volume.h>
#include <VolumeRoster.h>
#include "Attributes.h"
#include "Bitmaps.h"
#include "FSUtils.h"
#include "IconCache.h"
#include "Tracker.h"
BTrashWatcher::BTrashWatcher()
:
BLooper("TrashWatcher", B_LOW_PRIORITY),
fTrashNodeList(20)
{
FSCreateTrashDirs();
WatchTrashDirs();
fTrashFull = CheckTrashDirs();
UpdateTrashIcon();
TTracker::WatchNode(0, B_WATCH_MOUNT, this);
}
thread_id
BTrashWatcher::Run()
{
BPath path;
if (find_directory(B_TRASH_DIRECTORY, &path) == B_OK) {
BDirectory trashDir(path.Path());
BEntry entry;
if (trashDir.GetEntry(&entry) == B_OK) {
Model trashModel(&entry);
IconCache::sIconCache->IconChanged(&trashModel);
}
}
return BLooper::Run();
}
BTrashWatcher::~BTrashWatcher()
{
stop_watching(this);
}
bool
BTrashWatcher::IsTrashNode(const node_ref* testNode) const
{
int32 count = fTrashNodeList.CountItems();
for (int32 index = 0; index < count; index++) {
node_ref* nref = fTrashNodeList.ItemAt(index);
if (nref->node == testNode->node && nref->device == testNode->device)
return true;
}
return false;
}
void
BTrashWatcher::MessageReceived(BMessage* message)
{
if (message->what != B_NODE_MONITOR) {
_inherited::MessageReceived(message);
return;
}
switch (message->GetInt32("opcode", 0)) {
case B_ENTRY_CREATED:
if (!fTrashFull) {
fTrashFull = true;
UpdateTrashIcon();
}
break;
case B_ENTRY_MOVED:
{
ino_t toDir;
ino_t fromDir;
message->FindInt64("from directory", &fromDir);
message->FindInt64("to directory", &toDir);
if (fromDir == toDir)
break;
}
case B_DEVICE_UNMOUNTED:
case B_ENTRY_REMOVED:
{
bool full = CheckTrashDirs();
if (fTrashFull != full) {
fTrashFull = full;
UpdateTrashIcon();
}
break;
}
case B_DEVICE_MOUNTED:
{
dev_t device;
BDirectory trashDir;
if (message->FindInt32("new device", &device) == B_OK
&& FSGetTrashDir(&trashDir, device) == B_OK) {
node_ref trashNode;
trashDir.GetNodeRef(&trashNode);
TTracker::WatchNode(&trashNode, B_WATCH_DIRECTORY, this);
fTrashNodeList.AddItem(new node_ref(trashNode));
if (CheckTrashDirs() && !fTrashFull) {
fTrashFull = true;
UpdateTrashIcon();
}
}
break;
}
}
}
void
BTrashWatcher::UpdateTrashIcon()
{
BPath path;
if (find_directory(B_TRASH_DIRECTORY, &path) != B_OK)
return;
BDirectory trashDir(path.Path());
int32 id = fTrashFull ? R_TrashFullIcon : R_TrashIcon;
size_t size = 0;
const void* data = GetTrackerResources()->LoadResource(B_VECTOR_ICON_TYPE, id, &size);
if (data != NULL && size > 0) {
trashDir.WriteAttr(kAttrIcon, B_VECTOR_ICON_TYPE, 0, data, size);
} else {
data = GetTrackerResources()->LoadResource('ICON', id, &size);
if (data != NULL && size > 0)
trashDir.WriteAttr(kAttrLargeIcon, 'ICON', 0, data, size);
data = GetTrackerResources()->LoadResource('MICN', id, &size);
if (data != NULL && size > 0)
trashDir.WriteAttr(kAttrMiniIcon, 'MICN', 0, data, size);
}
}
void
BTrashWatcher::WatchTrashDirs()
{
BVolumeRoster volRoster;
volRoster.Rewind();
BVolume volume;
while (volRoster.GetNextVolume(&volume) == B_OK) {
if (volume.IsReadOnly() || !volume.IsPersistent() || volume.Capacity() == 0)
continue;
BDirectory trashDir;
if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK) {
node_ref trashNode;
trashDir.GetNodeRef(&trashNode);
watch_node(&trashNode, B_WATCH_DIRECTORY, this);
fTrashNodeList.AddItem(new node_ref(trashNode));
}
}
}
bool
BTrashWatcher::CheckTrashDirs()
{
BVolumeRoster volRoster;
volRoster.Rewind();
BVolume volume;
while (volRoster.GetNextVolume(&volume) == B_OK) {
if (volume.IsReadOnly() || !volume.IsPersistent() || volume.Capacity() == 0)
continue;
BDirectory trashDir;
if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK) {
trashDir.Rewind();
entry_ref ref;
if (trashDir.GetNextRef(&ref) == B_OK)
return true;
}
}
return false;
}