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
This commit is contained in:
parent
5de78b2cdb
commit
687e327bac
@ -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<int32>(volume.FreeBytes() / (capacity / 100));
|
||||
off_t capacity = volume->Capacity();
|
||||
int32 percent = static_cast<int32>(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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ All rights reserved.
|
||||
#include <MenuItem.h>
|
||||
#include <MessageFilter.h>
|
||||
#include <Mime.h>
|
||||
#include <ObjectList.h>
|
||||
#include <Point.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
@ -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<periodic_pose> 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 {
|
||||
|
Loading…
Reference in New Issue
Block a user