1/*
2 * Copyright 2000, Georges-Edouard Berenger. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "TeamBarMenu.h"
8#include "ThreadBarMenu.h"
9#include "TeamBarMenuItem.h"
10#include "NoiseBarMenuItem.h"
11#include "ProcessController.h"
12
13#include <Bitmap.h>
14#include <Roster.h>
15#include <Window.h>
16
17#include <stdlib.h>
18
19
20#define EXTRA 10
21
22
23TeamBarMenu::TeamBarMenu(const char* title, info_pack* infos, int32 teamCount)
24	: BMenu(title),
25	fTeamCount(teamCount+EXTRA),
26	fFirstShow(true)
27{
28	SetFlags(Flags() | B_PULSE_NEEDED);
29	fTeamList = (team_id*)malloc(sizeof(team_id) * fTeamCount);
30	int	k;
31	for (k = 0; k < teamCount; k++) {
32		fTeamList[k] = infos[k].team_info.team;
33	}
34	while (k < fTeamCount) {
35		fTeamList[k++] = -1;
36	}
37	fRecycleCount = EXTRA;
38	fRecycleList = (TRecycleItem*)malloc(sizeof(TRecycleItem) * fRecycleCount);
39	SetFont(be_plain_font);
40	gCurrentThreadBarMenu = NULL;
41	fLastTotalTime = system_time();
42	AddItem(new NoiseBarMenuItem());
43}
44
45
46TeamBarMenu::~TeamBarMenu()
47{
48	gCurrentThreadBarMenu = NULL;
49	free(fTeamList);
50	free(fRecycleList);
51}
52
53
54void
55TeamBarMenu::Draw(BRect updateRect)
56{
57	BMenu::Draw (updateRect);
58	if (fFirstShow) {
59		Pulse();
60		fFirstShow = false;
61	}
62}
63
64
65void
66TeamBarMenu::Pulse()
67{
68	Window()->BeginViewTransaction();
69
70	// create the list of items to remove, for their team is gone. Update the old teams.
71	int lastRecycle = 0;
72	int firstRecycle = 0;
73	int	k;
74	TeamBarMenuItem *item;
75	double total = 0;
76	for (k = 1; (item = (TeamBarMenuItem*)ItemAt(k)) != NULL; k++) {
77		item->BarUpdate();
78		if (item->fKernel < 0) {
79			if (lastRecycle == fRecycleCount) {
80				fRecycleCount += EXTRA;
81				fRecycleList = (TRecycleItem*)realloc(fRecycleList,
82					sizeof(TRecycleItem)*fRecycleCount);
83			}
84			fRecycleList[lastRecycle].index = k;
85			fRecycleList[lastRecycle++].item = item;
86		} else {
87			if (lastRecycle > 0) {
88				RemoveItems(fRecycleList[0].index, lastRecycle, true);
89				k -= lastRecycle;
90				lastRecycle = 0;
91			}
92			total += item->fUser + item->fKernel;
93		}
94	}
95
96	// Look new teams that have appeared. Create an item for them, or recycle from the list.
97	int32 cookie = 0;
98	info_pack infos;
99	item = NULL;
100	while (get_next_team_info(&cookie, &infos.team_info) == B_OK) {
101		int	j = 0;
102		while (j < fTeamCount && infos.team_info.team != fTeamList[j])
103			j++;
104		if (infos.team_info.team != fTeamList[j]) {
105			// new team
106			team_info info;
107			j = 0;
108			while (j < fTeamCount && fTeamList[j] != -1)
109				if (get_team_info(fTeamList[j], &info) != B_OK)
110					fTeamList[j] = -1;
111				else
112					j++;
113			if (j == fTeamCount) {
114				fTeamCount +=  10;
115				fTeamList = (team_id*)realloc(fTeamList, sizeof(team_id) * fTeamCount);
116			}
117			fTeamList[j] = infos.team_info.team;
118			if (!get_team_name_and_icon(infos, true)) {
119				// the team is already gone!
120				fTeamList[j] = -1;
121			} else {
122				if (!item && firstRecycle < lastRecycle) {
123					item = fRecycleList[firstRecycle++].item;
124				}
125				if (item) {
126					item->Reset(infos.team_name, infos.team_info.team, infos.team_icon, true);
127				} else {
128					BMessage* kill_team = new BMessage('KlTm');
129					kill_team->AddInt32("team", infos.team_info.team);
130					item = new TeamBarMenuItem(new ThreadBarMenu(infos.team_name,
131						infos.team_info.team, infos.team_info.thread_count),
132						kill_team, infos.team_info.team, infos.team_icon, true);
133					item->SetTarget(gPCView);
134					AddItem(item);
135					item->BarUpdate();
136				}
137				if (item->fKernel >= 0) {
138					total += item->fUser + item->fKernel;
139					item = NULL;
140				} else {
141					fTeamList[j] = -1;
142				}
143			}
144		}
145	}
146	if (item) {
147		RemoveItem(item);
148		delete item;
149	}
150
151	// Delete the items that haven't been recycled.
152	if (firstRecycle < lastRecycle)
153		RemoveItems(IndexOf(fRecycleList[firstRecycle].item), lastRecycle - firstRecycle, true);
154
155	total /= gCPUcount;
156	total = 1 - total;
157
158	fLastTotalTime = system_time();
159	NoiseBarMenuItem* noiseItem;
160	if ((noiseItem = (NoiseBarMenuItem*)ItemAt(0)) != NULL) {
161		noiseItem->SetBusyWaiting(0);
162		if (total >= 0)
163			noiseItem->SetLost(total);
164		else
165			noiseItem->SetLost(0);
166		noiseItem->DrawBar(false);
167	}
168
169	if (gCurrentThreadBarMenu && gCurrentThreadBarMenu->LockLooperWithTimeout(25000) == B_OK) {
170		gCurrentThreadBarMenu->Window()->BeginViewTransaction();
171		gCurrentThreadBarMenu->Update();
172		gCurrentThreadBarMenu->Window()->EndViewTransaction();
173		gCurrentThreadBarMenu->Window()->Flush();
174		gCurrentThreadBarMenu->UnlockLooper();
175	}
176
177	Window()->EndViewTransaction();
178	Window()->Flush();
179}
180