diff --git a/src/apps/Jamfile b/src/apps/Jamfile index 6b815e5864..07f1d1d0c1 100644 --- a/src/apps/Jamfile +++ b/src/apps/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src apps ; SubInclude HAIKU_TOP src apps 3dmov ; SubInclude HAIKU_TOP src apps aboutsystem ; +SubInclude HAIKU_TOP src apps activitymonitor ; SubInclude HAIKU_TOP src apps bsnow ; SubInclude HAIKU_TOP src apps bootman ; SubInclude HAIKU_TOP src apps cdplayer ; diff --git a/src/apps/activitymonitor/ActivityMonitor.cpp b/src/apps/activitymonitor/ActivityMonitor.cpp new file mode 100644 index 0000000000..543cd53491 --- /dev/null +++ b/src/apps/activitymonitor/ActivityMonitor.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "ActivityMonitor.h" + +#include + +#include +#include +#include + +#include "ActivityWindow.h" + + +const char* kSignature = "application/x-vnd.Haiku-ActivityMonitor"; + + +ActivityMonitor::ActivityMonitor() + : BApplication(kSignature) +{ +} + + +ActivityMonitor::~ActivityMonitor() +{ +} + + +void +ActivityMonitor::ReadyToRun() +{ + fWindow = new ActivityWindow(); + fWindow->Show(); +} + + +void +ActivityMonitor::RefsReceived(BMessage* message) +{ + fWindow->PostMessage(message); +} + + +void +ActivityMonitor::MessageReceived(BMessage* message) +{ + BApplication::MessageReceived(message); +} + + +void +ActivityMonitor::AboutRequested() +{ + ShowAbout(); +} + + +/*static*/ void +ActivityMonitor::ShowAbout() +{ + BAlert *alert = new BAlert("about", "ActivityMonitor\n" + "\twritten by Axel Dörfler\n" + "\tCopyright 2008, Haiku Inc.\n", "Ok"); + BTextView *view = alert->TextView(); + BFont font; + + view->SetStylable(true); + + view->GetFont(&font); + font.SetSize(18); + font.SetFace(B_BOLD_FACE); + view->SetFontAndColor(0, 15, &font); + + alert->Go(); +} + + +// #pragma mark - + + +int +main(int /*argc*/, char** /*argv*/) +{ + ActivityMonitor app; + app.Run(); + + return 0; +} diff --git a/src/apps/activitymonitor/ActivityMonitor.h b/src/apps/activitymonitor/ActivityMonitor.h new file mode 100644 index 0000000000..507b9d83fb --- /dev/null +++ b/src/apps/activitymonitor/ActivityMonitor.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ACTIVITY_MONITOR_H +#define ACTIVITY_MONITOR_H + + +#include + +class BMessage; +class ActivityWindow; + + +class ActivityMonitor : public BApplication { +public: + ActivityMonitor(); + virtual ~ActivityMonitor(); + + virtual void ReadyToRun(); + + virtual void RefsReceived(BMessage* message); + virtual void MessageReceived(BMessage* message); + + virtual void AboutRequested(); + + static void ShowAbout(); + +private: + ActivityWindow* fWindow; +}; + +extern const char* kSignature; + +#endif // ACTIVITY_MONITOR_H diff --git a/src/apps/activitymonitor/ActivityMonitor.rdef b/src/apps/activitymonitor/ActivityMonitor.rdef new file mode 100644 index 0000000000..c21d013343 --- /dev/null +++ b/src/apps/activitymonitor/ActivityMonitor.rdef @@ -0,0 +1,46 @@ + +resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku-ActivityMonitor"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_BETA, + internal = 3, + + short_info = "ActivityMonitor", + long_info = "ActivityMonitor ©2008 Haiku, Inc." +}; + +resource app_flags B_MULTIPLE_LAUNCH; + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU + +resource vector_icon { + $"6E6369660E03010000020002023980000000000000004000004BE00008908100" + $"010000FFFF01000000020016023CC7EE389BC0BA16573E39B04977C842ADC700" + $"FFFFD3020006023C529D3753A2B8966F3D9D084B6044496AAF00474747FFA5A0" + $"A002001602BC4E76BC411B3C90DABCA00D47587D4ABA850090FFD40200160238" + $"313C3B5CF0BFCD963C7AAC4C13943FCAF901ECFFC3054B04017E020006033E2F" + $"99387F17BA42DB3FF5B94A0E32482C90001D1E2C3D454658FF01010102000602" + $"3879063B8224BE2CC83B10DB4A1F6F49B894FF9A9A9A00242222020006033C69" + $"A60000000000003E186148800049800058F3F3F300D4CECEFFD9D9D902000603" + $"3C1F1A33E78CB7ACC03FFE4F48BB3EBD7B6C0078D905818CFF05FF7ADD050200" + $"1602349C2E37B5FABA1F6036FC624A3E004B320001D3FF910200160235777837" + $"0A67B7E8CE363A844A1D684B45D800F3FF2E0D0A04486050605C51544E04033E" + $"5349594856475C49604B5C4E604B0A06262A264C485E5252523030240A04262A" + $"4838523030240A044838485E525252300A04262A264C485E48380A04453A4553" + $"2844282E0A04B6F9C0F42845282EB701B8EC0A044550455328452AC0F30A0445" + $"3A45502A43B701B8EC0408AEBAB6BCBCC32FBD4F2E3930BDA8B9ACC0A5BA9EBC" + $"03BB1EBFD937BF0DBD4FC072BCC3C019BDDBC0CB46460204BF23C726BF91C70D" + $"BEB5C73FBE9FC87EBE7AC7D9BEC5C922BFAAC97BBF3CC994C018C962C02DC823" + $"C053C8C8C008C77F0204BFCEC6FBC042C6E0BF5BC715BF48C85ABF1FC7B3BF71" + $"C902C063C95ABFF0C974C0D7C93FC0EAC7FAC113C8A2C0C1C7530E0A07010000" + $"0A0101011001178300040A0001021001178400040A020103000A080109000A0B" + $"010A1001178120040A030104000A04020506000A090107000A0A0108000A0D01" + $"0C0815FF0A0C010B0815FF0A0D010C0A3FEAF70000000000003FEAF7C573B4C2" + $"770615FF0A0C010B0A3FEAF70000000000003FEAF7C573B4C2770615FF" +}; + +#endif // HAIKU_TARGET_PLATFORM_HAIKU diff --git a/src/apps/activitymonitor/ActivityView.cpp b/src/apps/activitymonitor/ActivityView.cpp new file mode 100644 index 0000000000..9be7486270 --- /dev/null +++ b/src/apps/activitymonitor/ActivityView.cpp @@ -0,0 +1,500 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "ActivityView.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ActivityMonitor.h" +#include "DataSource.h" +#include "SystemInfo.h" + + +struct data_item { + bigtime_t time; + int64 value; +}; + +const bigtime_t kInitialRefreshInterval = 500000LL; + +const uint32 kMsgRefresh = 'refr'; +const uint32 kMsgToggleDataSource = 'tgds'; + +extern const char* kSignature; + + +DataHistory::DataHistory(bigtime_t memorize, bigtime_t interval) + : + fBuffer(10000), + fMinimumValue(0), + fMaximumValue(0), + fRefreshInterval(interval), + fLastIndex(-1) +{ +} + + +DataHistory::~DataHistory() +{ +} + + +void +DataHistory::AddValue(bigtime_t time, int64 value) +{ + if (fBuffer.IsEmpty() || fMaximumValue < value) + fMaximumValue = value; + if (fBuffer.IsEmpty() || fMinimumValue > value) + fMinimumValue = value; + + data_item item = {time, value}; + fBuffer.AddItem(item); +} + + +int64 +DataHistory::ValueAt(bigtime_t time) +{ + // TODO: if the refresh rate changes, this computation won't work anymore! + int32 index = (time - Start()) / fRefreshInterval; + data_item* item = fBuffer.ItemAt(index); + if (item != NULL) + return item->value; + + return 0; +} + + +int64 +DataHistory::MaximumValue() const +{ + return fMaximumValue; +} + + +int64 +DataHistory::MinimumValue() const +{ + return fMinimumValue; +} + + +bigtime_t +DataHistory::Start() const +{ + if (fBuffer.CountItems() == 0) + return 0; + + return fBuffer.ItemAt(0)->time; +} + + +bigtime_t +DataHistory::End() const +{ + if (fBuffer.CountItems() == 0) + return 0; + + return fBuffer.ItemAt(fBuffer.CountItems() - 1)->time; +} + + +void +DataHistory::SetRefreshInterval(bigtime_t interval) +{ + // TODO: adjust buffer size +} + + +// #pragma mark - + + +ActivityView::ActivityView(BRect frame, const char* name, + const BMessage& settings, uint32 resizingMode) + : BView(frame, name, resizingMode, + B_WILL_DRAW | B_SUBPIXEL_PRECISE | B_FULL_UPDATE_ON_RESIZE + | B_FRAME_EVENTS) +{ + _Init(&settings); + + BRect rect(Bounds()); + rect.top = rect.bottom - 7; + rect.left = rect.right - 7; + BDragger* dragger = new BDragger(rect, this, + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + AddChild(dragger); +} + + +ActivityView::ActivityView(BMessage* archive) + : BView(archive) +{ + _Init(archive); +} + + +ActivityView::~ActivityView() +{ +} + + +void +ActivityView::_Init(const BMessage* settings) +{ + fBackgroundColor = (rgb_color){255, 255, 240}; + SetLowColor(fBackgroundColor); + + fRefreshInterval = kInitialRefreshInterval; + fDrawInterval = kInitialRefreshInterval * 2; + fLastRefresh = 0; + fDrawResolution = 1; + + AddDataSource(new UsedMemoryDataSource()); + AddDataSource(new CachedMemoryDataSource()); + AddDataSource(new ThreadsDataSource()); + AddDataSource(new CpuUsageDataSource()); +} + + +status_t +ActivityView::Archive(BMessage* into, bool deep) const +{ + status_t status; + + status = BView::Archive(into, deep); + if (status < B_OK) + return status; + + status = into->AddString("add_on", kSignature); + if (status < B_OK) + return status; + + status = SaveState(*into); + if (status < B_OK) + return status; + + return B_OK; +} + + +BArchivable* +ActivityView::Instantiate(BMessage* archive) +{ + if (!validate_instantiation(archive, "ActivityView")) + return NULL; + + return new ActivityView(archive); +} + + +status_t +ActivityView::SaveState(BMessage& state) const +{ + return B_ERROR; +} + + +DataSource* +ActivityView::FindDataSource(const char* name) +{ + for (int32 i = fSources.CountItems(); i-- > 0;) { + DataSource* source = fSources.ItemAt(i); + if (!strcmp(source->Label(), name)) + return source; + } + + return NULL; +} + + +status_t +ActivityView::AddDataSource(DataSource* source) +{ + DataHistory* values = new(std::nothrow) DataHistory(10 * 60000000LL, + fRefreshInterval); + if (values == NULL) + return B_NO_MEMORY; + if (!fValues.AddItem(values)) { + delete values; + return B_NO_MEMORY; + } + + if (!fSources.AddItem(source)) { + fValues.RemoveItem(values); + delete values; + return B_NO_MEMORY; + } + + return B_OK; +} + + +status_t +ActivityView::RemoveDataSource(DataSource* source) +{ + int32 index = fSources.IndexOf(source); + if (index < 0) + return B_ENTRY_NOT_FOUND; + + fSources.RemoveItemAt(index); + delete source; + DataHistory* values = fValues.RemoveItemAt(index); + delete values; + + return B_OK; +} + + +void +ActivityView::RemoveAllDataSources() +{ + fSources.MakeEmpty(); + fValues.MakeEmpty(); +} + + +void +ActivityView::AttachedToWindow() +{ + BMessage refresh(kMsgRefresh); + fRunner = new BMessageRunner(this, &refresh, fRefreshInterval); +} + + +void +ActivityView::DetachedFromWindow() +{ + delete fRunner; +} + + +void +ActivityView::FrameResized(float /*width*/, float /*height*/) +{ +} + + +void +ActivityView::MouseDown(BPoint where) +{ +#if 0 + int32 buttons = B_PRIMARY_MOUSE_BUTTON; + int32 clicks = 1; + if (Looper() != NULL && Looper()->CurrentMessage() != NULL) { + Looper()->CurrentMessage()->FindInt32("buttons", &buttons); + Looper()->CurrentMessage()->FindInt32("clicks", &clicks); + } +#endif + + BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); + menu->SetFont(be_plain_font); + BMenuItem* item; + + for (int32 i = 0; i < DataSource::CountSources(); i++) { + const DataSource* source = DataSource::SourceAt(i); + + BMessage* message = new BMessage(kMsgToggleDataSource); + message->AddInt32("index", i); + + item = new BMenuItem(source->Label(), message); + if (FindDataSource(source->Label())) + item->SetMarked(true); + + menu->AddItem(item); + } + + menu->SetTargetForItems(this); + + ConvertToScreen(&where); + menu->Go(where, true, false, true); + +} + + +void +ActivityView::MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage) +{ +} + + +void +ActivityView::MessageReceived(BMessage* message) +{ + switch (message->what) { + case B_ABOUT_REQUESTED: + ActivityMonitor::ShowAbout(); + break; + + case kMsgRefresh: + _Refresh(); + break; + + case kMsgToggleDataSource: + { + int32 index; + if (message->FindInt32("index", &index) != B_OK) + break; + + const DataSource* baseSource = DataSource::SourceAt(index); + if (baseSource == NULL) + break; + + DataSource* source = FindDataSource(baseSource->Label()); + if (source == NULL) + AddDataSource(baseSource->Copy()); + else + RemoveDataSource(source); + + Invalidate(); + break; + } + + case B_MOUSE_WHEEL_CHANGED: + { + float deltaY = 0.0f; + if (message->FindFloat("be:wheel_delta_y", &deltaY) != B_OK + || deltaY == 0.0f) + break; + + if (deltaY > 0) + fDrawResolution *= 2; + else + fDrawResolution /= 2; + + if (fDrawResolution < 1) + fDrawResolution = 1; + if (fDrawResolution > 128) + fDrawResolution = 128; + + Invalidate(); + break; + } + + default: + BView::MessageReceived(message); + break; + } +} + + +float +ActivityView::_PositionForValue(DataSource* source, DataHistory* values, + int64 value) +{ + int64 min = source->Minimum(); + int64 max = source->Maximum(); + if (source->AdaptiveScale()) { + int64 adaptiveMax = int64(values->MaximumValue() * 1.2); + if (adaptiveMax < max) + max = adaptiveMax; + } + + if (value > max) + value = max; + if (value < min) + value = min; + + float height = Bounds().Height(); + return height - (value - min) * height / (max - min); +} + + +void +ActivityView::Draw(BRect /*updateRect*/) +{ + uint32 step = 2; + uint32 resolution = fDrawResolution; + if (fDrawResolution > 1) { + step = 1; + resolution--; + } + + uint32 width = Bounds().IntegerWidth() - 10; + uint32 steps = width / step; + bigtime_t timeStep = fRefreshInterval * resolution; + bigtime_t now = system_time(); + + SetPenSize(2); + + for (uint32 i = fSources.CountItems(); i-- > 0;) { + DataSource* source = fSources.ItemAt(i); + DataHistory* values = fValues.ItemAt(i); + bigtime_t time = now - steps * timeStep; + // for now steps pixels per second + + BeginLineArray(steps); + SetHighColor(source->Color()); + + float lastY = FLT_MIN; + uint32 lastX = 0; + + for (uint32 x = 0; x < width; x += step, time += timeStep) { + // TODO: compute starting point instead! + if (values->Start() > time || values->End() < time) + continue; + + int64 value = values->ValueAt(time); + if (timeStep > fRefreshInterval) { + // TODO: always start with the same index, so that it always + // uses the same values for computation (currently it jumps) + uint32 count = 1; + for (bigtime_t offset = fRefreshInterval; offset < timeStep; + offset += fRefreshInterval) { + // TODO: handle int64 overflow correctly! + value += values->ValueAt(time + offset); + count++; + } + value /= count; + } + + float y = _PositionForValue(source, values, value); + if (lastY != FLT_MIN) + AddLine(BPoint(lastX, lastY), BPoint(x, y), source->Color()); + + lastX = x; + lastY = y; + } + + EndLineArray(); + } + + // TODO: add marks when an app started or quit +} + + +void +ActivityView::_Refresh() +{ + SystemInfo info; + + // TODO: run refresh in another thread to decouple it from the UI! + + for (uint32 i = fSources.CountItems(); i-- > 0;) { + DataSource* source = fSources.ItemAt(i); + DataHistory* values = fValues.ItemAt(i); + + int64 value = source->NextValue(info); + values->AddValue(info.Time(), value); + } + + bigtime_t now = info.Time(); + if (fLastRefresh + fDrawInterval <= now) { + Invalidate(); + fLastRefresh = now; + } +} + diff --git a/src/apps/activitymonitor/ActivityView.h b/src/apps/activitymonitor/ActivityView.h new file mode 100644 index 0000000000..0130b6b2ea --- /dev/null +++ b/src/apps/activitymonitor/ActivityView.h @@ -0,0 +1,89 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ACTIVITY_VIEW_H +#define ACTIVITY_VIEW_H + + +#include +#include + +#include "CircularBuffer.h" + +class BMessageRunner; +class DataSource; +struct data_item; + + +class DataHistory { +public: + DataHistory(bigtime_t memorize, bigtime_t interval); + ~DataHistory(); + + void AddValue(bigtime_t time, int64 value); + + int64 ValueAt(bigtime_t time); + int64 MaximumValue() const; + int64 MinimumValue() const; + bigtime_t Start() const; + bigtime_t End() const; + + void SetRefreshInterval(bigtime_t interval); + +private: + CircularBuffer fBuffer; + int64 fMinimumValue; + int64 fMaximumValue; + bigtime_t fRefreshInterval; + int32 fLastIndex; +}; + + +class ActivityView : public BView { +public: + ActivityView(BRect frame, const char* name, + const BMessage& settings, uint32 resizingMode); + ActivityView(BMessage* archive); + virtual ~ActivityView(); + + virtual status_t Archive(BMessage* into, bool deep = true) const; + static BArchivable* Instantiate(BMessage* archive); + + status_t SaveState(BMessage& state) const; + + DataSource* FindDataSource(const char* name); + status_t AddDataSource(DataSource* source); + status_t RemoveDataSource(DataSource* source); + void RemoveAllDataSources(); + +protected: + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + + virtual void FrameResized(float width, float height); + virtual void MouseDown(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage); + + virtual void MessageReceived(BMessage* message); + + virtual void Draw(BRect updateRect); + +private: + void _Init(const BMessage* settings); + void _Refresh(); + float _PositionForValue(DataSource* source, + DataHistory* values, int64 value); + + rgb_color fBackgroundColor; + BObjectList fSources; + BObjectList fValues; + BMessageRunner* fRunner; + bigtime_t fRefreshInterval; + bigtime_t fLastRefresh; + bigtime_t fDrawInterval; + int32 fDrawResolution; +}; + +#endif // ACTIVITY_VIEW_H diff --git a/src/apps/activitymonitor/ActivityWindow.cpp b/src/apps/activitymonitor/ActivityWindow.cpp new file mode 100644 index 0000000000..27890cf0d7 --- /dev/null +++ b/src/apps/activitymonitor/ActivityWindow.cpp @@ -0,0 +1,156 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "ActivityWindow.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ActivityMonitor.h" +#include "ActivityView.h" + + +ActivityWindow::ActivityWindow() + : BWindow(BRect(100, 100, 500, 250), "ActivityMonitor", B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE) +{ + BMessage settings; + _LoadSettings(settings); + + BRect frame; + if (settings.FindRect("window frame", &frame) == B_OK) { + MoveTo(frame.LeftTop()); + ResizeTo(frame.Width(), frame.Height()); + frame.OffsetTo(B_ORIGIN); + } else + frame = Bounds(); + + // create GUI + + BMenuBar* menuBar = new BMenuBar(Bounds(), "menu"); + AddChild(menuBar); + + frame.top = menuBar->Frame().bottom; + + BView* top = new BView(frame, NULL, B_FOLLOW_ALL, B_WILL_DRAW); + top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(top); + + fActivityView = new ActivityView(top->Bounds().InsetByCopy(10, 10), + "ActivityMonitor", settings, B_FOLLOW_ALL); + top->AddChild(fActivityView); + + // add menu + + // "File" menu + BMenu* menu = new BMenu("File"); + BMenuItem* item; + + menu->AddItem(item = new BMenuItem("About ActivityMonitor" B_UTF8_ELLIPSIS, + new BMessage(B_ABOUT_REQUESTED))); + menu->AddSeparatorItem(); + + menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')); + menu->SetTargetForItems(this); + item->SetTarget(be_app); + menuBar->AddItem(menu); +} + + +ActivityWindow::~ActivityWindow() +{ +} + + +status_t +ActivityWindow::_OpenSettings(BFile& file, uint32 mode) +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return B_ERROR; + + path.Append("ActivityMonitor settings"); + + return file.SetTo(path.Path(), mode); +} + + +status_t +ActivityWindow::_LoadSettings(BMessage& settings) +{ + BFile file; + status_t status = _OpenSettings(file, B_READ_ONLY); + if (status < B_OK) + return status; + + return settings.Unflatten(&file); +} + + +status_t +ActivityWindow::_SaveSettings() +{ + BFile file; + status_t status = _OpenSettings(file, B_WRITE_ONLY | B_CREATE_FILE + | B_ERASE_FILE); + if (status < B_OK) + return status; + + BMessage settings('actm'); + status = settings.AddRect("window frame", Frame()); + if (status == B_OK) + status = settings.Flatten(&file); + + return status; +} + + +void +ActivityWindow::_MessageDropped(BMessage* message) +{ + entry_ref ref; + if (message->FindRef("refs", &ref) != B_OK) { + // TODO: If app, then launch it, and add ActivityView for this one? + } +} + + +void +ActivityWindow::MessageReceived(BMessage* message) +{ + if (message->WasDropped()) { + _MessageDropped(message); + return; + } + + switch (message->what) { + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + _MessageDropped(message); + break; + + default: + BWindow::MessageReceived(message); + break; + } +} + + +bool +ActivityWindow::QuitRequested() +{ + _SaveSettings(); + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} diff --git a/src/apps/activitymonitor/ActivityWindow.h b/src/apps/activitymonitor/ActivityWindow.h new file mode 100644 index 0000000000..65e795169b --- /dev/null +++ b/src/apps/activitymonitor/ActivityWindow.h @@ -0,0 +1,33 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ACTIVITY_WINDOW_H +#define ACTIVITY_WINDOW_H + + +#include + +class BFile; +class ActivityView; + + +class ActivityWindow : public BWindow { +public: + ActivityWindow(); + virtual ~ActivityWindow(); + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + +private: + status_t _OpenSettings(BFile& file, uint32 mode); + status_t _LoadSettings(BMessage& settings); + status_t _SaveSettings(); + + void _MessageDropped(BMessage *message); + + ActivityView* fActivityView; +}; + +#endif // ACTIVITY_WINDOW_H diff --git a/src/apps/activitymonitor/CircularBuffer.h b/src/apps/activitymonitor/CircularBuffer.h new file mode 100644 index 0000000000..a5fac336cf --- /dev/null +++ b/src/apps/activitymonitor/CircularBuffer.h @@ -0,0 +1,77 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef CIRCULAR_BUFFER_H +#define CIRCULAR_BUFFER_H + + +#include + +#include + + +template +class CircularBuffer { +public: + CircularBuffer(size_t size) + : + fSize(size) + { + fBuffer = (Type *)malloc(fSize * sizeof(Type)); + MakeEmpty(); + } + + ~CircularBuffer() + { + free(fBuffer); + } + + status_t InitCheck() const + { + return fBuffer != NULL ? B_OK : B_NO_MEMORY; + } + + void MakeEmpty() + { + fIn = 0; + fFirst = 0; + } + + bool IsEmpty() const + { + return fIn == 0; + } + + int32 CountItems() const + { + return fIn; + } + + Type* ItemAt(int32 index) const + { + if (index >= (int32)fIn || index < 0) + return NULL; + + return &fBuffer[(fFirst + index) % fSize]; + } + + void AddItem(const Type& item) + { + uint32 index; + if (fIn < fSize) + index = fFirst + fIn++; + else + index = fFirst++; + + fBuffer[index % fSize] = item; + } + +private: + uint32 fFirst; + uint32 fIn; + uint32 fSize; + Type* fBuffer; +}; + +#endif // CIRCULAR_BUFFER_H diff --git a/src/apps/activitymonitor/DataSource.cpp b/src/apps/activitymonitor/DataSource.cpp new file mode 100644 index 0000000000..9038c12050 --- /dev/null +++ b/src/apps/activitymonitor/DataSource.cpp @@ -0,0 +1,395 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "DataSource.h" + +#include + +#include +#include + +#include "SystemInfo.h" + + +const DataSource* kSources[] = { + new UsedMemoryDataSource(), + new CachedMemoryDataSource(), + new ThreadsDataSource(), + new CpuUsageDataSource(), +}; +const size_t kSourcesCount = sizeof(kSources) / sizeof(kSources[0]); + + +DataSource::DataSource(int64 initialMin, int64 initialMax) + : + fMinimum(initialMin), + fMaximum(initialMax), + fInterval(1000000LL), + fColor((rgb_color){200, 0, 0}) +{ +} + + +DataSource::DataSource() + : + fMinimum(0), + fMaximum(100), + fInterval(1000000LL), + fColor((rgb_color){200, 0, 0}) +{ +} + + +DataSource::DataSource(const DataSource& other) +{ + fMinimum = other.fMinimum; + fMaximum = other.fMaximum; + fInterval = other.fInterval; + fColor = other.fColor; +} + + +DataSource::~DataSource() +{ +} + + +DataSource* +DataSource::Copy() const +{ + return NULL; + // this class cannot be copied +} + + +int64 +DataSource::Minimum() const +{ + return fMinimum; +} + + +int64 +DataSource::Maximum() const +{ + return fMaximum; +} + + +bigtime_t +DataSource::RefreshInterval() const +{ + return fInterval; +} + + +void +DataSource::SetLimits(int64 min, int64 max) +{ + fMinimum = min; + fMaximum = max; +} + + +void +DataSource::SetRefreshInterval(bigtime_t interval) +{ + fInterval = interval; +} + + +void +DataSource::SetColor(rgb_color color) +{ + fColor = color; +} + + +int64 +DataSource::NextValue(SystemInfo& info) +{ + return 0; +} + + +void +DataSource::Print(BString& text, int64 value) const +{ + text = ""; + text << value; +} + + +const char* +DataSource::Label() const +{ + return ""; +} + + +const char* +DataSource::Unit() const +{ + return ""; +} + + +rgb_color +DataSource::Color() const +{ + return fColor; +} + + +bool +DataSource::AdaptiveScale() const +{ + return false; +} + + +/*static*/ int32 +DataSource::CountSources() +{ + return kSourcesCount; +} + + +/*static*/ const DataSource* +DataSource::SourceAt(int32 index) +{ + if (index >= (int32)kSourcesCount || index < 0) + return NULL; + + return kSources[index]; +} + + +// #pragma mark - + + +MemoryDataSource::MemoryDataSource() +{ + SystemInfo info; + + fMinimum = 0; + fMaximum = info.MaxMemory(); +} + + +MemoryDataSource::~MemoryDataSource() +{ +} + + +void +MemoryDataSource::Print(BString& text, int64 value) const +{ + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.1g MB", value / 1048576.0); + + text = buffer; +} + + +const char* +MemoryDataSource::Unit() const +{ + return "MB"; +} + + +// #pragma mark - + + +UsedMemoryDataSource::UsedMemoryDataSource() +{ +} + + +UsedMemoryDataSource::~UsedMemoryDataSource() +{ +} + + +DataSource* +UsedMemoryDataSource::Copy() const +{ + return new UsedMemoryDataSource(*this); +} + + +int64 +UsedMemoryDataSource::NextValue(SystemInfo& info) +{ + return info.UsedMemory(); +} + + +const char* +UsedMemoryDataSource::Label() const +{ + return "Available Memory"; +} + + +// #pragma mark - + + +CachedMemoryDataSource::CachedMemoryDataSource() +{ + fColor = (rgb_color){0, 200, 0}; +} + + +CachedMemoryDataSource::~CachedMemoryDataSource() +{ +} + + +DataSource* +CachedMemoryDataSource::Copy() const +{ + return new CachedMemoryDataSource(*this); +} + + +int64 +CachedMemoryDataSource::NextValue(SystemInfo& info) +{ + return info.CachedMemory(); +} + + +const char* +CachedMemoryDataSource::Label() const +{ + return "Cached Memory"; +} + + +// #pragma mark - + + +ThreadsDataSource::ThreadsDataSource() +{ + SystemInfo info; + + fMinimum = 0; + fMaximum = info.MaxThreads(); + + fColor = (rgb_color){0, 0, 200}; +} + + +ThreadsDataSource::~ThreadsDataSource() +{ +} + + +DataSource* +ThreadsDataSource::Copy() const +{ + return new ThreadsDataSource(*this); +} + + +int64 +ThreadsDataSource::NextValue(SystemInfo& info) +{ + return info.UsedThreads(); +} + + +const char* +ThreadsDataSource::Label() const +{ + return "Threads"; +} + + +bool +ThreadsDataSource::AdaptiveScale() const +{ + return true; +} + + +// #pragma mark - + + +CpuUsageDataSource::CpuUsageDataSource() + : + fPreviousActive(0), + fPreviousTime(0) +{ + fMinimum = 0; + fMaximum = 1000; + + fColor = (rgb_color){200, 200, 0}; +} + + +CpuUsageDataSource::CpuUsageDataSource(const CpuUsageDataSource& other) +{ + fPreviousActive = other.fPreviousActive; + fPreviousTime = other.fPreviousTime; +} + + +CpuUsageDataSource::~CpuUsageDataSource() +{ +} + + +DataSource* +CpuUsageDataSource::Copy() const +{ + return new CpuUsageDataSource(*this); +} + + +void +CpuUsageDataSource::Print(BString& text, int64 value) const +{ + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.1g%%", value / 10.0); + + text = buffer; +} + + +int64 +CpuUsageDataSource::NextValue(SystemInfo& info) +{ + int32 running = 0; + bigtime_t active = 0; + + for (int32 cpu = 0; cpu < info.Info().cpu_count; cpu++) { + active += info.Info().cpu_infos[cpu].active_time; + running++; + // TODO: take disabled CPUs into account + } + + int64 percent = int64(1000.0 * (active - fPreviousActive) + / (running * (info.Time() - fPreviousTime))); + if (percent < 0) + percent = 0; + if (percent > 1000) + percent = 1000; + + fPreviousActive = active; + fPreviousTime = info.Time(); + + return percent; +} + + +const char* +CpuUsageDataSource::Label() const +{ + return "CPU Usage"; +} diff --git a/src/apps/activitymonitor/DataSource.h b/src/apps/activitymonitor/DataSource.h new file mode 100644 index 0000000000..a123d7d66d --- /dev/null +++ b/src/apps/activitymonitor/DataSource.h @@ -0,0 +1,115 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef DATA_SOURCE_H +#define DATA_SOURCE_H + + +#include + +class BString; +class SystemInfo; + + +class DataSource { +public: + DataSource(int64 initialMin, int64 initialMax); + DataSource(); + DataSource(const DataSource& other); + virtual ~DataSource(); + + virtual DataSource* Copy() const; + + int64 Minimum() const; + int64 Maximum() const; + bigtime_t RefreshInterval() const; + + virtual void SetLimits(int64 min, int64 max); + virtual void SetRefreshInterval(bigtime_t interval); + virtual void SetColor(rgb_color color); + + virtual int64 NextValue(SystemInfo& info); + virtual void Print(BString& text, int64 value) const; + + virtual const char* Label() const; + virtual const char* Unit() const; + virtual rgb_color Color() const; + virtual bool AdaptiveScale() const; + + static int32 CountSources(); + static const DataSource* SourceAt(int32 index); + +protected: + int64 fMinimum; + int64 fMaximum; + bigtime_t fInterval; + rgb_color fColor; +}; + + +class MemoryDataSource : public DataSource { +public: + MemoryDataSource(); + virtual ~MemoryDataSource(); + + virtual void Print(BString& text, int64 value) const; + virtual const char* Unit() const; +}; + + +class UsedMemoryDataSource : public MemoryDataSource { +public: + UsedMemoryDataSource(); + virtual ~UsedMemoryDataSource(); + + virtual DataSource* Copy() const; + + virtual int64 NextValue(SystemInfo& info); + virtual const char* Label() const; +}; + + +class CachedMemoryDataSource : public MemoryDataSource { +public: + CachedMemoryDataSource(); + virtual ~CachedMemoryDataSource(); + + virtual DataSource* Copy() const; + + virtual int64 NextValue(SystemInfo& info); + virtual const char* Label() const; +}; + + +class ThreadsDataSource : public DataSource { +public: + ThreadsDataSource(); + virtual ~ThreadsDataSource(); + + virtual DataSource* Copy() const; + + virtual int64 NextValue(SystemInfo& info); + virtual const char* Label() const; + virtual bool AdaptiveScale() const; +}; + + +class CpuUsageDataSource : public DataSource { +public: + CpuUsageDataSource(); + CpuUsageDataSource(const CpuUsageDataSource& other); + virtual ~CpuUsageDataSource(); + + virtual DataSource* Copy() const; + + virtual void Print(BString& text, int64 value) const; + virtual int64 NextValue(SystemInfo& info); + virtual const char* Label() const; + +private: + bigtime_t fPreviousActive; + bigtime_t fPreviousTime; +}; + +#endif // DATA_SOURCE_H diff --git a/src/apps/activitymonitor/Jamfile b/src/apps/activitymonitor/Jamfile new file mode 100644 index 0000000000..2a18e39a4b --- /dev/null +++ b/src/apps/activitymonitor/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src apps activitymonitor ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders shared ; + +Application ActivityMonitor : + ActivityMonitor.cpp + ActivityView.cpp + ActivityWindow.cpp + DataSource.cpp + SystemInfo.cpp + + : be tracker $(TARGET_LIBSTDC++) + : ActivityMonitor.rdef + ; diff --git a/src/apps/activitymonitor/SystemInfo.cpp b/src/apps/activitymonitor/SystemInfo.cpp new file mode 100644 index 0000000000..f07c0992df --- /dev/null +++ b/src/apps/activitymonitor/SystemInfo.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "SystemInfo.h" + + +SystemInfo::SystemInfo() + : + fTime(system_time()) +{ + get_system_info(&fSystemInfo); +} + + +SystemInfo::~SystemInfo() +{ +} + + +uint64 +SystemInfo::CachedMemory() const +{ + return fSystemInfo.cached_pages * B_PAGE_SIZE; +} + + +uint64 +SystemInfo::UsedMemory() const +{ + return fSystemInfo.used_pages * B_PAGE_SIZE; +} + + +uint64 +SystemInfo::MaxMemory() const +{ + return fSystemInfo.max_pages * B_PAGE_SIZE; +} + + +uint32 +SystemInfo::UsedThreads() const +{ + return fSystemInfo.used_threads; +} + + +uint32 +SystemInfo::MaxThreads() const +{ + return fSystemInfo.max_threads; +} + + +uint32 +SystemInfo::UsedTeams() const +{ + return fSystemInfo.used_teams; +} + + +uint32 +SystemInfo::MaxTeams() const +{ + return fSystemInfo.max_teams; +} diff --git a/src/apps/activitymonitor/SystemInfo.h b/src/apps/activitymonitor/SystemInfo.h new file mode 100644 index 0000000000..e88976cf53 --- /dev/null +++ b/src/apps/activitymonitor/SystemInfo.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef SYSTEM_INFO_H +#define SYSTEM_INFO_H + + +#include + + +class SystemInfo { +public: + SystemInfo(); + ~SystemInfo(); + + uint64 CachedMemory() const; + uint64 UsedMemory() const; + uint64 MaxMemory() const; + + uint32 UsedThreads() const; + uint32 MaxThreads() const; + + uint32 UsedTeams() const; + uint32 MaxTeams() const; + + bigtime_t Time() const { return fTime; } + const system_info& Info() const { return fSystemInfo; } + +private: + system_info fSystemInfo; + bigtime_t fTime; +}; + +#endif // SYSTEM_INFO_H