1//****************************************************************************************
2//
3//	File:		PulseView.cpp
4//
5//	Written by:	David Ramsey and Daniel Switkin
6//
7//	Copyright 1999, Be Incorporated
8//
9//****************************************************************************************
10
11#include "PulseView.h"
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16
17#include <Alert.h>
18#include <Catalog.h>
19
20#include <syscalls.h>
21
22#include "Common.h"
23#include "PulseApp.h"
24
25#undef B_TRANSLATION_CONTEXT
26#define B_TRANSLATION_CONTEXT "PulseView"
27
28
29PulseView::PulseView(BRect rect, const char *name)
30	:
31	BView(rect, name, B_FOLLOW_ALL_SIDES,
32		B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS),
33	kCPUCount(sysconf(_SC_NPROCESSORS_CONF)),
34	cpu_times(new double[kCPUCount]),
35	prev_active(new bigtime_t[kCPUCount])
36{
37
38	popupmenu = NULL;
39	cpu_menu_items = NULL;
40
41	// Don't init the menus for the DeskbarPulseView, because this instance
42	// will only be used to archive the replicant
43	if (strcmp(name, "DeskbarPulseView") != 0) {
44		Init();
45	}
46}
47
48// This version will be used by the instantiated replicant
49PulseView::PulseView(BMessage *message)
50	:
51	BView(message),
52	kCPUCount(sysconf(_SC_NPROCESSORS_CONF)),
53	cpu_times(new double[kCPUCount]),
54	prev_active(new bigtime_t[kCPUCount])
55{
56	SetResizingMode(B_FOLLOW_ALL_SIDES);
57	SetFlags(B_WILL_DRAW | B_PULSE_NEEDED);
58
59	popupmenu = NULL;
60	cpu_menu_items = NULL;
61	Init();
62}
63
64void PulseView::Init() {
65	memset(cpu_times, 0, sizeof(double) * kCPUCount);
66	memset(prev_active, 0, sizeof(double) * kCPUCount);
67
68	popupmenu = new BPopUpMenu("PopUpMenu", false, false, B_ITEMS_IN_COLUMN);
69	popupmenu->SetFont(be_plain_font);
70	mode1 = new BMenuItem("", NULL, 0, 0);
71	mode2 = new BMenuItem("", NULL, 0, 0);
72	preferences = new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS),
73		new BMessage(PV_PREFERENCES), 0, 0);
74	about = new BMenuItem(B_TRANSLATE("About Pulse" B_UTF8_ELLIPSIS),
75		new BMessage(PV_ABOUT), 0, 0);
76
77	popupmenu->AddItem(mode1);
78	popupmenu->AddItem(mode2);
79	popupmenu->AddSeparatorItem();
80
81	system_info sys_info;
82	get_system_info(&sys_info);
83
84	// Only add menu items to control CPUs on an SMP machine
85	if (sys_info.cpu_count >= 2) {
86		cpu_menu_items = new BMenuItem *[sys_info.cpu_count];
87		char temp[20];
88		for (unsigned int x = 0; x < sys_info.cpu_count; x++) {
89			sprintf(temp, "CPU %d", x + 1);
90			BMessage *message = new BMessage(PV_CPU_MENU_ITEM);
91			message->AddInt32("which", x);
92			cpu_menu_items[x] = new BMenuItem(temp, message, 0, 0);
93			popupmenu->AddItem(cpu_menu_items[x]);
94		}
95		popupmenu->AddSeparatorItem();
96	}
97
98	popupmenu->AddItem(preferences);
99	popupmenu->AddItem(about);
100}
101
102void PulseView::MouseDown(BPoint point) {
103	BPoint cursor;
104	uint32 buttons;
105	MakeFocus(true);
106	GetMouse(&cursor, &buttons, true);
107
108	if (buttons & B_SECONDARY_MOUSE_BUTTON) {
109		ConvertToScreen(&point);
110		// Use the asynchronous version so we don't interfere with
111		// the window responding to Pulse() events
112		popupmenu->Go(point, true, false, true);
113	}
114}
115
116void PulseView::Update() {
117	system_info sys_info;
118	get_system_info(&sys_info);
119	bigtime_t now = system_time();
120
121	cpu_info* cpuInfos = new cpu_info[sys_info.cpu_count];
122	get_cpu_info(0, sys_info.cpu_count, cpuInfos);
123
124	// Calculate work done since last call to Update() for each CPU
125	for (unsigned int x = 0; x < sys_info.cpu_count; x++) {
126		double cpu_time = (double)(cpuInfos[x].active_time - prev_active[x])
127				/ (now - prev_time);
128		prev_active[x] = cpuInfos[x].active_time;
129		if (cpu_time < 0) cpu_time = 0;
130		if (cpu_time > 1) cpu_time = 1;
131		cpu_times[x] = cpu_time;
132
133		if (sys_info.cpu_count >= 2) {
134			if (!_kern_cpu_enabled(x) && cpu_menu_items[x]->IsMarked())
135				cpu_menu_items[x]->SetMarked(false);
136			if (_kern_cpu_enabled(x) && !cpu_menu_items[x]->IsMarked())
137				cpu_menu_items[x]->SetMarked(true);
138		}
139	}
140	prev_time = now;
141
142	delete[] cpuInfos;
143}
144
145void PulseView::ChangeCPUState(BMessage *message) {
146	int which = message->FindInt32("which");
147
148	if (!LastEnabledCPU(which)) {
149		_kern_set_cpu_enabled(which, (int)!cpu_menu_items[which]->IsMarked());
150	} else {
151		BAlert *alert = new BAlert(B_TRANSLATE("Info"),
152			B_TRANSLATE("You can't disable the last active CPU."),
153			B_TRANSLATE("OK"));
154		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
155		alert->Go(NULL);
156	}
157}
158
159PulseView::~PulseView() {
160	if (popupmenu != NULL) delete popupmenu;
161	if (cpu_menu_items != NULL) delete[] cpu_menu_items;
162
163	delete[] prev_active;
164	delete[] cpu_times;
165}
166
167