diff --git a/src/kits/tracker/Pose.cpp b/src/kits/tracker/Pose.cpp index 6b14b20c03..84aa2b97b2 100644 --- a/src/kits/tracker/Pose.cpp +++ b/src/kits/tracker/Pose.cpp @@ -49,32 +49,15 @@ All rights reserved. int32 -CalcFreeSpace(dev_t device) +CalcFreeSpace(BVolume *volume) { - BVolume volume(device); - fs_info info; - if (volume.InitCheck() == B_OK && fs_stat_dev(device,&info) == B_OK) { - // Philosophy here: - // Bars go on all drives with read/write capabilities - // Exceptions: Not on CDDA, but on NTFS/Ext2 - // Also note that some volumes may return 0 when - // BVolume::Capacity() is called (believe-me... That *DOES* - // happen) so we also check for that. - off_t capacity = volume.Capacity(); - if (((!volume.IsReadOnly() && strcmp(info.fsh_name,"cdda")) - || !strcmp(info.fsh_name,"ntfs") - || !strcmp(info.fsh_name,"ext2")) - && (capacity > 0)) { - int32 percent = static_cast(volume.FreeBytes() / (capacity / 100)); + off_t capacity = volume->Capacity(); + int32 percent = static_cast(volume->FreeBytes() / (capacity / 100)); - // warn below 20 MB of free space (if this is less than 10% of free space) - if (volume.FreeBytes() < 20 * 1024 * 1024 && percent < 10) - return -2 - percent; - - return percent; - } - } - return -1; + // warn below 20 MB of free space (if this is less than 10% of free space) + if (volume->FreeBytes() < 20 * 1024 * 1024 && percent < 10) + return -2 - percent; + return percent; } @@ -98,9 +81,32 @@ BPose::BPose(Model *model, BPoseView *view, bool selected) { CreateWidgets(view); - if (model->IsVolume() && TrackerSettings().ShowVolumeSpaceBar()) { + if (model->IsVolume()) { + fs_info info; dev_t device = model->NodeRef()->device; - fPercent = CalcFreeSpace(device); + BVolume *volume = new BVolume(device); + if (volume->InitCheck() == B_OK + && fs_stat_dev(device, &info) == B_OK) { + // Philosophy here: + // Bars go on all drives with read/write capabilities + // Exceptions: Not on CDDA, but on NTFS/Ext2 + // Also note that some volumes may return 0 when + // BVolume::Capacity() is called (believe-me... That *DOES* + // happen) so we also check for that. + off_t capacity = volume->Capacity(); + if (((!volume->IsReadOnly() && strcmp(info.fsh_name,"cdda")) + || !strcmp(info.fsh_name,"ntfs") + || !strcmp(info.fsh_name,"ext2")) + && capacity > 0) { + // The volume is ok and we want space bars on it + gPeriodicUpdatePoses.AddPose(this, view, + _PeriodicUpdateCallback, volume); + if (TrackerSettings().ShowVolumeSpaceBar()) + fPercent = CalcFreeSpace(volume); + } else + delete volume; + } else + delete volume; } if ((fClipboardMode = FSClipboardFindNodeMode(model,true)) != 0 @@ -112,6 +118,13 @@ BPose::BPose(Model *model, BPoseView *view, bool selected) BPose::~BPose() { + if (fModel->IsVolume()) { + // we might be registered for periodic updates + BVolume *volume = NULL; + if (gPeriodicUpdatePoses.RemovePose(this, (void **)&volume)) + delete volume; + } + delete fModel; } @@ -285,8 +298,16 @@ BPose::UpdateWidgetAndModel(Model *resolvedModel, const char *attrName, bool -BPose::UpdateVolumeSpaceBar(bool enabled) +BPose::_PeriodicUpdateCallback(BPose *pose, void *cookie) { + return pose->UpdateVolumeSpaceBar((BVolume *)cookie); +} + + +bool +BPose::UpdateVolumeSpaceBar(BVolume *volume) +{ + bool enabled = TrackerSettings().ShowVolumeSpaceBar(); if (!enabled) { if (fPercent == -1) return false; @@ -295,9 +316,7 @@ BPose::UpdateVolumeSpaceBar(bool enabled) return true; } - dev_t device = TargetModel()->NodeRef()->device; - int32 percent = CalcFreeSpace(device); - + int32 percent = CalcFreeSpace(volume); if (fPercent != percent) { if (percent > 100) fPercent = 100; diff --git a/src/kits/tracker/Pose.h b/src/kits/tracker/Pose.h index 0c5a98c627..9246742c3b 100644 --- a/src/kits/tracker/Pose.h +++ b/src/kits/tracker/Pose.h @@ -96,7 +96,7 @@ class BPose { void UpdateAllWidgets(int32 poseIndex, BPoint poseLoc, BPoseView *); void UpdateWidgetAndModel(Model *resolvedModel, const char *attrName, uint32 attrType, int32 poseIndex, BPoint poseLoc, BPoseView *view); - bool UpdateVolumeSpaceBar(bool enabled); + bool UpdateVolumeSpaceBar(BVolume *volume); void UpdateIcon(BPoint poseLoc, BPoseView *); //void UpdateFixedSymlink(BPoint poseLoc, BPoseView *); @@ -126,6 +126,7 @@ class BPose { #endif private: + static bool _PeriodicUpdateCallback(BPose *pose, void *cookie); void EditPreviousNextWidgetCommon(BPoseView *poseView, bool next); void CreateWidgets(BPoseView *); bool TestLargeIconPixel(BPoint) const; diff --git a/src/kits/tracker/PoseList.cpp b/src/kits/tracker/PoseList.cpp index ddcfd086ce..987308fd7e 100644 --- a/src/kits/tracker/PoseList.cpp +++ b/src/kits/tracker/PoseList.cpp @@ -105,20 +105,3 @@ PoseList::DeepFindPose(const node_ref *node, int32 *resultingIndex) const return NULL; } - -BPose * -PoseList::FindVolumePose(const dev_t device, int32 *resultingIndex) const -{ - int32 count = CountItems(); - for (int32 index = 0; index < count; index++) { - BPose *pose = ItemAt(index); - Model *model = pose->TargetModel(); - ASSERT(model); - if (model->IsVolume() && model->NodeRef()->device == device) { - if (resultingIndex) - *resultingIndex = index; - return pose; - } - } - return NULL; -} diff --git a/src/kits/tracker/PoseList.h b/src/kits/tracker/PoseList.h index c28959905c..b16b5d89f7 100644 --- a/src/kits/tracker/PoseList.h +++ b/src/kits/tracker/PoseList.h @@ -64,7 +64,6 @@ public: BPose *DeepFindPose(const node_ref *node, int32 *index = NULL) const; // same as FindPose, node can be a target of the actual // pose if the pose is a symlink - BPose *FindVolumePose(const dev_t device, int32 *index = NULL) const; }; // iteration glue, add permutations as needed diff --git a/src/kits/tracker/PoseView.cpp b/src/kits/tracker/PoseView.cpp index e8052afe45..0b4246b4e5 100644 --- a/src/kits/tracker/PoseView.cpp +++ b/src/kits/tracker/PoseView.cpp @@ -803,9 +803,6 @@ BPoseView::DetachedFromWindow() app->StopWatching(this, kShowSelectionWhenInactiveChanged); app->StopWatching(this, kTransparentSelectionChanged); app->StopWatching(this, kSortFolderNamesFirstChanged); - app->StopWatching(this, kShowVolumeSpaceBar); - app->StopWatching(this, kSpaceBarColorChanged); - app->StopWatching(this, kUpdateVolumeSpaceBar); app->Unlock(); } @@ -890,9 +887,6 @@ BPoseView::AttachedToWindow() app->StartWatching(this, kShowSelectionWhenInactiveChanged); app->StartWatching(this, kTransparentSelectionChanged); app->StartWatching(this, kSortFolderNamesFirstChanged); - app->StartWatching(this, kShowVolumeSpaceBar); - app->StartWatching(this, kSpaceBarColorChanged); - app->StartWatching(this, kUpdateVolumeSpaceBar); app->Unlock(); } @@ -2331,20 +2325,6 @@ BPoseView::MessageReceived(BMessage *message) Invalidate(); } break; - - case kShowVolumeSpaceBar: - bool enabled; - if (message->FindBool("ShowVolumeSpaceBar", &enabled) == B_OK) - TrackerSettings().SetShowVolumeSpaceBar(enabled); - // supposed to fall through - case kSpaceBarColorChanged: - UpdateVolumeIcons(); - break; - case kUpdateVolumeSpaceBar: - dev_t device; - message->FindInt32("device", (int32 *)&device); - UpdateVolumeIcon(device); - break; } } break; @@ -5214,34 +5194,21 @@ BPoseView::AttributeChanged(const BMessage *message) void -BPoseView::UpdateVolumeIcon(dev_t device, bool forceUpdate) +BPoseView::UpdateIcon(BPose *pose) { - int32 index; - BPose *pose = fPoseList->FindVolumePose(device,&index); - if (pose == NULL) - return; - - if (pose->UpdateVolumeSpaceBar(TrackerSettings().ShowVolumeSpaceBar()) || forceUpdate) { - BPoint loc(0, index * fListElemHeight); - pose->UpdateIcon(loc, this); + BPoint location; + if (ViewMode() == kListMode) { + // need to find the index of the pose in the pose list + int32 count = fPoseList->CountItems(); + for (int32 index = 0; index < count; index++) { + if (fPoseList->ItemAt(index) == pose) { + location.Set(0, index * fListElemHeight); + break; + } + } } -} - -void -BPoseView::UpdateVolumeIcons() -{ - BVolumeRoster roster; - - BVolume volume; - while(roster.GetNextVolume(&volume) == B_NO_ERROR) { - BDirectory dir; - volume.GetRootDirectory(&dir); - node_ref nodeRef; - dir.GetNodeRef(&nodeRef); - - UpdateVolumeIcon(nodeRef.device, true); - } + pose->UpdateIcon(location, this); } diff --git a/src/kits/tracker/PoseView.h b/src/kits/tracker/PoseView.h index a365bf9498..efb832f235 100644 --- a/src/kits/tracker/PoseView.h +++ b/src/kits/tracker/PoseView.h @@ -159,8 +159,7 @@ class BPoseView : public BView { void SetAutoScroll(bool); void SetPoseEditing(bool); - void UpdateVolumeIcon(dev_t device, bool forceUpdate = false); - void UpdateVolumeIcons(); + void UpdateIcon(BPose *pose); // file change notification handler virtual bool FSNotification(const BMessage *); diff --git a/src/kits/tracker/SettingsViews.cpp b/src/kits/tracker/SettingsViews.cpp index 60152bf6e8..418d083830 100644 --- a/src/kits/tracker/SettingsViews.cpp +++ b/src/kits/tracker/SettingsViews.cpp @@ -1072,9 +1072,7 @@ SpaceBarSettingsView::MessageReceived(BMessage *message) { settings.SetShowVolumeSpaceBar(fSpaceBarShowCheckBox->Value() == 1); Window()->PostMessage(kSettingsContentsModified); - BMessage notificationMessage; - notificationMessage.AddBool("ShowVolumeSpaceBar", settings.ShowVolumeSpaceBar()); - tracker->SendNotices(kShowVolumeSpaceBar, ¬ificationMessage); + tracker->PostMessage(kShowVolumeSpaceBar); break; } @@ -1094,6 +1092,7 @@ SpaceBarSettingsView::MessageReceived(BMessage *message) } break; } + case kSpaceBarColorChanged: { switch (fCurrentColor) { @@ -1109,8 +1108,7 @@ SpaceBarSettingsView::MessageReceived(BMessage *message) } Window()->PostMessage(kSettingsContentsModified); - BMessage notificationMessage; - tracker->SendNotices(kSpaceBarColorChanged, ¬ificationMessage); + tracker->PostMessage(kSpaceBarColorChanged); break; } diff --git a/src/kits/tracker/Tracker.cpp b/src/kits/tracker/Tracker.cpp index bb6a915847..067c5cd73d 100644 --- a/src/kits/tracker/Tracker.cpp +++ b/src/kits/tracker/Tracker.cpp @@ -483,6 +483,12 @@ TTracker::MessageReceived(BMessage *message) break; } + case kShowVolumeSpaceBar: + case kSpaceBarColorChanged: { + gPeriodicUpdatePoses.DoPeriodicUpdate(true); + break; + } + default: _inherited::MessageReceived(message); break; @@ -497,20 +503,7 @@ TTracker::Pulse() return; // update the volume icon's free space bars - BVolumeRoster roster; - - BVolume volume; - while (roster.GetNextVolume(&volume) == B_OK) { - BDirectory dir; - volume.GetRootDirectory(&dir); - node_ref nodeRef; - dir.GetNodeRef(&nodeRef); - - BMessage notificationMessage; - notificationMessage.AddInt32("device", *(int32 *)&nodeRef.device); - - SendNotices(kUpdateVolumeSpaceBar, ¬ificationMessage); - } + gPeriodicUpdatePoses.DoPeriodicUpdate(false); } diff --git a/src/kits/tracker/Utilities.cpp b/src/kits/tracker/Utilities.cpp index 2804a31e6b..c81aa76f6a 100644 --- a/src/kits/tracker/Utilities.cpp +++ b/src/kits/tracker/Utilities.cpp @@ -35,6 +35,7 @@ All rights reserved. #include "Attributes.h" #include "MimeTypes.h" #include "Model.h" +#include "PoseView.h" #include "Utilities.h" #include "ContainerWindow.h" @@ -158,7 +159,81 @@ DisallowMetaKeys(BTextView *textView) textView->DisallowChar(B_PAGE_DOWN); textView->DisallowChar(B_FUNCTION_KEY); } - + + +PeriodicUpdatePoses::PeriodicUpdatePoses() + : fPoseList(20, true) +{ + fLock = new Benaphore("PeriodicUpdatePoses"); +} + + +PeriodicUpdatePoses::~PeriodicUpdatePoses() +{ + fLock->Lock(); + fPoseList.MakeEmpty(); + delete fLock; +} + + +void +PeriodicUpdatePoses::AddPose(BPose *pose, BPoseView *poseView, + PeriodicUpdateCallback callback, void *cookie) +{ + periodic_pose *periodic = new periodic_pose; + periodic->pose = pose; + periodic->pose_view = poseView; + periodic->callback = callback; + periodic->cookie = cookie; + fPoseList.AddItem(periodic); +} + + +bool +PeriodicUpdatePoses::RemovePose(BPose *pose, void **cookie) +{ + int32 count = fPoseList.CountItems(); + for (int32 index = 0; index < count; index++) { + if (fPoseList.ItemAt(index)->pose == pose) { + if (!fLock->Lock()) + return false; + + periodic_pose *periodic = fPoseList.RemoveItemAt(index); + if (cookie) + *cookie = periodic->cookie; + delete periodic; + fLock->Unlock(); + return true; + } + } + + return false; +} + + +void +PeriodicUpdatePoses::DoPeriodicUpdate(bool forceRedraw) +{ + if (!fLock->Lock()) + return; + + int32 count = fPoseList.CountItems(); + for (int32 index = 0; index < count; index++) { + periodic_pose *periodic = fPoseList.ItemAt(index); + if (periodic->callback(periodic->pose, periodic->cookie) + || forceRedraw) { + periodic->pose_view->LockLooper(); + periodic->pose_view->UpdateIcon(periodic->pose); + periodic->pose_view->UnlockLooper(); + } + } + + fLock->Unlock(); +} + + +static PeriodicUpdatePoses gPeriodicUpdatePoses; + } // namespace BPrivate diff --git a/src/kits/tracker/Utilities.h b/src/kits/tracker/Utilities.h index d6b248832c..f48e774ea4 100644 --- a/src/kits/tracker/Utilities.h +++ b/src/kits/tracker/Utilities.h @@ -46,6 +46,7 @@ All rights reserved. #include #include #include +#include #include #include #include @@ -62,6 +63,8 @@ class BView; namespace BPrivate { class Benaphore; +class BPose; +class BPoseView; // global variables extern const rgb_color kBlack; @@ -83,6 +86,38 @@ const color_space kDefaultIconDepth = B_CMAP8; // misc typedefs, constants and structs +// Periodically updated poses (ones with a volume space bar) register +// themselfs in this global list. This way they can be iterated over instead +// of sending around update messages. + +class PeriodicUpdatePoses { + public: + PeriodicUpdatePoses(); + ~PeriodicUpdatePoses(); + + typedef bool (*PeriodicUpdateCallback)(BPose *pose, void *cookie); + + void AddPose(BPose *pose, BPoseView *poseView, + PeriodicUpdateCallback callback, void *cookie); + bool RemovePose(BPose *pose, void **cookie); + + void DoPeriodicUpdate(bool forceRedraw); + + private: + struct periodic_pose { + BPose *pose; + BPoseView *pose_view; + PeriodicUpdateCallback callback; + void *cookie; + }; + + Benaphore *fLock; + BObjectList fPoseList; +}; + +extern PeriodicUpdatePoses gPeriodicUpdatePoses; + + // PoseInfo is the structure that gets saved as attributes for every node on // disk, defining the node's position and visibility class PoseInfo {