xref: /haiku/src/apps/activitymonitor/ActivityView.cpp (revision 8e26f38727f01b9130d72f2877a7391ddafc06f1)
118d3e65eSAxel Dörfler /*
21bb87bd0SAxel Dörfler  * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de.
318d3e65eSAxel Dörfler  * Distributed under the terms of the MIT License.
418d3e65eSAxel Dörfler  */
518d3e65eSAxel Dörfler 
618d3e65eSAxel Dörfler 
718d3e65eSAxel Dörfler #include "ActivityView.h"
818d3e65eSAxel Dörfler 
918d3e65eSAxel Dörfler #include <new>
1018d3e65eSAxel Dörfler #include <stdio.h>
1118d3e65eSAxel Dörfler #include <stdlib.h>
12*8e26f387SAxel Dörfler #include <vector.h>
1318d3e65eSAxel Dörfler 
14dc1ffc79SFrançois Revol #ifdef __HAIKU__
15065e8de0SAxel Dörfler #	include <AbstractLayoutItem.h>
16dc1ffc79SFrançois Revol #endif
1718d3e65eSAxel Dörfler #include <Application.h>
18d4216445SAxel Dörfler #include <Autolock.h>
1918d3e65eSAxel Dörfler #include <Bitmap.h>
2018d3e65eSAxel Dörfler #include <Dragger.h>
2118d3e65eSAxel Dörfler #include <MenuItem.h>
2218d3e65eSAxel Dörfler #include <MessageRunner.h>
2318d3e65eSAxel Dörfler #include <PopUpMenu.h>
24*8e26f387SAxel Dörfler #include <Shape.h>
2518d3e65eSAxel Dörfler #include <String.h>
2618d3e65eSAxel Dörfler 
2718d3e65eSAxel Dörfler #include "ActivityMonitor.h"
283f315b26SAxel Dörfler #include "ActivityWindow.h"
291bb87bd0SAxel Dörfler #include "SettingsWindow.h"
3018d3e65eSAxel Dörfler #include "SystemInfo.h"
3174158bb4SFrançois Revol #include "SystemInfoHandler.h"
3218d3e65eSAxel Dörfler 
3318d3e65eSAxel Dörfler 
34*8e26f387SAxel Dörfler template<typename ObjectType>
35*8e26f387SAxel Dörfler class ListAddDeleter {
36*8e26f387SAxel Dörfler public:
37*8e26f387SAxel Dörfler 	ListAddDeleter(BObjectList<ObjectType>& list, ObjectType* object,
38*8e26f387SAxel Dörfler 			int32 spot)
39*8e26f387SAxel Dörfler 		:
40*8e26f387SAxel Dörfler 		fList(list),
41*8e26f387SAxel Dörfler 		fObject(object)
42*8e26f387SAxel Dörfler 	{
43*8e26f387SAxel Dörfler 		if (fObject != NULL && !fList.AddItem(fObject, spot)) {
44*8e26f387SAxel Dörfler 			delete fObject;
45*8e26f387SAxel Dörfler 			fObject = NULL;
46*8e26f387SAxel Dörfler 		}
47*8e26f387SAxel Dörfler 	}
48*8e26f387SAxel Dörfler 
49*8e26f387SAxel Dörfler 	~ListAddDeleter()
50*8e26f387SAxel Dörfler 	{
51*8e26f387SAxel Dörfler 		if (fObject != NULL) {
52*8e26f387SAxel Dörfler 			fList.RemoveItem(fObject);
53*8e26f387SAxel Dörfler 			delete fObject;
54*8e26f387SAxel Dörfler 		}
55*8e26f387SAxel Dörfler 	}
56*8e26f387SAxel Dörfler 
57*8e26f387SAxel Dörfler 	bool Failed() const
58*8e26f387SAxel Dörfler 	{
59*8e26f387SAxel Dörfler 		return fObject == NULL;
60*8e26f387SAxel Dörfler 	}
61*8e26f387SAxel Dörfler 
62*8e26f387SAxel Dörfler 	void Detach()
63*8e26f387SAxel Dörfler 	{
64*8e26f387SAxel Dörfler 		fObject = NULL;
65*8e26f387SAxel Dörfler 	}
66*8e26f387SAxel Dörfler 
67*8e26f387SAxel Dörfler private:
68*8e26f387SAxel Dörfler 	BObjectList<ObjectType>&	fList;
69*8e26f387SAxel Dörfler 	ObjectType*					fObject;
70*8e26f387SAxel Dörfler };
71*8e26f387SAxel Dörfler 
72*8e26f387SAxel Dörfler 
73*8e26f387SAxel Dörfler /*!	This class manages the scale of a history with a dynamic scale.
74*8e26f387SAxel Dörfler 	Every history value will be input via Update(), and the minimum/maximum
75*8e26f387SAxel Dörfler 	is computed from that.
76*8e26f387SAxel Dörfler */
7751591198SAxel Dörfler class Scale {
7851591198SAxel Dörfler public:
7951591198SAxel Dörfler 								Scale(scale_type type);
8051591198SAxel Dörfler 
8151591198SAxel Dörfler 			int64				MinimumValue() const { return fMinimumValue; }
8251591198SAxel Dörfler 			int64				MaximumValue() const { return fMaximumValue; }
8351591198SAxel Dörfler 
8451591198SAxel Dörfler 			void				Update(int64 value);
8551591198SAxel Dörfler 
8651591198SAxel Dörfler private:
8751591198SAxel Dörfler 			scale_type			fType;
8851591198SAxel Dörfler 			int64				fMinimumValue;
8951591198SAxel Dörfler 			int64				fMaximumValue;
9051591198SAxel Dörfler 			bool				fInitialized;
9151591198SAxel Dörfler };
9251591198SAxel Dörfler 
93*8e26f387SAxel Dörfler /*!	Stores the interpolated on screen view values. This is done so that the
94*8e26f387SAxel Dörfler 	interpolation is fixed, and does not change when being scrolled.
95*8e26f387SAxel Dörfler 
96*8e26f387SAxel Dörfler 	We could also just do this by making sure we always ask for the same
97*8e26f387SAxel Dörfler 	interval only, but this way we also save the interpolation.
98*8e26f387SAxel Dörfler */
99*8e26f387SAxel Dörfler class ViewHistory {
100*8e26f387SAxel Dörfler public:
101*8e26f387SAxel Dörfler 								ViewHistory();
102*8e26f387SAxel Dörfler 
103*8e26f387SAxel Dörfler 			int64				ValueAt(int32 x);
104*8e26f387SAxel Dörfler 
105*8e26f387SAxel Dörfler 			int32				Start() const
106*8e26f387SAxel Dörfler 									{ return fValues.Size()
107*8e26f387SAxel Dörfler 										- fValues.CountItems(); }
108*8e26f387SAxel Dörfler 
109*8e26f387SAxel Dörfler 			void				Update(DataHistory* history, int32 width,
110*8e26f387SAxel Dörfler 									int32 resolution, bigtime_t toTime,
111*8e26f387SAxel Dörfler 									bigtime_t step, bigtime_t refresh);
112*8e26f387SAxel Dörfler 
113*8e26f387SAxel Dörfler private:
114*8e26f387SAxel Dörfler 			CircularBuffer<int64> fValues;
115*8e26f387SAxel Dörfler 			int32				fResolution;
116*8e26f387SAxel Dörfler 			bigtime_t			fRefresh;
117*8e26f387SAxel Dörfler 			bigtime_t			fLastTime;
118*8e26f387SAxel Dörfler };
119*8e26f387SAxel Dörfler 
12018d3e65eSAxel Dörfler struct data_item {
12118d3e65eSAxel Dörfler 	bigtime_t	time;
12218d3e65eSAxel Dörfler 	int64		value;
12318d3e65eSAxel Dörfler };
12418d3e65eSAxel Dörfler 
125dc1ffc79SFrançois Revol #ifdef __HAIKU__
126065e8de0SAxel Dörfler class ActivityView::HistoryLayoutItem : public BAbstractLayoutItem {
127065e8de0SAxel Dörfler public:
128065e8de0SAxel Dörfler 							HistoryLayoutItem(ActivityView* parent);
129065e8de0SAxel Dörfler 
130065e8de0SAxel Dörfler 	virtual	bool			IsVisible();
131065e8de0SAxel Dörfler 	virtual	void			SetVisible(bool visible);
132065e8de0SAxel Dörfler 
133065e8de0SAxel Dörfler 	virtual	BRect			Frame();
134065e8de0SAxel Dörfler 	virtual	void			SetFrame(BRect frame);
135065e8de0SAxel Dörfler 
136065e8de0SAxel Dörfler 	virtual	BView*			View();
137065e8de0SAxel Dörfler 
138065e8de0SAxel Dörfler 	virtual	BSize			BasePreferredSize();
139065e8de0SAxel Dörfler 
140065e8de0SAxel Dörfler private:
141065e8de0SAxel Dörfler 	ActivityView*			fParent;
142065e8de0SAxel Dörfler 	BRect					fFrame;
143065e8de0SAxel Dörfler };
144065e8de0SAxel Dörfler 
145065e8de0SAxel Dörfler class ActivityView::LegendLayoutItem : public BAbstractLayoutItem {
146065e8de0SAxel Dörfler public:
147065e8de0SAxel Dörfler 							LegendLayoutItem(ActivityView* parent);
148065e8de0SAxel Dörfler 
149065e8de0SAxel Dörfler 	virtual	bool			IsVisible();
150065e8de0SAxel Dörfler 	virtual	void			SetVisible(bool visible);
151065e8de0SAxel Dörfler 
152065e8de0SAxel Dörfler 	virtual	BRect			Frame();
153065e8de0SAxel Dörfler 	virtual	void			SetFrame(BRect frame);
154065e8de0SAxel Dörfler 
155065e8de0SAxel Dörfler 	virtual	BView*			View();
156065e8de0SAxel Dörfler 
157065e8de0SAxel Dörfler 	virtual	BSize			BaseMinSize();
158065e8de0SAxel Dörfler 	virtual	BSize			BaseMaxSize();
159065e8de0SAxel Dörfler 	virtual	BSize			BasePreferredSize();
160065e8de0SAxel Dörfler 	virtual	BAlignment		BaseAlignment();
161065e8de0SAxel Dörfler 
162065e8de0SAxel Dörfler private:
163065e8de0SAxel Dörfler 	ActivityView*			fParent;
164065e8de0SAxel Dörfler 	BRect					fFrame;
165065e8de0SAxel Dörfler };
166dc1ffc79SFrançois Revol #endif
167065e8de0SAxel Dörfler 
1681bb87bd0SAxel Dörfler const bigtime_t kInitialRefreshInterval = 250000LL;
16918d3e65eSAxel Dörfler 
17018d3e65eSAxel Dörfler const uint32 kMsgToggleDataSource = 'tgds';
1713a4a2141SAxel Dörfler const uint32 kMsgToggleLegend = 'tglg';
1721bb87bd0SAxel Dörfler const uint32 kMsgUpdateResolution = 'ures';
17318d3e65eSAxel Dörfler 
17418d3e65eSAxel Dörfler extern const char* kSignature;
17518d3e65eSAxel Dörfler 
17618d3e65eSAxel Dörfler 
17751591198SAxel Dörfler Scale::Scale(scale_type type)
17851591198SAxel Dörfler 	:
17951591198SAxel Dörfler 	fType(type),
18051591198SAxel Dörfler 	fMinimumValue(0),
18151591198SAxel Dörfler 	fMaximumValue(0),
18251591198SAxel Dörfler 	fInitialized(false)
18351591198SAxel Dörfler {
18451591198SAxel Dörfler }
18551591198SAxel Dörfler 
18651591198SAxel Dörfler 
18751591198SAxel Dörfler void
18851591198SAxel Dörfler Scale::Update(int64 value)
18951591198SAxel Dörfler {
19051591198SAxel Dörfler 	if (!fInitialized || fMinimumValue > value)
19151591198SAxel Dörfler 		fMinimumValue = value;
192230e3259SAxel Dörfler 	if (!fInitialized || fMaximumValue < value)
19351591198SAxel Dörfler 		fMaximumValue = value;
19451591198SAxel Dörfler 
19551591198SAxel Dörfler 	fInitialized = true;
19651591198SAxel Dörfler }
19751591198SAxel Dörfler 
19851591198SAxel Dörfler 
19951591198SAxel Dörfler //	#pragma mark -
20051591198SAxel Dörfler 
20151591198SAxel Dörfler 
202*8e26f387SAxel Dörfler ViewHistory::ViewHistory()
203*8e26f387SAxel Dörfler 	:
204*8e26f387SAxel Dörfler 	fValues(1),
205*8e26f387SAxel Dörfler 	fResolution(-1),
206*8e26f387SAxel Dörfler 	fRefresh(-1),
207*8e26f387SAxel Dörfler 	fLastTime(0)
208*8e26f387SAxel Dörfler {
209*8e26f387SAxel Dörfler }
210*8e26f387SAxel Dörfler 
211*8e26f387SAxel Dörfler 
212*8e26f387SAxel Dörfler int64
213*8e26f387SAxel Dörfler ViewHistory::ValueAt(int32 x)
214*8e26f387SAxel Dörfler {
215*8e26f387SAxel Dörfler 	int64* value = fValues.ItemAt(x - Start());
216*8e26f387SAxel Dörfler 	if (value != NULL)
217*8e26f387SAxel Dörfler 		return *value;
218*8e26f387SAxel Dörfler 
219*8e26f387SAxel Dörfler 	return 0;
220*8e26f387SAxel Dörfler }
221*8e26f387SAxel Dörfler 
222*8e26f387SAxel Dörfler 
223*8e26f387SAxel Dörfler void
224*8e26f387SAxel Dörfler ViewHistory::Update(DataHistory* history, int32 width, int32 resolution,
225*8e26f387SAxel Dörfler 	bigtime_t toTime, bigtime_t step, bigtime_t refresh)
226*8e26f387SAxel Dörfler {
227*8e26f387SAxel Dörfler 	// Check if we need to invalidate the existing values
228*8e26f387SAxel Dörfler 	if ((int32)fValues.Size() != width
229*8e26f387SAxel Dörfler 		|| fResolution != resolution
230*8e26f387SAxel Dörfler 		|| fRefresh != refresh) {
231*8e26f387SAxel Dörfler 		fValues.SetSize(width);
232*8e26f387SAxel Dörfler 		fLastTime = 0;
233*8e26f387SAxel Dörfler 		fResolution = resolution;
234*8e26f387SAxel Dörfler 		fRefresh = refresh;
235*8e26f387SAxel Dörfler 	}
236*8e26f387SAxel Dörfler 
237*8e26f387SAxel Dörfler 	// Compute how many new values we need to retrieve
238*8e26f387SAxel Dörfler 	if (fLastTime < history->Start())
239*8e26f387SAxel Dörfler 		fLastTime = history->Start();
240*8e26f387SAxel Dörfler 
241*8e26f387SAxel Dörfler 	int32 updateWidth = int32((toTime - fLastTime) / step);
242*8e26f387SAxel Dörfler 	if (updateWidth < 1)
243*8e26f387SAxel Dörfler 		return;
244*8e26f387SAxel Dörfler 
245*8e26f387SAxel Dörfler 	if (updateWidth > (int32)fValues.Size()) {
246*8e26f387SAxel Dörfler 		updateWidth = fValues.Size();
247*8e26f387SAxel Dörfler 		fLastTime = toTime - updateWidth * step;
248*8e26f387SAxel Dörfler 	}
249*8e26f387SAxel Dörfler 
250*8e26f387SAxel Dörfler 	for (int32 i = 0; i < updateWidth; i++) {
251*8e26f387SAxel Dörfler 		int64 value = history->ValueAt(fLastTime += step);
252*8e26f387SAxel Dörfler 
253*8e26f387SAxel Dörfler 		if (step > refresh) {
254*8e26f387SAxel Dörfler 			uint32 count = 1;
255*8e26f387SAxel Dörfler 			for (bigtime_t offset = refresh; offset < step; offset += refresh) {
256*8e26f387SAxel Dörfler 				// TODO: handle int64 overflow correctly!
257*8e26f387SAxel Dörfler 				value += history->ValueAt(fLastTime + offset);
258*8e26f387SAxel Dörfler 				count++;
259*8e26f387SAxel Dörfler 			}
260*8e26f387SAxel Dörfler 			value /= count;
261*8e26f387SAxel Dörfler 		}
262*8e26f387SAxel Dörfler 
263*8e26f387SAxel Dörfler 		fValues.AddItem(value);
264*8e26f387SAxel Dörfler 	}
265*8e26f387SAxel Dörfler }
266*8e26f387SAxel Dörfler 
267*8e26f387SAxel Dörfler 
268*8e26f387SAxel Dörfler //	#pragma mark -
269*8e26f387SAxel Dörfler 
270*8e26f387SAxel Dörfler 
27118d3e65eSAxel Dörfler DataHistory::DataHistory(bigtime_t memorize, bigtime_t interval)
27218d3e65eSAxel Dörfler 	:
27318d3e65eSAxel Dörfler 	fBuffer(10000),
27418d3e65eSAxel Dörfler 	fMinimumValue(0),
27518d3e65eSAxel Dörfler 	fMaximumValue(0),
27618d3e65eSAxel Dörfler 	fRefreshInterval(interval),
27751591198SAxel Dörfler 	fLastIndex(-1),
27851591198SAxel Dörfler 	fScale(NULL)
27918d3e65eSAxel Dörfler {
28018d3e65eSAxel Dörfler }
28118d3e65eSAxel Dörfler 
28218d3e65eSAxel Dörfler 
28318d3e65eSAxel Dörfler DataHistory::~DataHistory()
28418d3e65eSAxel Dörfler {
28518d3e65eSAxel Dörfler }
28618d3e65eSAxel Dörfler 
28718d3e65eSAxel Dörfler 
28818d3e65eSAxel Dörfler void
28918d3e65eSAxel Dörfler DataHistory::AddValue(bigtime_t time, int64 value)
29018d3e65eSAxel Dörfler {
29118d3e65eSAxel Dörfler 	if (fBuffer.IsEmpty() || fMaximumValue < value)
29218d3e65eSAxel Dörfler 		fMaximumValue = value;
29318d3e65eSAxel Dörfler 	if (fBuffer.IsEmpty() || fMinimumValue > value)
29418d3e65eSAxel Dörfler 		fMinimumValue = value;
29551591198SAxel Dörfler 	if (fScale != NULL)
29651591198SAxel Dörfler 		fScale->Update(value);
29718d3e65eSAxel Dörfler 
29818d3e65eSAxel Dörfler 	data_item item = {time, value};
29918d3e65eSAxel Dörfler 	fBuffer.AddItem(item);
30018d3e65eSAxel Dörfler }
30118d3e65eSAxel Dörfler 
30218d3e65eSAxel Dörfler 
30318d3e65eSAxel Dörfler int64
30418d3e65eSAxel Dörfler DataHistory::ValueAt(bigtime_t time)
30518d3e65eSAxel Dörfler {
30651591198SAxel Dörfler 	int32 left = 0;
30751591198SAxel Dörfler 	int32 right = fBuffer.CountItems() - 1;
30851591198SAxel Dörfler 	data_item* item = NULL;
30951591198SAxel Dörfler 
31051591198SAxel Dörfler 	while (left <= right) {
31151591198SAxel Dörfler 		int32 index = (left + right) / 2;
31251591198SAxel Dörfler 		item = fBuffer.ItemAt(index);
31351591198SAxel Dörfler 
31451591198SAxel Dörfler 		if (item->time > time) {
31551591198SAxel Dörfler 			// search in left part
31651591198SAxel Dörfler 			right = index - 1;
31751591198SAxel Dörfler 		} else {
31884e23a5dSAxel Dörfler 			data_item* nextItem = fBuffer.ItemAt(index + 1);
31984e23a5dSAxel Dörfler 			if (nextItem == NULL)
32084e23a5dSAxel Dörfler 				return item->value;
32184e23a5dSAxel Dörfler 			if (nextItem->time > time) {
32251591198SAxel Dörfler 				// found item
32384e23a5dSAxel Dörfler 				int64 value = item->value;
32484e23a5dSAxel Dörfler 				value += int64(double(nextItem->value - value)
32584e23a5dSAxel Dörfler 					/ (nextItem->time - item->time) * (time - item->time));
326*8e26f387SAxel Dörfler 				return value;
32751591198SAxel Dörfler 			}
32851591198SAxel Dörfler 
32951591198SAxel Dörfler 			// search in right part
33051591198SAxel Dörfler 			left = index + 1;
33151591198SAxel Dörfler 		}
33251591198SAxel Dörfler 	}
33318d3e65eSAxel Dörfler 
33418d3e65eSAxel Dörfler 	return 0;
33518d3e65eSAxel Dörfler }
33618d3e65eSAxel Dörfler 
33718d3e65eSAxel Dörfler 
33818d3e65eSAxel Dörfler int64
33918d3e65eSAxel Dörfler DataHistory::MaximumValue() const
34018d3e65eSAxel Dörfler {
34151591198SAxel Dörfler 	if (fScale != NULL)
34251591198SAxel Dörfler 		return fScale->MaximumValue();
34351591198SAxel Dörfler 
34418d3e65eSAxel Dörfler 	return fMaximumValue;
34518d3e65eSAxel Dörfler }
34618d3e65eSAxel Dörfler 
34718d3e65eSAxel Dörfler 
34818d3e65eSAxel Dörfler int64
34918d3e65eSAxel Dörfler DataHistory::MinimumValue() const
35018d3e65eSAxel Dörfler {
35151591198SAxel Dörfler 	if (fScale != NULL)
35251591198SAxel Dörfler 		return fScale->MinimumValue();
35351591198SAxel Dörfler 
35418d3e65eSAxel Dörfler 	return fMinimumValue;
35518d3e65eSAxel Dörfler }
35618d3e65eSAxel Dörfler 
35718d3e65eSAxel Dörfler 
35818d3e65eSAxel Dörfler bigtime_t
35918d3e65eSAxel Dörfler DataHistory::Start() const
36018d3e65eSAxel Dörfler {
36118d3e65eSAxel Dörfler 	if (fBuffer.CountItems() == 0)
36218d3e65eSAxel Dörfler 		return 0;
36318d3e65eSAxel Dörfler 
36418d3e65eSAxel Dörfler 	return fBuffer.ItemAt(0)->time;
36518d3e65eSAxel Dörfler }
36618d3e65eSAxel Dörfler 
36718d3e65eSAxel Dörfler 
36818d3e65eSAxel Dörfler bigtime_t
36918d3e65eSAxel Dörfler DataHistory::End() const
37018d3e65eSAxel Dörfler {
37118d3e65eSAxel Dörfler 	if (fBuffer.CountItems() == 0)
37218d3e65eSAxel Dörfler 		return 0;
37318d3e65eSAxel Dörfler 
37418d3e65eSAxel Dörfler 	return fBuffer.ItemAt(fBuffer.CountItems() - 1)->time;
37518d3e65eSAxel Dörfler }
37618d3e65eSAxel Dörfler 
37718d3e65eSAxel Dörfler 
37818d3e65eSAxel Dörfler void
37918d3e65eSAxel Dörfler DataHistory::SetRefreshInterval(bigtime_t interval)
38018d3e65eSAxel Dörfler {
38118d3e65eSAxel Dörfler 	// TODO: adjust buffer size
38218d3e65eSAxel Dörfler }
38318d3e65eSAxel Dörfler 
38418d3e65eSAxel Dörfler 
38551591198SAxel Dörfler void
38651591198SAxel Dörfler DataHistory::SetScale(Scale* scale)
38751591198SAxel Dörfler {
38851591198SAxel Dörfler 	fScale = scale;
38951591198SAxel Dörfler }
39051591198SAxel Dörfler 
39151591198SAxel Dörfler 
39218d3e65eSAxel Dörfler //	#pragma mark -
39318d3e65eSAxel Dörfler 
39418d3e65eSAxel Dörfler 
395dc1ffc79SFrançois Revol #ifdef __HAIKU__
396065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::HistoryLayoutItem(ActivityView* parent)
397065e8de0SAxel Dörfler 	:
398065e8de0SAxel Dörfler 	fParent(parent),
399065e8de0SAxel Dörfler 	fFrame()
400065e8de0SAxel Dörfler {
401065e8de0SAxel Dörfler }
402065e8de0SAxel Dörfler 
403065e8de0SAxel Dörfler 
404065e8de0SAxel Dörfler bool
405065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::IsVisible()
406065e8de0SAxel Dörfler {
407065e8de0SAxel Dörfler 	return !fParent->IsHidden(fParent);
408065e8de0SAxel Dörfler }
409065e8de0SAxel Dörfler 
410065e8de0SAxel Dörfler 
411065e8de0SAxel Dörfler void
412065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetVisible(bool visible)
413065e8de0SAxel Dörfler {
414065e8de0SAxel Dörfler 	// not allowed
415065e8de0SAxel Dörfler }
416065e8de0SAxel Dörfler 
417065e8de0SAxel Dörfler 
418065e8de0SAxel Dörfler BRect
419065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::Frame()
420065e8de0SAxel Dörfler {
421065e8de0SAxel Dörfler 	return fFrame;
422065e8de0SAxel Dörfler }
423065e8de0SAxel Dörfler 
424065e8de0SAxel Dörfler 
425065e8de0SAxel Dörfler void
426065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetFrame(BRect frame)
427065e8de0SAxel Dörfler {
428065e8de0SAxel Dörfler 	fFrame = frame;
429065e8de0SAxel Dörfler 	fParent->_UpdateFrame();
430065e8de0SAxel Dörfler }
431065e8de0SAxel Dörfler 
432065e8de0SAxel Dörfler 
433065e8de0SAxel Dörfler BView*
434065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::View()
435065e8de0SAxel Dörfler {
436065e8de0SAxel Dörfler 	return fParent;
437065e8de0SAxel Dörfler }
438065e8de0SAxel Dörfler 
439065e8de0SAxel Dörfler 
440065e8de0SAxel Dörfler BSize
441065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::BasePreferredSize()
442065e8de0SAxel Dörfler {
443065e8de0SAxel Dörfler 	BSize size(BaseMaxSize());
444065e8de0SAxel Dörfler 	return size;
445065e8de0SAxel Dörfler }
446065e8de0SAxel Dörfler 
447065e8de0SAxel Dörfler 
448065e8de0SAxel Dörfler //	#pragma mark -
449065e8de0SAxel Dörfler 
450065e8de0SAxel Dörfler 
451065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::LegendLayoutItem(ActivityView* parent)
452065e8de0SAxel Dörfler 	:
453065e8de0SAxel Dörfler 	fParent(parent),
454065e8de0SAxel Dörfler 	fFrame()
455065e8de0SAxel Dörfler {
456065e8de0SAxel Dörfler }
457065e8de0SAxel Dörfler 
458065e8de0SAxel Dörfler 
459065e8de0SAxel Dörfler bool
460065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::IsVisible()
461065e8de0SAxel Dörfler {
462065e8de0SAxel Dörfler 	return !fParent->IsHidden(fParent);
463065e8de0SAxel Dörfler }
464065e8de0SAxel Dörfler 
465065e8de0SAxel Dörfler 
466065e8de0SAxel Dörfler void
467065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetVisible(bool visible)
468065e8de0SAxel Dörfler {
469065e8de0SAxel Dörfler 	// not allowed
470065e8de0SAxel Dörfler }
471065e8de0SAxel Dörfler 
472065e8de0SAxel Dörfler 
473065e8de0SAxel Dörfler BRect
474065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::Frame()
475065e8de0SAxel Dörfler {
476065e8de0SAxel Dörfler 	return fFrame;
477065e8de0SAxel Dörfler }
478065e8de0SAxel Dörfler 
479065e8de0SAxel Dörfler 
480065e8de0SAxel Dörfler void
481065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetFrame(BRect frame)
482065e8de0SAxel Dörfler {
483065e8de0SAxel Dörfler 	fFrame = frame;
484065e8de0SAxel Dörfler 	fParent->_UpdateFrame();
485065e8de0SAxel Dörfler }
486065e8de0SAxel Dörfler 
487065e8de0SAxel Dörfler 
488065e8de0SAxel Dörfler BView*
489065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::View()
490065e8de0SAxel Dörfler {
491065e8de0SAxel Dörfler 	return fParent;
492065e8de0SAxel Dörfler }
493065e8de0SAxel Dörfler 
494065e8de0SAxel Dörfler 
495065e8de0SAxel Dörfler BSize
496065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMinSize()
497065e8de0SAxel Dörfler {
498065e8de0SAxel Dörfler 	// TODO: Cache the info. Might be too expensive for this call.
499065e8de0SAxel Dörfler 	BSize size;
500065e8de0SAxel Dörfler 	size.width = 80;
501065e8de0SAxel Dörfler 	size.height = fParent->_LegendHeight();
502065e8de0SAxel Dörfler 
503065e8de0SAxel Dörfler 	return size;
504065e8de0SAxel Dörfler }
505065e8de0SAxel Dörfler 
506065e8de0SAxel Dörfler 
507065e8de0SAxel Dörfler BSize
508065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMaxSize()
509065e8de0SAxel Dörfler {
510065e8de0SAxel Dörfler 	BSize size(BaseMinSize());
511065e8de0SAxel Dörfler 	size.width = B_SIZE_UNLIMITED;
512065e8de0SAxel Dörfler 	return size;
513065e8de0SAxel Dörfler }
514065e8de0SAxel Dörfler 
515065e8de0SAxel Dörfler 
516065e8de0SAxel Dörfler BSize
517065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BasePreferredSize()
518065e8de0SAxel Dörfler {
519065e8de0SAxel Dörfler 	BSize size(BaseMinSize());
520065e8de0SAxel Dörfler 	return size;
521065e8de0SAxel Dörfler }
522065e8de0SAxel Dörfler 
523065e8de0SAxel Dörfler 
524065e8de0SAxel Dörfler BAlignment
525065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseAlignment()
526065e8de0SAxel Dörfler {
527065e8de0SAxel Dörfler 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
528065e8de0SAxel Dörfler }
529dc1ffc79SFrançois Revol #endif
530065e8de0SAxel Dörfler 
531065e8de0SAxel Dörfler 
532065e8de0SAxel Dörfler //	#pragma mark -
533065e8de0SAxel Dörfler 
534065e8de0SAxel Dörfler 
53518d3e65eSAxel Dörfler ActivityView::ActivityView(BRect frame, const char* name,
5363a4a2141SAxel Dörfler 		const BMessage* settings, uint32 resizingMode)
53718d3e65eSAxel Dörfler 	: BView(frame, name, resizingMode,
538d4216445SAxel Dörfler 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
539d4216445SAxel Dörfler 	fSourcesLock("data sources")
54018d3e65eSAxel Dörfler {
5413a4a2141SAxel Dörfler 	_Init(settings);
5423a4a2141SAxel Dörfler 
5433a4a2141SAxel Dörfler 	BRect rect(Bounds());
5443a4a2141SAxel Dörfler 	rect.top = rect.bottom - 7;
5453a4a2141SAxel Dörfler 	rect.left = rect.right - 7;
5463a4a2141SAxel Dörfler 	BDragger* dragger = new BDragger(rect, this,
5473a4a2141SAxel Dörfler 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
5483a4a2141SAxel Dörfler 	AddChild(dragger);
5493a4a2141SAxel Dörfler }
5503a4a2141SAxel Dörfler 
5513a4a2141SAxel Dörfler 
5523a4a2141SAxel Dörfler ActivityView::ActivityView(const char* name, const BMessage* settings)
553cbd4bc95SFrançois Revol #ifdef __HAIKU__
554d4216445SAxel Dörfler 	: BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
555cbd4bc95SFrançois Revol #else
556d4216445SAxel Dörfler 	: BView(BRect(0,0,300,200), name, B_FOLLOW_NONE,
557d4216445SAxel Dörfler 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
558cbd4bc95SFrançois Revol #endif
559d4216445SAxel Dörfler 	fSourcesLock("data sources")
5603a4a2141SAxel Dörfler {
56179cbd226SFrançois Revol 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
5629c89c450SAxel Dörfler 
5633a4a2141SAxel Dörfler 	_Init(settings);
56418d3e65eSAxel Dörfler 
56518d3e65eSAxel Dörfler 	BRect rect(Bounds());
56618d3e65eSAxel Dörfler 	rect.top = rect.bottom - 7;
56718d3e65eSAxel Dörfler 	rect.left = rect.right - 7;
56818d3e65eSAxel Dörfler 	BDragger* dragger = new BDragger(rect, this,
56918d3e65eSAxel Dörfler 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
57018d3e65eSAxel Dörfler 	AddChild(dragger);
57118d3e65eSAxel Dörfler }
57218d3e65eSAxel Dörfler 
57318d3e65eSAxel Dörfler 
57418d3e65eSAxel Dörfler ActivityView::ActivityView(BMessage* archive)
57518d3e65eSAxel Dörfler 	: BView(archive)
57618d3e65eSAxel Dörfler {
57718d3e65eSAxel Dörfler 	_Init(archive);
57818d3e65eSAxel Dörfler }
57918d3e65eSAxel Dörfler 
58018d3e65eSAxel Dörfler 
58118d3e65eSAxel Dörfler ActivityView::~ActivityView()
58218d3e65eSAxel Dörfler {
5833a4a2141SAxel Dörfler 	delete fOffscreen;
58474158bb4SFrançois Revol 	delete fSystemInfoHandler;
58518d3e65eSAxel Dörfler }
58618d3e65eSAxel Dörfler 
58718d3e65eSAxel Dörfler 
58818d3e65eSAxel Dörfler void
58918d3e65eSAxel Dörfler ActivityView::_Init(const BMessage* settings)
59018d3e65eSAxel Dörfler {
5919c89c450SAxel Dörfler 	fHistoryBackgroundColor = (rgb_color){255, 255, 240};
5929c89c450SAxel Dörfler 	fLegendBackgroundColor = LowColor();
5939c89c450SAxel Dörfler 		// the low color is restored by the BView unarchiving
5943a4a2141SAxel Dörfler 	fOffscreen = NULL;
595dc1ffc79SFrançois Revol #ifdef __HAIKU__
596065e8de0SAxel Dörfler 	fHistoryLayoutItem = NULL;
597065e8de0SAxel Dörfler 	fLegendLayoutItem = NULL;
598dc1ffc79SFrançois Revol #endif
5993a4a2141SAxel Dörfler 	SetViewColor(B_TRANSPARENT_COLOR);
60018d3e65eSAxel Dörfler 
60118d3e65eSAxel Dörfler 	fRefreshInterval = kInitialRefreshInterval;
60218d3e65eSAxel Dörfler 	fLastRefresh = 0;
60318d3e65eSAxel Dörfler 	fDrawResolution = 1;
60451591198SAxel Dörfler 	fZooming = false;
60518d3e65eSAxel Dörfler 
60674158bb4SFrançois Revol 	fSystemInfoHandler = new SystemInfoHandler;
60774158bb4SFrançois Revol 
6083a4a2141SAxel Dörfler 	if (settings == NULL
6093a4a2141SAxel Dörfler 		|| settings->FindBool("show legend", &fShowLegend) != B_OK)
6103a4a2141SAxel Dörfler 		fShowLegend = true;
6113a4a2141SAxel Dörfler 
61251591198SAxel Dörfler 	if (settings == NULL)
6133a4a2141SAxel Dörfler 		return;
6143a4a2141SAxel Dörfler 
6159c89c450SAxel Dörfler 	ssize_t colorLength;
61679cbd226SFrançois Revol 	rgb_color *color;
6179c89c450SAxel Dörfler 	if (settings->FindData("history background color", B_RGB_COLOR_TYPE,
6189c89c450SAxel Dörfler 			(const void **)&color, &colorLength) == B_OK
6199c89c450SAxel Dörfler 		&& colorLength == sizeof(rgb_color))
6209c89c450SAxel Dörfler 		fHistoryBackgroundColor = *color;
62179cbd226SFrançois Revol 
6223a4a2141SAxel Dörfler 	const char* name;
6233a4a2141SAxel Dörfler 	for (int32 i = 0; settings->FindString("source", i, &name) == B_OK; i++) {
6241201d52eSAxel Dörfler 		AddDataSource(DataSource::FindSource(name), settings);
6253a4a2141SAxel Dörfler 	}
62618d3e65eSAxel Dörfler }
62718d3e65eSAxel Dörfler 
62818d3e65eSAxel Dörfler 
62918d3e65eSAxel Dörfler status_t
63018d3e65eSAxel Dörfler ActivityView::Archive(BMessage* into, bool deep) const
63118d3e65eSAxel Dörfler {
63218d3e65eSAxel Dörfler 	status_t status;
63318d3e65eSAxel Dörfler 
63418d3e65eSAxel Dörfler 	status = BView::Archive(into, deep);
63518d3e65eSAxel Dörfler 	if (status < B_OK)
63618d3e65eSAxel Dörfler 		return status;
63718d3e65eSAxel Dörfler 
63818d3e65eSAxel Dörfler 	status = into->AddString("add_on", kSignature);
63918d3e65eSAxel Dörfler 	if (status < B_OK)
64018d3e65eSAxel Dörfler 		return status;
64118d3e65eSAxel Dörfler 
64218d3e65eSAxel Dörfler 	status = SaveState(*into);
64318d3e65eSAxel Dörfler 	if (status < B_OK)
64418d3e65eSAxel Dörfler 		return status;
64518d3e65eSAxel Dörfler 
64618d3e65eSAxel Dörfler 	return B_OK;
64718d3e65eSAxel Dörfler }
64818d3e65eSAxel Dörfler 
64918d3e65eSAxel Dörfler 
65018d3e65eSAxel Dörfler BArchivable*
65118d3e65eSAxel Dörfler ActivityView::Instantiate(BMessage* archive)
65218d3e65eSAxel Dörfler {
65318d3e65eSAxel Dörfler 	if (!validate_instantiation(archive, "ActivityView"))
65418d3e65eSAxel Dörfler 		return NULL;
65518d3e65eSAxel Dörfler 
65618d3e65eSAxel Dörfler 	return new ActivityView(archive);
65718d3e65eSAxel Dörfler }
65818d3e65eSAxel Dörfler 
65918d3e65eSAxel Dörfler 
66018d3e65eSAxel Dörfler status_t
66118d3e65eSAxel Dörfler ActivityView::SaveState(BMessage& state) const
66218d3e65eSAxel Dörfler {
6633a4a2141SAxel Dörfler 	status_t status = state.AddBool("show legend", fShowLegend);
6643a4a2141SAxel Dörfler 	if (status != B_OK)
6653a4a2141SAxel Dörfler 		return status;
6663a4a2141SAxel Dörfler 
6679c89c450SAxel Dörfler 	status = state.AddData("history background color", B_RGB_COLOR_TYPE,
6689c89c450SAxel Dörfler 		&fHistoryBackgroundColor, sizeof(rgb_color));
66979cbd226SFrançois Revol 	if (status != B_OK)
67079cbd226SFrançois Revol 		return status;
67179cbd226SFrançois Revol 
6723a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems(); i++) {
6733a4a2141SAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
6743a4a2141SAxel Dörfler 
6753a4a2141SAxel Dörfler 		if (!source->PerCPU() || source->CPU() == 0)
6763a4a2141SAxel Dörfler 			status = state.AddString("source", source->Name());
6773a4a2141SAxel Dörfler 		if (status != B_OK)
6783a4a2141SAxel Dörfler 			return status;
6793a4a2141SAxel Dörfler 
6809c89c450SAxel Dörfler 		BString name = source->Name();
6819c89c450SAxel Dörfler 		name << " color";
6829c89c450SAxel Dörfler 		rgb_color color = source->Color();
6839c89c450SAxel Dörfler 		state.AddData(name.String(), B_RGB_COLOR_TYPE, &color,
6849c89c450SAxel Dörfler 			sizeof(rgb_color));
6853a4a2141SAxel Dörfler 	}
6863a4a2141SAxel Dörfler 	return B_OK;
68718d3e65eSAxel Dörfler }
68818d3e65eSAxel Dörfler 
68918d3e65eSAxel Dörfler 
69051591198SAxel Dörfler Scale*
69151591198SAxel Dörfler ActivityView::_ScaleFor(scale_type type)
69251591198SAxel Dörfler {
69351591198SAxel Dörfler 	if (type == kNoScale)
69451591198SAxel Dörfler 		return NULL;
69551591198SAxel Dörfler 
69651591198SAxel Dörfler 	std::map<scale_type, ::Scale*>::iterator iterator = fScales.find(type);
69751591198SAxel Dörfler 	if (iterator != fScales.end())
69851591198SAxel Dörfler 		return iterator->second;
69951591198SAxel Dörfler 
70051591198SAxel Dörfler 	// add new scale
70151591198SAxel Dörfler 	::Scale* scale = new ::Scale(type);
70251591198SAxel Dörfler 	fScales[type] = scale;
70351591198SAxel Dörfler 
70451591198SAxel Dörfler 	return scale;
70551591198SAxel Dörfler }
70651591198SAxel Dörfler 
70751591198SAxel Dörfler 
708dc1ffc79SFrançois Revol #ifdef __HAIKU__
709065e8de0SAxel Dörfler BLayoutItem*
710065e8de0SAxel Dörfler ActivityView::CreateHistoryLayoutItem()
711065e8de0SAxel Dörfler {
712065e8de0SAxel Dörfler 	if (fHistoryLayoutItem == NULL)
713065e8de0SAxel Dörfler 		fHistoryLayoutItem = new HistoryLayoutItem(this);
714065e8de0SAxel Dörfler 
715065e8de0SAxel Dörfler 	return fHistoryLayoutItem;
716065e8de0SAxel Dörfler }
717065e8de0SAxel Dörfler 
718065e8de0SAxel Dörfler 
719065e8de0SAxel Dörfler BLayoutItem*
720065e8de0SAxel Dörfler ActivityView::CreateLegendLayoutItem()
721065e8de0SAxel Dörfler {
722065e8de0SAxel Dörfler 	if (fLegendLayoutItem == NULL)
723065e8de0SAxel Dörfler 		fLegendLayoutItem = new LegendLayoutItem(this);
724065e8de0SAxel Dörfler 
725065e8de0SAxel Dörfler 	return fLegendLayoutItem;
726065e8de0SAxel Dörfler }
727dc1ffc79SFrançois Revol #endif
728065e8de0SAxel Dörfler 
7299c89c450SAxel Dörfler 
73018d3e65eSAxel Dörfler DataSource*
7313a4a2141SAxel Dörfler ActivityView::FindDataSource(const DataSource* search)
73218d3e65eSAxel Dörfler {
733d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
734d4216445SAxel Dörfler 
73518d3e65eSAxel Dörfler 	for (int32 i = fSources.CountItems(); i-- > 0;) {
73618d3e65eSAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
7373a4a2141SAxel Dörfler 		if (!strcmp(source->Name(), search->Name()))
73818d3e65eSAxel Dörfler 			return source;
73918d3e65eSAxel Dörfler 	}
74018d3e65eSAxel Dörfler 
74118d3e65eSAxel Dörfler 	return NULL;
74218d3e65eSAxel Dörfler }
74318d3e65eSAxel Dörfler 
74418d3e65eSAxel Dörfler 
74518d3e65eSAxel Dörfler status_t
7469c89c450SAxel Dörfler ActivityView::AddDataSource(const DataSource* source, const BMessage* state)
74718d3e65eSAxel Dörfler {
7483a4a2141SAxel Dörfler 	if (source == NULL)
7493a4a2141SAxel Dörfler 		return B_BAD_VALUE;
7503a4a2141SAxel Dörfler 
751d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
752d4216445SAxel Dörfler 
753*8e26f387SAxel Dörfler 	// Search for the correct insert spot to maintain the order of the sources
7543a4a2141SAxel Dörfler 	int32 insert = DataSource::IndexOf(source);
7553a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems() && i < insert; i++) {
7563a4a2141SAxel Dörfler 		DataSource* before = fSources.ItemAt(i);
7573a4a2141SAxel Dörfler 		if (DataSource::IndexOf(before) > insert) {
7583a4a2141SAxel Dörfler 			insert = i;
7593a4a2141SAxel Dörfler 			break;
7603a4a2141SAxel Dörfler 		}
7613a4a2141SAxel Dörfler 	}
7623a4a2141SAxel Dörfler 	if (insert > fSources.CountItems())
7633a4a2141SAxel Dörfler 		insert = fSources.CountItems();
7643a4a2141SAxel Dörfler 
765*8e26f387SAxel Dörfler 	// Generate DataHistory and ViewHistory objects for the source
766*8e26f387SAxel Dörfler 	// (one might need one history per CPU)
767*8e26f387SAxel Dörfler 
7683a4a2141SAxel Dörfler 	uint32 count = 1;
7693a4a2141SAxel Dörfler 	if (source->PerCPU()) {
7703a4a2141SAxel Dörfler 		SystemInfo info;
7713a4a2141SAxel Dörfler 		count = info.CPUCount();
7723a4a2141SAxel Dörfler 	}
7733a4a2141SAxel Dörfler 
7743a4a2141SAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
77518d3e65eSAxel Dörfler 		DataHistory* values = new(std::nothrow) DataHistory(10 * 60000000LL,
7761bb87bd0SAxel Dörfler 			RefreshInterval());
777*8e26f387SAxel Dörfler 		ListAddDeleter<DataHistory> valuesDeleter(fValues, values, insert);
7783a4a2141SAxel Dörfler 
779*8e26f387SAxel Dörfler 		ViewHistory* viewValues = new(std::nothrow) ViewHistory;
780*8e26f387SAxel Dörfler 		ListAddDeleter<ViewHistory> viewValuesDeleter(fViewValues, viewValues,
781*8e26f387SAxel Dörfler 			insert);
782*8e26f387SAxel Dörfler 
783*8e26f387SAxel Dörfler 		if (valuesDeleter.Failed() || viewValuesDeleter.Failed())
78418d3e65eSAxel Dörfler 			return B_NO_MEMORY;
78518d3e65eSAxel Dörfler 
78651591198SAxel Dörfler 		values->SetScale(_ScaleFor(source->ScaleType()));
78751591198SAxel Dörfler 
7883a4a2141SAxel Dörfler 		DataSource* copy;
7893a4a2141SAxel Dörfler 		if (source->PerCPU())
7903a4a2141SAxel Dörfler 			copy = source->CopyForCPU(i);
7913a4a2141SAxel Dörfler 		else
7923a4a2141SAxel Dörfler 			copy = source->Copy();
7933a4a2141SAxel Dörfler 
794*8e26f387SAxel Dörfler 		ListAddDeleter<DataSource> sourceDeleter(fSources, copy, insert);
795*8e26f387SAxel Dörfler 		if (sourceDeleter.Failed())
796*8e26f387SAxel Dörfler 			return B_NO_MEMORY;
797*8e26f387SAxel Dörfler 
7989c89c450SAxel Dörfler 		BString colorName = source->Name();
7999c89c450SAxel Dörfler 		colorName << " color";
8009c89c450SAxel Dörfler 		if (state != NULL) {
8019c89c450SAxel Dörfler 			const rgb_color* color = NULL;
8029c89c450SAxel Dörfler 			ssize_t colorLength;
8039c89c450SAxel Dörfler 			if (state->FindData(colorName.String(), B_RGB_COLOR_TYPE, i,
8049c89c450SAxel Dörfler 					(const void**)&color, &colorLength) == B_OK
8059c89c450SAxel Dörfler 				&& colorLength == sizeof(rgb_color))
8069c89c450SAxel Dörfler 				copy->SetColor(*color);
8079c89c450SAxel Dörfler 		}
8089c89c450SAxel Dörfler 
809*8e26f387SAxel Dörfler 		valuesDeleter.Detach();
810*8e26f387SAxel Dörfler 		viewValuesDeleter.Detach();
811*8e26f387SAxel Dörfler 		sourceDeleter.Detach();
8123a4a2141SAxel Dörfler 	}
81318d3e65eSAxel Dörfler 
814dc1ffc79SFrançois Revol #ifdef __HAIKU__
815065e8de0SAxel Dörfler 	InvalidateLayout();
816dc1ffc79SFrançois Revol #endif
81718d3e65eSAxel Dörfler 	return B_OK;
81818d3e65eSAxel Dörfler }
81918d3e65eSAxel Dörfler 
82018d3e65eSAxel Dörfler 
82118d3e65eSAxel Dörfler status_t
8223a4a2141SAxel Dörfler ActivityView::RemoveDataSource(const DataSource* remove)
82318d3e65eSAxel Dörfler {
824065e8de0SAxel Dörfler 	bool removed = false;
825065e8de0SAxel Dörfler 
826d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
827d4216445SAxel Dörfler 
8283a4a2141SAxel Dörfler 	while (true) {
8293a4a2141SAxel Dörfler 		DataSource* source = FindDataSource(remove);
830acef7474SFrançois Revol 		//debug_printf("SEARCH %s, found %p\n", remove->Name(), source);
831065e8de0SAxel Dörfler 		if (source == NULL) {
832065e8de0SAxel Dörfler 			if (removed)
833065e8de0SAxel Dörfler 				break;
834065e8de0SAxel Dörfler 			return B_ENTRY_NOT_FOUND;
835065e8de0SAxel Dörfler 		}
8363a4a2141SAxel Dörfler 
83718d3e65eSAxel Dörfler 		int32 index = fSources.IndexOf(source);
83818d3e65eSAxel Dörfler 		if (index < 0)
83918d3e65eSAxel Dörfler 			return B_ENTRY_NOT_FOUND;
84018d3e65eSAxel Dörfler 
84118d3e65eSAxel Dörfler 		fSources.RemoveItemAt(index);
84218d3e65eSAxel Dörfler 		delete source;
84318d3e65eSAxel Dörfler 		DataHistory* values = fValues.RemoveItemAt(index);
84418d3e65eSAxel Dörfler 		delete values;
845065e8de0SAxel Dörfler 		removed = true;
8463a4a2141SAxel Dörfler 	}
84718d3e65eSAxel Dörfler 
848dc1ffc79SFrançois Revol #ifdef __HAIKU__
849065e8de0SAxel Dörfler 	InvalidateLayout();
850dc1ffc79SFrançois Revol #endif
85118d3e65eSAxel Dörfler 	return B_OK;
85218d3e65eSAxel Dörfler }
85318d3e65eSAxel Dörfler 
85418d3e65eSAxel Dörfler 
85518d3e65eSAxel Dörfler void
85618d3e65eSAxel Dörfler ActivityView::RemoveAllDataSources()
85718d3e65eSAxel Dörfler {
858d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
859d4216445SAxel Dörfler 
86018d3e65eSAxel Dörfler 	fSources.MakeEmpty();
86118d3e65eSAxel Dörfler 	fValues.MakeEmpty();
86218d3e65eSAxel Dörfler }
86318d3e65eSAxel Dörfler 
86418d3e65eSAxel Dörfler 
86518d3e65eSAxel Dörfler void
86618d3e65eSAxel Dörfler ActivityView::AttachedToWindow()
86718d3e65eSAxel Dörfler {
86874158bb4SFrançois Revol 	Looper()->AddHandler(fSystemInfoHandler);
8696f6ba875SAxel Dörfler 	fSystemInfoHandler->StartWatching();
8706f6ba875SAxel Dörfler 
871d4216445SAxel Dörfler 	fRefreshSem = create_sem(0, "refresh sem");
872d4216445SAxel Dörfler 	fRefreshThread = spawn_thread(&_RefreshThread, "source refresh",
873*8e26f387SAxel Dörfler 		B_URGENT_DISPLAY_PRIORITY, this);
874d4216445SAxel Dörfler 	resume_thread(fRefreshThread);
8753a4a2141SAxel Dörfler 
8763a4a2141SAxel Dörfler 	FrameResized(Bounds().Width(), Bounds().Height());
87718d3e65eSAxel Dörfler }
87818d3e65eSAxel Dörfler 
87918d3e65eSAxel Dörfler 
88018d3e65eSAxel Dörfler void
88118d3e65eSAxel Dörfler ActivityView::DetachedFromWindow()
88218d3e65eSAxel Dörfler {
8836f6ba875SAxel Dörfler 	fSystemInfoHandler->StopWatching();
88474158bb4SFrançois Revol 	Looper()->RemoveHandler(fSystemInfoHandler);
8856f6ba875SAxel Dörfler 
886d4216445SAxel Dörfler 	delete_sem(fRefreshSem);
887d4216445SAxel Dörfler 	wait_for_thread(fRefreshThread, NULL);
88818d3e65eSAxel Dörfler }
88918d3e65eSAxel Dörfler 
89018d3e65eSAxel Dörfler 
891cbd4bc95SFrançois Revol #ifdef __HAIKU__
8923a4a2141SAxel Dörfler BSize
8933a4a2141SAxel Dörfler ActivityView::MinSize()
8943a4a2141SAxel Dörfler {
8953a4a2141SAxel Dörfler 	BSize size(32, 32);
8963a4a2141SAxel Dörfler 	if (fShowLegend)
8979c89c450SAxel Dörfler 		size.height = _LegendHeight();
8983a4a2141SAxel Dörfler 
8993a4a2141SAxel Dörfler 	return size;
9003a4a2141SAxel Dörfler }
901cbd4bc95SFrançois Revol #endif
9023a4a2141SAxel Dörfler 
9033a4a2141SAxel Dörfler 
90418d3e65eSAxel Dörfler void
90518d3e65eSAxel Dörfler ActivityView::FrameResized(float /*width*/, float /*height*/)
90618d3e65eSAxel Dörfler {
9073a4a2141SAxel Dörfler 	_UpdateOffscreenBitmap();
9083a4a2141SAxel Dörfler }
9093a4a2141SAxel Dörfler 
9103a4a2141SAxel Dörfler 
9113a4a2141SAxel Dörfler void
9129c89c450SAxel Dörfler ActivityView::_UpdateOffscreenBitmap()
9133a4a2141SAxel Dörfler {
9143a4a2141SAxel Dörfler 	BRect frame = _HistoryFrame();
9159c89c450SAxel Dörfler 	if (fOffscreen != NULL && frame == fOffscreen->Bounds())
9163a4a2141SAxel Dörfler 		return;
9173a4a2141SAxel Dörfler 
9183a4a2141SAxel Dörfler 	delete fOffscreen;
9193a4a2141SAxel Dörfler 
9203a4a2141SAxel Dörfler 	// create offscreen bitmap
9213a4a2141SAxel Dörfler 
9223a4a2141SAxel Dörfler 	fOffscreen = new(std::nothrow) BBitmap(frame, B_BITMAP_ACCEPTS_VIEWS,
9233a4a2141SAxel Dörfler 		B_RGB32);
9243a4a2141SAxel Dörfler 	if (fOffscreen == NULL || fOffscreen->InitCheck() != B_OK) {
9253a4a2141SAxel Dörfler 		delete fOffscreen;
9263a4a2141SAxel Dörfler 		fOffscreen = NULL;
9273a4a2141SAxel Dörfler 		return;
9283a4a2141SAxel Dörfler 	}
9293a4a2141SAxel Dörfler 
9303a4a2141SAxel Dörfler 	BView* view = new BView(frame, NULL, B_FOLLOW_NONE, B_SUBPIXEL_PRECISE);
9319c89c450SAxel Dörfler 	view->SetViewColor(fHistoryBackgroundColor);
9323a4a2141SAxel Dörfler 	view->SetLowColor(view->ViewColor());
9333a4a2141SAxel Dörfler 	fOffscreen->AddChild(view);
93418d3e65eSAxel Dörfler }
93518d3e65eSAxel Dörfler 
93618d3e65eSAxel Dörfler 
9379c89c450SAxel Dörfler BView*
9389c89c450SAxel Dörfler ActivityView::_OffscreenView()
9399c89c450SAxel Dörfler {
9409c89c450SAxel Dörfler 	if (fOffscreen == NULL)
9419c89c450SAxel Dörfler 		return NULL;
9429c89c450SAxel Dörfler 
9439c89c450SAxel Dörfler 	return fOffscreen->ChildAt(0);
9449c89c450SAxel Dörfler }
9459c89c450SAxel Dörfler 
9469c89c450SAxel Dörfler 
94718d3e65eSAxel Dörfler void
94818d3e65eSAxel Dörfler ActivityView::MouseDown(BPoint where)
94918d3e65eSAxel Dörfler {
95051591198SAxel Dörfler 	int32 buttons = B_SECONDARY_MOUSE_BUTTON;
95151591198SAxel Dörfler 	if (Looper() != NULL && Looper()->CurrentMessage() != NULL)
95218d3e65eSAxel Dörfler 		Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
95351591198SAxel Dörfler 
95451591198SAxel Dörfler 	if (buttons == B_PRIMARY_MOUSE_BUTTON) {
95551591198SAxel Dörfler 		fZoomPoint = where;
95651591198SAxel Dörfler 		fOriginalResolution = fDrawResolution;
95751591198SAxel Dörfler 		fZooming = true;
958*8e26f387SAxel Dörfler 		SetMouseEventMask(B_POINTER_EVENTS);
95951591198SAxel Dörfler 		return;
96018d3e65eSAxel Dörfler 	}
96118d3e65eSAxel Dörfler 
96218d3e65eSAxel Dörfler 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
96318d3e65eSAxel Dörfler 	menu->SetFont(be_plain_font);
9643a4a2141SAxel Dörfler 
96543eda1cdSAxel Dörfler 	BMenu* additionalMenu = new BMenu("Additional Items");
966dc1ffc79SFrançois Revol 	additionalMenu->SetFont(be_plain_font);
967dc1ffc79SFrançois Revol 
9683a4a2141SAxel Dörfler 	SystemInfo info;
96918d3e65eSAxel Dörfler 	BMenuItem* item;
97018d3e65eSAxel Dörfler 
97118d3e65eSAxel Dörfler 	for (int32 i = 0; i < DataSource::CountSources(); i++) {
97218d3e65eSAxel Dörfler 		const DataSource* source = DataSource::SourceAt(i);
97318d3e65eSAxel Dörfler 
9743a4a2141SAxel Dörfler 		if (source->MultiCPUOnly() && info.CPUCount() == 1)
9753a4a2141SAxel Dörfler 			continue;
9763a4a2141SAxel Dörfler 
97718d3e65eSAxel Dörfler 		BMessage* message = new BMessage(kMsgToggleDataSource);
97818d3e65eSAxel Dörfler 		message->AddInt32("index", i);
97918d3e65eSAxel Dörfler 
9803a4a2141SAxel Dörfler 		item = new BMenuItem(source->Name(), message);
9813a4a2141SAxel Dörfler 		if (FindDataSource(source))
98218d3e65eSAxel Dörfler 			item->SetMarked(true);
98318d3e65eSAxel Dörfler 
98443eda1cdSAxel Dörfler 		if (source->Primary())
98518d3e65eSAxel Dörfler 			menu->AddItem(item);
98643eda1cdSAxel Dörfler 		else
98743eda1cdSAxel Dörfler 			additionalMenu->AddItem(item);
98818d3e65eSAxel Dörfler 	}
98918d3e65eSAxel Dörfler 
99043eda1cdSAxel Dörfler 	menu->AddItem(new BMenuItem(additionalMenu));
9913a4a2141SAxel Dörfler 	menu->AddSeparatorItem();
9923a4a2141SAxel Dörfler 	menu->AddItem(new BMenuItem(fShowLegend ? "Hide Legend" : "Show Legend",
9933a4a2141SAxel Dörfler 		new BMessage(kMsgToggleLegend)));
9943a4a2141SAxel Dörfler 
99518d3e65eSAxel Dörfler 	menu->SetTargetForItems(this);
996dc1ffc79SFrançois Revol 	additionalMenu->SetTargetForItems(this);
99718d3e65eSAxel Dörfler 
9983f315b26SAxel Dörfler 	ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window());
9993f315b26SAxel Dörfler 	if (window != NULL && window->ActivityViewCount() > 1) {
10003f315b26SAxel Dörfler 		menu->AddSeparatorItem();
10013f315b26SAxel Dörfler 		BMessage* message = new BMessage(kMsgRemoveView);
10023f315b26SAxel Dörfler 		message->AddPointer("view", this);
10033f315b26SAxel Dörfler 		menu->AddItem(item = new BMenuItem("Remove View", message));
10043f315b26SAxel Dörfler 		item->SetTarget(window);
10053f315b26SAxel Dörfler 	}
10063f315b26SAxel Dörfler 
100718d3e65eSAxel Dörfler 	ConvertToScreen(&where);
100818d3e65eSAxel Dörfler 	menu->Go(where, true, false, true);
100918d3e65eSAxel Dörfler }
101018d3e65eSAxel Dörfler 
101118d3e65eSAxel Dörfler 
101218d3e65eSAxel Dörfler void
101351591198SAxel Dörfler ActivityView::MouseUp(BPoint where)
101451591198SAxel Dörfler {
101551591198SAxel Dörfler 	fZooming = false;
101651591198SAxel Dörfler }
101751591198SAxel Dörfler 
101851591198SAxel Dörfler 
101951591198SAxel Dörfler void
102018d3e65eSAxel Dörfler ActivityView::MouseMoved(BPoint where, uint32 transit,
102118d3e65eSAxel Dörfler 	const BMessage* dragMessage)
102218d3e65eSAxel Dörfler {
102351591198SAxel Dörfler 	if (!fZooming)
102451591198SAxel Dörfler 		return;
102551591198SAxel Dörfler 
102651591198SAxel Dörfler 	int32 shift = int32(where.x - fZoomPoint.x) / 25;
10271bb87bd0SAxel Dörfler 	int32 resolution;
102851591198SAxel Dörfler 	if (shift > 0)
10291bb87bd0SAxel Dörfler 		resolution = fOriginalResolution << shift;
103051591198SAxel Dörfler 	else
10311bb87bd0SAxel Dörfler 		resolution = fOriginalResolution >> -shift;
103251591198SAxel Dörfler 
10331bb87bd0SAxel Dörfler 	_UpdateResolution(resolution);
103418d3e65eSAxel Dörfler }
103518d3e65eSAxel Dörfler 
103618d3e65eSAxel Dörfler 
103718d3e65eSAxel Dörfler void
103818d3e65eSAxel Dörfler ActivityView::MessageReceived(BMessage* message)
103918d3e65eSAxel Dörfler {
1040c28f8ea3SFrançois Revol 	// if a color is dropped, use it as background
1041c28f8ea3SFrançois Revol 	if (message->WasDropped()) {
1042c28f8ea3SFrançois Revol 		rgb_color* color;
1043c28f8ea3SFrançois Revol 		ssize_t size;
10441201d52eSAxel Dörfler 		if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 0,
10451201d52eSAxel Dörfler 				(const void**)&color, &size) == B_OK
10469c89c450SAxel Dörfler 			&& size == sizeof(rgb_color)) {
10479c89c450SAxel Dörfler 			BPoint dropPoint = message->DropPoint();
1048c28f8ea3SFrançois Revol 			ConvertFromScreen(&dropPoint);
10499c89c450SAxel Dörfler 
1050c28f8ea3SFrançois Revol 			if (_HistoryFrame().Contains(dropPoint)) {
10519c89c450SAxel Dörfler 				fHistoryBackgroundColor = *color;
10529c89c450SAxel Dörfler 				Invalidate(_HistoryFrame());
1053c28f8ea3SFrançois Revol 			} else {
10545f2f72a2SFrançois Revol 				// check each legend color box
1055d4216445SAxel Dörfler 				BAutolock _(fSourcesLock);
1056d4216445SAxel Dörfler 
10575f2f72a2SFrançois Revol 				BRect legendFrame = _LegendFrame();
10589c89c450SAxel Dörfler 				for (int32 i = 0; i < fSources.CountItems(); i++) {
10591201d52eSAxel Dörfler 					BRect frame = _LegendColorFrameAt(legendFrame, i);
10609c89c450SAxel Dörfler 					if (frame.Contains(dropPoint)) {
10615f2f72a2SFrançois Revol 						fSources.ItemAt(i)->SetColor(*color);
10629c89c450SAxel Dörfler 						Invalidate(_HistoryFrame());
10631201d52eSAxel Dörfler 						Invalidate(frame);
10645f2f72a2SFrançois Revol 						return;
10655f2f72a2SFrançois Revol 					}
10665f2f72a2SFrançois Revol 				}
10679c89c450SAxel Dörfler 
10689c89c450SAxel Dörfler 				if (dynamic_cast<ActivityMonitor*>(be_app) == NULL) {
10699c89c450SAxel Dörfler 					// allow background color change in the replicant only
10709c89c450SAxel Dörfler 					fLegendBackgroundColor = *color;
10711201d52eSAxel Dörfler 					SetLowColor(fLegendBackgroundColor);
10729c89c450SAxel Dörfler 					Invalidate(legendFrame);
10739c89c450SAxel Dörfler 				}
1074c28f8ea3SFrançois Revol 			}
1075c28f8ea3SFrançois Revol 			return;
1076c28f8ea3SFrançois Revol 		}
10779c89c450SAxel Dörfler 	}
10789c89c450SAxel Dörfler 
107918d3e65eSAxel Dörfler 	switch (message->what) {
108018d3e65eSAxel Dörfler 		case B_ABOUT_REQUESTED:
108118d3e65eSAxel Dörfler 			ActivityMonitor::ShowAbout();
108218d3e65eSAxel Dörfler 			break;
108318d3e65eSAxel Dörfler 
10841bb87bd0SAxel Dörfler 		case kMsgUpdateResolution:
10851bb87bd0SAxel Dörfler 		{
10861bb87bd0SAxel Dörfler 			int32 resolution;
10871bb87bd0SAxel Dörfler 			if (message->FindInt32("resolution", &resolution) != B_OK)
10881bb87bd0SAxel Dörfler 				break;
10891bb87bd0SAxel Dörfler 
10901bb87bd0SAxel Dörfler 			_UpdateResolution(resolution, false);
10911bb87bd0SAxel Dörfler 			break;
10921bb87bd0SAxel Dörfler 		}
10931bb87bd0SAxel Dörfler 
10941bb87bd0SAxel Dörfler 		case kMsgTimeIntervalUpdated:
10951bb87bd0SAxel Dörfler 			bigtime_t interval;
10961bb87bd0SAxel Dörfler 			if (message->FindInt64("interval", &interval) != B_OK)
10971bb87bd0SAxel Dörfler 				break;
10981bb87bd0SAxel Dörfler 
10991bb87bd0SAxel Dörfler 			if (interval < 10000)
11001bb87bd0SAxel Dörfler 				interval = 10000;
11011bb87bd0SAxel Dörfler 
11021bb87bd0SAxel Dörfler 			atomic_set64(&fRefreshInterval, interval);
11031bb87bd0SAxel Dörfler 			break;
11041bb87bd0SAxel Dörfler 
110518d3e65eSAxel Dörfler 		case kMsgToggleDataSource:
110618d3e65eSAxel Dörfler 		{
110718d3e65eSAxel Dörfler 			int32 index;
110818d3e65eSAxel Dörfler 			if (message->FindInt32("index", &index) != B_OK)
110918d3e65eSAxel Dörfler 				break;
111018d3e65eSAxel Dörfler 
111118d3e65eSAxel Dörfler 			const DataSource* baseSource = DataSource::SourceAt(index);
111218d3e65eSAxel Dörfler 			if (baseSource == NULL)
111318d3e65eSAxel Dörfler 				break;
111418d3e65eSAxel Dörfler 
11153a4a2141SAxel Dörfler 			DataSource* source = FindDataSource(baseSource);
111618d3e65eSAxel Dörfler 			if (source == NULL)
11173a4a2141SAxel Dörfler 				AddDataSource(baseSource);
111818d3e65eSAxel Dörfler 			else
111918d3e65eSAxel Dörfler 				RemoveDataSource(source);
112018d3e65eSAxel Dörfler 
112118d3e65eSAxel Dörfler 			Invalidate();
112218d3e65eSAxel Dörfler 			break;
112318d3e65eSAxel Dörfler 		}
112418d3e65eSAxel Dörfler 
11253a4a2141SAxel Dörfler 		case kMsgToggleLegend:
11263a4a2141SAxel Dörfler 			fShowLegend = !fShowLegend;
11273a4a2141SAxel Dörfler 			Invalidate();
11283a4a2141SAxel Dörfler 			break;
11293a4a2141SAxel Dörfler 
113018d3e65eSAxel Dörfler 		case B_MOUSE_WHEEL_CHANGED:
113118d3e65eSAxel Dörfler 		{
113218d3e65eSAxel Dörfler 			float deltaY = 0.0f;
113318d3e65eSAxel Dörfler 			if (message->FindFloat("be:wheel_delta_y", &deltaY) != B_OK
113418d3e65eSAxel Dörfler 				|| deltaY == 0.0f)
113518d3e65eSAxel Dörfler 				break;
113618d3e65eSAxel Dörfler 
11371bb87bd0SAxel Dörfler 			int32 resolution = fDrawResolution;
113818d3e65eSAxel Dörfler 			if (deltaY > 0)
11391bb87bd0SAxel Dörfler 				resolution *= 2;
114018d3e65eSAxel Dörfler 			else
11411bb87bd0SAxel Dörfler 				resolution /= 2;
114218d3e65eSAxel Dörfler 
11431bb87bd0SAxel Dörfler 			_UpdateResolution(resolution);
114418d3e65eSAxel Dörfler 			break;
114518d3e65eSAxel Dörfler 		}
114618d3e65eSAxel Dörfler 
114718d3e65eSAxel Dörfler 		default:
114818d3e65eSAxel Dörfler 			BView::MessageReceived(message);
114918d3e65eSAxel Dörfler 			break;
115018d3e65eSAxel Dörfler 	}
115118d3e65eSAxel Dörfler }
115218d3e65eSAxel Dörfler 
115318d3e65eSAxel Dörfler 
1154065e8de0SAxel Dörfler void
1155065e8de0SAxel Dörfler ActivityView::_UpdateFrame()
1156065e8de0SAxel Dörfler {
1157dc1ffc79SFrançois Revol #ifdef __HAIKU__
1158065e8de0SAxel Dörfler 	if (fLegendLayoutItem == NULL || fHistoryLayoutItem == NULL)
1159065e8de0SAxel Dörfler 		return;
1160065e8de0SAxel Dörfler 
1161065e8de0SAxel Dörfler 	BRect historyFrame = fHistoryLayoutItem->Frame();
1162065e8de0SAxel Dörfler 	BRect legendFrame = fLegendLayoutItem->Frame();
1163dc1ffc79SFrançois Revol #else
1164dc1ffc79SFrançois Revol 	BRect historyFrame = Bounds();
1165dc1ffc79SFrançois Revol 	BRect legendFrame = Bounds();
1166dc1ffc79SFrançois Revol 	historyFrame.bottom -= 2 * Bounds().Height() / 3;
1167dc1ffc79SFrançois Revol 	legendFrame.top += Bounds().Height() / 3;
1168dc1ffc79SFrançois Revol #endif
1169065e8de0SAxel Dörfler 	MoveTo(historyFrame.left, historyFrame.top);
1170065e8de0SAxel Dörfler 	ResizeTo(legendFrame.left + legendFrame.Width() - historyFrame.left,
1171065e8de0SAxel Dörfler 		legendFrame.top + legendFrame.Height() - historyFrame.top);
1172065e8de0SAxel Dörfler }
1173065e8de0SAxel Dörfler 
1174065e8de0SAxel Dörfler 
11753a4a2141SAxel Dörfler BRect
11763a4a2141SAxel Dörfler ActivityView::_HistoryFrame() const
11773a4a2141SAxel Dörfler {
11783a4a2141SAxel Dörfler 	if (!fShowLegend)
11793a4a2141SAxel Dörfler 		return Bounds();
11803a4a2141SAxel Dörfler 
11813a4a2141SAxel Dörfler 	BRect frame = Bounds();
11823a4a2141SAxel Dörfler 	BRect legendFrame = _LegendFrame();
11833a4a2141SAxel Dörfler 
11843a4a2141SAxel Dörfler 	frame.bottom = legendFrame.top - 1;
11853a4a2141SAxel Dörfler 
11863a4a2141SAxel Dörfler 	return frame;
11873a4a2141SAxel Dörfler }
11883a4a2141SAxel Dörfler 
11893a4a2141SAxel Dörfler 
1190065e8de0SAxel Dörfler float
1191065e8de0SAxel Dörfler ActivityView::_LegendHeight() const
11923a4a2141SAxel Dörfler {
11933a4a2141SAxel Dörfler 	font_height fontHeight;
11943a4a2141SAxel Dörfler 	GetFontHeight(&fontHeight);
11953a4a2141SAxel Dörfler 
1196d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
1197d4216445SAxel Dörfler 
11983a4a2141SAxel Dörfler 	int32 rows = (fSources.CountItems() + 1) / 2;
1199065e8de0SAxel Dörfler 	return rows * (4 + ceilf(fontHeight.ascent)
12003a4a2141SAxel Dörfler 		+ ceilf(fontHeight.descent) + ceilf(fontHeight.leading));
1201065e8de0SAxel Dörfler }
1202065e8de0SAxel Dörfler 
1203065e8de0SAxel Dörfler 
1204065e8de0SAxel Dörfler BRect
1205065e8de0SAxel Dörfler ActivityView::_LegendFrame() const
1206065e8de0SAxel Dörfler {
1207065e8de0SAxel Dörfler 	float height;
1208dc1ffc79SFrançois Revol #ifdef __HAIKU__
1209065e8de0SAxel Dörfler 	if (fLegendLayoutItem != NULL)
1210065e8de0SAxel Dörfler 		height = fLegendLayoutItem->Frame().Height();
1211065e8de0SAxel Dörfler 	else
1212dc1ffc79SFrançois Revol #endif
1213065e8de0SAxel Dörfler 		height = _LegendHeight();
1214065e8de0SAxel Dörfler 
1215065e8de0SAxel Dörfler 	BRect frame = Bounds();
1216065e8de0SAxel Dörfler 	frame.top = frame.bottom - height;
12173a4a2141SAxel Dörfler 
12183a4a2141SAxel Dörfler 	return frame;
12193a4a2141SAxel Dörfler }
12203a4a2141SAxel Dörfler 
12213a4a2141SAxel Dörfler 
12223a4a2141SAxel Dörfler BRect
12233a4a2141SAxel Dörfler ActivityView::_LegendFrameAt(BRect frame, int32 index) const
12243a4a2141SAxel Dörfler {
12253a4a2141SAxel Dörfler 	int32 column = index & 1;
12263a4a2141SAxel Dörfler 	int32 row = index / 2;
12273a4a2141SAxel Dörfler 	if (column == 0)
12283a4a2141SAxel Dörfler 		frame.right = frame.left + floorf(frame.Width() / 2) - 5;
12293a4a2141SAxel Dörfler 	else
12303a4a2141SAxel Dörfler 		frame.left = frame.right - floorf(frame.Width() / 2) + 5;
12313a4a2141SAxel Dörfler 
1232d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
1233d4216445SAxel Dörfler 
12343a4a2141SAxel Dörfler 	int32 rows = (fSources.CountItems() + 1) / 2;
12353a4a2141SAxel Dörfler 	float height = floorf((frame.Height() - 5) / rows);
12363a4a2141SAxel Dörfler 
12373a4a2141SAxel Dörfler 	frame.top = frame.top + 5 + row * height;
12383a4a2141SAxel Dörfler 	frame.bottom = frame.top + height - 1;
12393a4a2141SAxel Dörfler 
12403a4a2141SAxel Dörfler 	return frame;
12413a4a2141SAxel Dörfler }
12423a4a2141SAxel Dörfler 
12433a4a2141SAxel Dörfler 
12441201d52eSAxel Dörfler BRect
12451201d52eSAxel Dörfler ActivityView::_LegendColorFrameAt(BRect frame, int32 index) const
12461201d52eSAxel Dörfler {
12471201d52eSAxel Dörfler 	frame = _LegendFrameAt(frame, index);
12481201d52eSAxel Dörfler 	frame.InsetBy(1, 1);
12491201d52eSAxel Dörfler 	frame.right = frame.left + frame.Height();
12501201d52eSAxel Dörfler 
12511201d52eSAxel Dörfler 	return frame;
12521201d52eSAxel Dörfler }
12531201d52eSAxel Dörfler 
12541201d52eSAxel Dörfler 
125518d3e65eSAxel Dörfler float
125618d3e65eSAxel Dörfler ActivityView::_PositionForValue(DataSource* source, DataHistory* values,
125718d3e65eSAxel Dörfler 	int64 value)
125818d3e65eSAxel Dörfler {
125918d3e65eSAxel Dörfler 	int64 min = source->Minimum();
126018d3e65eSAxel Dörfler 	int64 max = source->Maximum();
126118d3e65eSAxel Dörfler 	if (source->AdaptiveScale()) {
126218d3e65eSAxel Dörfler 		int64 adaptiveMax = int64(values->MaximumValue() * 1.2);
126318d3e65eSAxel Dörfler 		if (adaptiveMax < max)
126418d3e65eSAxel Dörfler 			max = adaptiveMax;
126518d3e65eSAxel Dörfler 	}
126618d3e65eSAxel Dörfler 
126718d3e65eSAxel Dörfler 	if (value > max)
126818d3e65eSAxel Dörfler 		value = max;
126918d3e65eSAxel Dörfler 	if (value < min)
127018d3e65eSAxel Dörfler 		value = min;
127118d3e65eSAxel Dörfler 
12723a4a2141SAxel Dörfler 	float height = _HistoryFrame().Height();
127318d3e65eSAxel Dörfler 	return height - (value - min) * height / (max - min);
127418d3e65eSAxel Dörfler }
127518d3e65eSAxel Dörfler 
127618d3e65eSAxel Dörfler 
127718d3e65eSAxel Dörfler void
12783a4a2141SAxel Dörfler ActivityView::_DrawHistory()
127918d3e65eSAxel Dörfler {
12803a4a2141SAxel Dörfler 	_UpdateOffscreenBitmap();
12813a4a2141SAxel Dörfler 
12823a4a2141SAxel Dörfler 	BView* view = this;
12833a4a2141SAxel Dörfler 	if (fOffscreen != NULL) {
12843a4a2141SAxel Dörfler 		fOffscreen->Lock();
12859c89c450SAxel Dörfler 		view = _OffscreenView();
12863a4a2141SAxel Dörfler 	}
12873a4a2141SAxel Dörfler 
12883a4a2141SAxel Dörfler 	BRect frame = _HistoryFrame();
12891201d52eSAxel Dörfler 	view->SetLowColor(fHistoryBackgroundColor);
12903a4a2141SAxel Dörfler 	view->FillRect(frame, B_SOLID_LOW);
12913a4a2141SAxel Dörfler 
129218d3e65eSAxel Dörfler 	uint32 step = 2;
129318d3e65eSAxel Dörfler 	uint32 resolution = fDrawResolution;
129418d3e65eSAxel Dörfler 	if (fDrawResolution > 1) {
129518d3e65eSAxel Dörfler 		step = 1;
129618d3e65eSAxel Dörfler 		resolution--;
129718d3e65eSAxel Dörfler 	}
129818d3e65eSAxel Dörfler 
12993a4a2141SAxel Dörfler 	uint32 width = frame.IntegerWidth() - 10;
130018d3e65eSAxel Dörfler 	uint32 steps = width / step;
13011bb87bd0SAxel Dörfler 	bigtime_t timeStep = RefreshInterval() * resolution;
130218d3e65eSAxel Dörfler 	bigtime_t now = system_time();
130318d3e65eSAxel Dörfler 
13041201d52eSAxel Dörfler 	// Draw scale
13051201d52eSAxel Dörfler 	// TODO: add second markers?
13061201d52eSAxel Dörfler 
13073a4a2141SAxel Dörfler 	view->SetPenSize(1);
13083a4a2141SAxel Dörfler 
13091201d52eSAxel Dörfler 	rgb_color scaleColor = view->LowColor();
13101201d52eSAxel Dörfler 	uint32 average = (scaleColor.red + scaleColor.green + scaleColor.blue) / 3;
13111201d52eSAxel Dörfler 	if (average < 96)
13121201d52eSAxel Dörfler 		scaleColor = tint_color(scaleColor, B_LIGHTEN_2_TINT);
13131201d52eSAxel Dörfler 	else
13141201d52eSAxel Dörfler 		scaleColor = tint_color(scaleColor, B_DARKEN_2_TINT);
13151201d52eSAxel Dörfler 
13161201d52eSAxel Dörfler 	view->SetHighColor(scaleColor);
13173a4a2141SAxel Dörfler 	view->StrokeRect(frame);
13183a4a2141SAxel Dörfler 	view->StrokeLine(BPoint(frame.left, frame.top + frame.Height() / 2),
13193a4a2141SAxel Dörfler 		BPoint(frame.right, frame.top + frame.Height() / 2));
13203a4a2141SAxel Dörfler 
13211201d52eSAxel Dörfler 	// Draw values
13221201d52eSAxel Dörfler 
13231bb87bd0SAxel Dörfler 	view->SetPenSize(1.5);
1324d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
132518d3e65eSAxel Dörfler 
132618d3e65eSAxel Dörfler 	for (uint32 i = fSources.CountItems(); i-- > 0;) {
1327*8e26f387SAxel Dörfler 		ViewHistory* viewValues = fViewValues.ItemAt(i);
132818d3e65eSAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
132918d3e65eSAxel Dörfler 		DataHistory* values = fValues.ItemAt(i);
133018d3e65eSAxel Dörfler 
1331*8e26f387SAxel Dörfler 		viewValues->Update(values, steps, fDrawResolution, now, timeStep,
1332*8e26f387SAxel Dörfler 			RefreshInterval());
1333*8e26f387SAxel Dörfler 
1334*8e26f387SAxel Dörfler 		uint32 x = viewValues->Start() * step;
1335*8e26f387SAxel Dörfler 		BShape shape;
1336*8e26f387SAxel Dörfler 		bool first = true;
1337*8e26f387SAxel Dörfler 
1338*8e26f387SAxel Dörfler 		for (uint32 i = viewValues->Start(); i < steps; x += step, i++) {
1339*8e26f387SAxel Dörfler 			float y = _PositionForValue(source, values,
1340*8e26f387SAxel Dörfler 				viewValues->ValueAt(i));
1341*8e26f387SAxel Dörfler 
1342*8e26f387SAxel Dörfler 			if (first) {
1343*8e26f387SAxel Dörfler 				shape.MoveTo(BPoint(x, y));
1344*8e26f387SAxel Dörfler 				first = false;
1345*8e26f387SAxel Dörfler 			} else
1346*8e26f387SAxel Dörfler 				shape.LineTo(BPoint(x, y));
1347*8e26f387SAxel Dörfler 		}
1348*8e26f387SAxel Dörfler 
13493a4a2141SAxel Dörfler 		view->SetHighColor(source->Color());
1350*8e26f387SAxel Dörfler 		view->SetLineMode(B_BUTT_CAP, B_ROUND_JOIN);
1351*8e26f387SAxel Dörfler 		view->MovePenTo(B_ORIGIN);
1352*8e26f387SAxel Dörfler 		view->StrokeShape(&shape);
135318d3e65eSAxel Dörfler 	}
135418d3e65eSAxel Dörfler 
135518d3e65eSAxel Dörfler 	// TODO: add marks when an app started or quit
13563a4a2141SAxel Dörfler 	view->Sync();
13573a4a2141SAxel Dörfler 	if (fOffscreen != NULL) {
13583a4a2141SAxel Dörfler 		fOffscreen->Unlock();
13594e78d3bcSStephan Aßmus 		DrawBitmap(fOffscreen, B_ORIGIN);
13603a4a2141SAxel Dörfler 	}
13613a4a2141SAxel Dörfler }
13623a4a2141SAxel Dörfler 
13633a4a2141SAxel Dörfler 
13643a4a2141SAxel Dörfler void
13651bb87bd0SAxel Dörfler ActivityView::_UpdateResolution(int32 resolution, bool broadcast)
13661bb87bd0SAxel Dörfler {
13671bb87bd0SAxel Dörfler 	if (resolution < 1)
13681bb87bd0SAxel Dörfler 		resolution = 1;
13691bb87bd0SAxel Dörfler 	if (resolution > 128)
13701bb87bd0SAxel Dörfler 		resolution = 128;
13711bb87bd0SAxel Dörfler 
13721bb87bd0SAxel Dörfler 	if (resolution == fDrawResolution)
13731bb87bd0SAxel Dörfler 		return;
13741bb87bd0SAxel Dörfler 
13751bb87bd0SAxel Dörfler 	ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window());
13761bb87bd0SAxel Dörfler 	if (broadcast && window != NULL) {
13771bb87bd0SAxel Dörfler 		BMessage update(kMsgUpdateResolution);
13781bb87bd0SAxel Dörfler 		update.AddInt32("resolution", resolution);
13791bb87bd0SAxel Dörfler 		window->BroadcastToActivityViews(&update, this);
13801bb87bd0SAxel Dörfler 	}
13811bb87bd0SAxel Dörfler 
13821bb87bd0SAxel Dörfler 	fDrawResolution = resolution;
13831bb87bd0SAxel Dörfler 	Invalidate();
13841bb87bd0SAxel Dörfler }
13851bb87bd0SAxel Dörfler 
13861bb87bd0SAxel Dörfler 
13871bb87bd0SAxel Dörfler void
13883a4a2141SAxel Dörfler ActivityView::Draw(BRect /*updateRect*/)
13893a4a2141SAxel Dörfler {
13903a4a2141SAxel Dörfler 	_DrawHistory();
13913a4a2141SAxel Dörfler 
13923a4a2141SAxel Dörfler 	if (!fShowLegend)
13933a4a2141SAxel Dörfler 		return;
13943a4a2141SAxel Dörfler 
13953a4a2141SAxel Dörfler 	// draw legend
13963a4a2141SAxel Dörfler 
1397d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
13983a4a2141SAxel Dörfler 	BRect legendFrame = _LegendFrame();
13999c89c450SAxel Dörfler 
14009c89c450SAxel Dörfler 	SetLowColor(fLegendBackgroundColor);
14013a4a2141SAxel Dörfler 	FillRect(legendFrame, B_SOLID_LOW);
14023a4a2141SAxel Dörfler 
14033a4a2141SAxel Dörfler 	font_height fontHeight;
14043a4a2141SAxel Dörfler 	GetFontHeight(&fontHeight);
14053a4a2141SAxel Dörfler 
14063a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems(); i++) {
14073a4a2141SAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
14083a4a2141SAxel Dörfler 		DataHistory* values = fValues.ItemAt(i);
14093a4a2141SAxel Dörfler 		BRect frame = _LegendFrameAt(legendFrame, i);
14103a4a2141SAxel Dörfler 
14113a4a2141SAxel Dörfler 		// draw color box
14121201d52eSAxel Dörfler 		BRect colorBox = _LegendColorFrameAt(legendFrame, i);
14133a4a2141SAxel Dörfler 		SetHighColor(tint_color(source->Color(), B_DARKEN_1_TINT));
14143a4a2141SAxel Dörfler 		StrokeRect(colorBox);
14153a4a2141SAxel Dörfler 		SetHighColor(source->Color());
14163a4a2141SAxel Dörfler 		colorBox.InsetBy(1, 1);
14173a4a2141SAxel Dörfler 		FillRect(colorBox);
14183a4a2141SAxel Dörfler 
14193a4a2141SAxel Dörfler 		// show current value and label
14203a4a2141SAxel Dörfler 		float y = frame.top + ceilf(fontHeight.ascent);
14213a4a2141SAxel Dörfler 		int64 value = values->ValueAt(values->End());
14223a4a2141SAxel Dörfler 		BString text;
14233a4a2141SAxel Dörfler 		source->Print(text, value);
14243a4a2141SAxel Dörfler 		float width = StringWidth(text.String());
14253a4a2141SAxel Dörfler 
14263a4a2141SAxel Dörfler 		BString label = source->Label();
14273a4a2141SAxel Dörfler 		TruncateString(&label, B_TRUNCATE_MIDDLE,
14283a4a2141SAxel Dörfler 			frame.right - colorBox.right - 12 - width);
14293a4a2141SAxel Dörfler 
14303a4a2141SAxel Dörfler 		SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
14313a4a2141SAxel Dörfler 		DrawString(label.String(), BPoint(6 + colorBox.right, y));
14323a4a2141SAxel Dörfler 		DrawString(text.String(), BPoint(frame.right - width, y));
14333a4a2141SAxel Dörfler 	}
143418d3e65eSAxel Dörfler }
143518d3e65eSAxel Dörfler 
143618d3e65eSAxel Dörfler 
143718d3e65eSAxel Dörfler void
143818d3e65eSAxel Dörfler ActivityView::_Refresh()
143918d3e65eSAxel Dörfler {
14401bb87bd0SAxel Dörfler 	bigtime_t lastTimeout = system_time() - RefreshInterval();
14414ce1e1d2SAxel Dörfler 	BMessenger target(this);
144218d3e65eSAxel Dörfler 
1443d4216445SAxel Dörfler 	while (true) {
1444d4216445SAxel Dörfler 		status_t status = acquire_sem_etc(fRefreshSem, 1, B_ABSOLUTE_TIMEOUT,
14451bb87bd0SAxel Dörfler 			lastTimeout + RefreshInterval());
1446d4216445SAxel Dörfler 		if (status == B_OK || status == B_BAD_SEM_ID)
1447d4216445SAxel Dörfler 			break;
1448d4216445SAxel Dörfler 		if (status == B_INTERRUPTED)
1449d4216445SAxel Dörfler 			continue;
1450d4216445SAxel Dörfler 
1451d4216445SAxel Dörfler 		SystemInfo info(fSystemInfoHandler);
14521bb87bd0SAxel Dörfler 		lastTimeout += RefreshInterval();
1453d4216445SAxel Dörfler 
1454d4216445SAxel Dörfler 		fSourcesLock.Lock();
145518d3e65eSAxel Dörfler 
145618d3e65eSAxel Dörfler 		for (uint32 i = fSources.CountItems(); i-- > 0;) {
145718d3e65eSAxel Dörfler 			DataSource* source = fSources.ItemAt(i);
145818d3e65eSAxel Dörfler 			DataHistory* values = fValues.ItemAt(i);
145918d3e65eSAxel Dörfler 
146018d3e65eSAxel Dörfler 			int64 value = source->NextValue(info);
146118d3e65eSAxel Dörfler 			values->AddValue(info.Time(), value);
146218d3e65eSAxel Dörfler 		}
146318d3e65eSAxel Dörfler 
1464d4216445SAxel Dörfler 		fSourcesLock.Unlock();
1465d4216445SAxel Dörfler 
14664ce1e1d2SAxel Dörfler 		target.SendMessage(B_INVALIDATE);
146718d3e65eSAxel Dörfler 	}
1468d4216445SAxel Dörfler }
146918d3e65eSAxel Dörfler 
1470d4216445SAxel Dörfler 
1471d4216445SAxel Dörfler /*static*/ status_t
1472d4216445SAxel Dörfler ActivityView::_RefreshThread(void* self)
1473d4216445SAxel Dörfler {
1474d4216445SAxel Dörfler 	((ActivityView*)self)->_Refresh();
1475d4216445SAxel Dörfler 	return B_OK;
1476d4216445SAxel Dörfler }
1477