2 * Copyright 2008-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "ActivityWindow.h"
11 #include <Application.h>
14 #include <FindDirectory.h>
16 #include <GroupLayout.h>
24 #include "ActivityMonitor.h"
25 #include "ActivityView.h"
26 #include "DataSource.h"
27 #include "SettingsWindow.h"
29 #undef B_TRANSLATION_CONTEXT
30 #define B_TRANSLATION_CONTEXT "ActivityWindow"
33 static const uint32 kMsgAddView
= 'advw';
34 static const uint32 kMsgAlwaysOnTop
= 'alot';
35 static const uint32 kMsgShowSettings
= 'shst';
38 ActivityWindow::ActivityWindow()
40 BWindow(BRect(100, 100, 500, 350), B_TRANSLATE_SYSTEM_NAME("ActivityMonitor"),
41 B_TITLED_WINDOW
, B_ASYNCHRONOUS_CONTROLS
| B_QUIT_ON_WINDOW_CLOSE
)
44 _LoadSettings(settings
);
47 if (settings
.FindRect("window frame", &frame
) == B_OK
) {
48 MoveTo(frame
.LeftTop());
49 ResizeTo(frame
.Width(), frame
.Height());
51 float scaling
= be_plain_font
->Size() / 12.0f
;
52 ResizeTo(Frame().Width() * scaling
, Frame().Height() * scaling
);
57 BGroupLayout
* layout
= new BGroupLayout(B_VERTICAL
, 0);
62 BMenuBar
* menuBar
= new BMenuBar("menu");
63 layout
->AddView(menuBar
);
65 fLayout
= new BGroupLayout(B_VERTICAL
);
66 float inset
= ceilf(be_plain_font
->Size() * 0.7);
67 fLayout
->SetInsets(B_USE_WINDOW_SPACING
);
68 fLayout
->SetSpacing(inset
);
70 BView
* top
= new BView("top", 0, fLayout
);
72 top
->SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
76 for (int32 i
= 0; settings
.FindMessage("activity view", i
, &viewState
)
78 ActivityView
* view
= new ActivityView("ActivityMonitor", &viewState
);
79 fLayout
->AddItem(view
->CreateHistoryLayoutItem());
80 fLayout
->AddItem(view
->CreateLegendLayoutItem());
84 // Add default views (memory & CPU usage)
89 BView
*layout
= new BView(Bounds(), "topmost", B_FOLLOW_NONE
, 0);
93 BRect
mbRect(Bounds());
95 BMenuBar
* menuBar
= new BMenuBar(mbRect
, "menu");
96 layout
->AddChild(menuBar
);
98 BRect
topRect(Bounds());
99 topRect
.top
= menuBar
->Bounds().bottom
+ 1;
101 BView
* top
= new BView(topRect
, "top", B_FOLLOW_ALL
, 0);
102 layout
->AddChild(top
);
108 for (int32 i
= 0; settings
.FindMessage("activity view", i
, &viewState
)
110 aview
= new ActivityView("ActivityMonitor", &viewState
);
112 rect
= aview
->Bounds();
114 rect
.OffsetBySelf(0.0, aview
->Bounds().Height());
115 top
->AddChild(aview
);
119 top
->AddChild(new ActivityView("ActivityMonitor", NULL
));
125 BMenu
* menu
= new BMenu(B_TRANSLATE("File"));
126 menu
->AddItem(new BMenuItem(B_TRANSLATE("Add graph"),
127 new BMessage(kMsgAddView
)));
128 menu
->AddSeparatorItem();
130 menu
->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
131 new BMessage(B_QUIT_REQUESTED
), 'Q'));
132 menu
->SetTargetForItems(this);
133 menuBar
->AddItem(menu
);
136 menu
= new BMenu(B_TRANSLATE("Settings"));
137 menu
->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS
),
138 new BMessage(kMsgShowSettings
)));
140 menu
->AddSeparatorItem();
141 fAlwaysOnTop
= new BMenuItem(B_TRANSLATE("Always on top"), new BMessage(kMsgAlwaysOnTop
));
142 _SetAlwaysOnTop(settings
.GetBool("always on top", false));
143 menu
->AddItem(fAlwaysOnTop
);
145 menu
->SetTargetForItems(this);
146 menuBar
->AddItem(menu
);
150 ActivityWindow::~ActivityWindow()
156 ActivityWindow::MessageReceived(BMessage
* message
)
158 if (message
->WasDropped()) {
159 _MessageDropped(message
);
163 switch (message
->what
) {
164 case B_REFS_RECEIVED
:
166 _MessageDropped(message
);
172 BView
* firstView
= fLayout
->View()->ChildAt(0);
176 if (firstView
!= NULL
)
177 ResizeBy(0, firstView
->Bounds().Height() + fLayout
->Spacing());
186 if (message
->FindPointer("view", (void**)&view
) != B_OK
)
190 ResizeBy(0, -view
->Bounds().Height() - fLayout
->Spacing());
196 case kMsgShowSettings
:
198 if (fSettingsWindow
.IsValid()) {
199 // Just bring the window to front (via scripting)
200 BMessage
toFront(B_SET_PROPERTY
);
201 toFront
.AddSpecifier("Active");
202 toFront
.AddBool("data", true);
203 fSettingsWindow
.SendMessage(&toFront
);
205 // Open new settings window
206 BWindow
* window
= new SettingsWindow(this);
209 fSettingsWindow
= window
;
214 case kMsgAlwaysOnTop
:
216 _SetAlwaysOnTop(!fAlwaysOnTop
->IsMarked());
220 case kMsgTimeIntervalUpdated
:
221 BroadcastToActivityViews(message
);
225 BWindow::MessageReceived(message
);
232 ActivityWindow::QuitRequested()
235 be_app
->PostMessage(B_QUIT_REQUESTED
);
241 ActivityWindow::ActivityViewCount() const
244 return fLayout
->View()->CountChildren();
252 ActivityWindow::ActivityViewAt(int32 index
) const
254 return dynamic_cast<ActivityView
*>(fLayout
->View()->ChildAt(index
));
259 ActivityWindow::IsAlwaysOnTop() const
261 return fAlwaysOnTop
->IsMarked();
266 ActivityWindow::BroadcastToActivityViews(BMessage
* message
, BView
* exceptToView
)
269 for (int32 i
= 0; (view
= ActivityViewAt(i
)) != NULL
; i
++) {
270 if (view
!= exceptToView
)
271 PostMessage(message
, view
);
277 ActivityWindow::RefreshInterval() const
279 ActivityView
* view
= ActivityViewAt(0);
281 return view
->RefreshInterval();
288 ActivityWindow::_OpenSettings(BFile
& file
, uint32 mode
)
291 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) != B_OK
)
294 path
.Append("ActivityMonitor settings");
296 return file
.SetTo(path
.Path(), mode
);
301 ActivityWindow::_LoadSettings(BMessage
& settings
)
304 status_t status
= _OpenSettings(file
, B_READ_ONLY
);
308 return settings
.Unflatten(&file
);
313 ActivityWindow::_SaveSettings()
316 status_t status
= _OpenSettings(file
, B_WRITE_ONLY
| B_CREATE_FILE
321 BMessage
settings('actm');
322 status
= settings
.AddRect("window frame", Frame());
326 status
= settings
.SetBool("always on top", fAlwaysOnTop
->IsMarked());
331 BView
* top
= fLayout
->View();
333 BView
* top
= ChildAt(0);
335 int32 count
= top
->CountChildren();
336 for (int32 i
= 0; i
< count
; i
++) {
337 ActivityView
* view
= dynamic_cast<ActivityView
*>(top
->ChildAt(i
));
342 status
= view
->SaveState(viewState
);
344 status
= settings
.AddMessage("activity view", &viewState
);
350 status
= settings
.Flatten(&file
);
357 ActivityWindow::_AddDefaultView()
360 settings
.AddInt64("refresh interval", RefreshInterval());
362 ActivityView
* view
= new ActivityView("ActivityMonitor", &settings
);
364 switch (ActivityViewCount()) {
366 // The first view defaults to memory usage
367 view
->AddDataSource(new UsedMemoryDataSource());
368 view
->AddDataSource(new CachedMemoryDataSource());
371 // The third view defaults to network in/out
372 view
->AddDataSource(new NetworkUsageDataSource(true));
373 view
->AddDataSource(new NetworkUsageDataSource(false));
377 // Everything beyond that defaults to a CPU usage view
378 view
->AddDataSource(new CPUUsageDataSource());
382 fLayout
->AddItem(view
->CreateHistoryLayoutItem());
383 fLayout
->AddItem(view
->CreateLegendLayoutItem());
388 ActivityWindow::_MessageDropped(BMessage
* message
)
391 if (message
->FindRef("refs", &ref
) != B_OK
) {
392 // TODO: If app, then launch it, and add ActivityView for this one?
398 ActivityWindow::_SetAlwaysOnTop(bool alwaysOnTop
)
400 SetFeel(alwaysOnTop
? B_FLOATING_ALL_WINDOW_FEEL
: B_NORMAL_WINDOW_FEEL
);
401 fAlwaysOnTop
->SetMarked(alwaysOnTop
);
402 if (fSettingsWindow
.IsValid() && alwaysOnTop
) {
403 // Change the settings window feel to modal (via scripting)
404 BMessage
toFront(B_SET_PROPERTY
);
405 toFront
.AddSpecifier("Feel");
406 toFront
.AddInt32("data", B_MODAL_ALL_WINDOW_FEEL
);
407 fSettingsWindow
.SendMessage(&toFront
);