From 687e327bace5d8abca3e75ce74a8f532fac5c151 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Tue, 19 Jun 2007 09:33:29 +0000 Subject: [PATCH] Reworked the handling of periodically updated poses (currently only ones with a volume space bar): * Addad global list where poses that need periodic updates can be registered with a callback * Use this mechanism for poses with a volume space bar * Create only one BVolume when the BPose is created for a volume, instead of every time the free space is calculated * On Pulse() the global list is used to update all of the registered periodic update poses * As the poses know their volume, it is no longer necessary to use a BVolumeRoster to loop through each volume on each Pulse() * Removed the now superfluous SendNotices() mechanism * Removed corresponding watching / handling of these notices in BPoseView The BPoseView did a linear search for each volume pose on each Pulse() before. What's more it did this once for each mounted volume as it did get one individual notice for each of them. To get these volumes a BVolumeRoster was used to loop through the volumes, but then the BPose did still create a new BVolume to actually calculate the free space! I'm surprised that it did not suck away more performance with this method... Anyway, this should bring down BVolume construction and update overhead down to a minimum and hopefully fix ticket #1247. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21462 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/tracker/Pose.cpp | 79 ++++++++++++++++++------------ src/kits/tracker/Pose.h | 3 +- src/kits/tracker/PoseList.cpp | 17 ------- src/kits/tracker/PoseList.h | 1 - src/kits/tracker/PoseView.cpp | 57 +++++---------------- src/kits/tracker/PoseView.h | 3 +- src/kits/tracker/SettingsViews.cpp | 8 ++- src/kits/tracker/Tracker.cpp | 21 +++----- src/kits/tracker/Utilities.cpp | 77 ++++++++++++++++++++++++++++- src/kits/tracker/Utilities.h | 35 +++++++++++++ 10 files changed, 185 insertions(+), 116 deletions(-) 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 {