1/*
2	ProcessController © 2000, Georges-Edouard Berenger, All Rights Reserved.
3	Copyright (C) 2004 beunited.org
4
5	This library is free software; you can redistribute it and/or
6	modify it under the terms of the GNU Lesser General Public
7	License as published by the Free Software Foundation; either
8	version 2.1 of the License, or (at your option) any later version.
9
10	This library is distributed in the hope that it will be useful,
11	but WITHOUT ANY WARRANTY; without even the implied warranty of
12	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13	Lesser General Public License for more details.
14
15	You should have received a copy of the GNU Lesser General Public
16	License along with this library; if not, write to the Free Software
17	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18*/
19
20
21#include "TeamBarMenu.h"
22#include "ThreadBarMenu.h"
23#include "TeamBarMenuItem.h"
24#include "NoiseBarMenuItem.h"
25#include "ProcessController.h"
26
27#include <Bitmap.h>
28#include <Roster.h>
29#include <Window.h>
30
31#include <stdlib.h>
32
33
34#define EXTRA 10
35
36
37TeamBarMenu::TeamBarMenu(const char* title, info_pack* infos, int32 teamCount)
38	: BMenu(title),
39	fTeamCount(teamCount+EXTRA),
40	fFirstShow(true)
41{
42	SetFlags(Flags() | B_PULSE_NEEDED);
43	fTeamList = (team_id*)malloc(sizeof(team_id) * fTeamCount);
44	int	k;
45	for (k = 0; k < teamCount; k++) {
46		fTeamList[k] = infos[k].team_info.team;
47	}
48	while (k < fTeamCount) {
49		fTeamList[k++] = -1;
50	}
51	fRecycleCount = EXTRA;
52	fRecycleList = (TRecycleItem*)malloc(sizeof(TRecycleItem) * fRecycleCount);
53	SetFont(be_plain_font);
54	gCurrentThreadBarMenu = NULL;
55	fLastTotalTime = system_time();
56	AddItem(new NoiseBarMenuItem());
57}
58
59
60TeamBarMenu::~TeamBarMenu()
61{
62	gCurrentThreadBarMenu = NULL;
63	free(fTeamList);
64	free(fRecycleList);
65}
66
67
68void
69TeamBarMenu::Draw(BRect updateRect)
70{
71	BMenu::Draw (updateRect);
72	if (fFirstShow) {
73		Pulse();
74		fFirstShow = false;
75	}
76}
77
78
79void
80TeamBarMenu::Pulse()
81{
82	Window()->BeginViewTransaction();
83
84	// create the list of items to remove, for their team is gone. Update the old teams.
85	int lastRecycle = 0;
86	int firstRecycle = 0;
87	int	k;
88	TeamBarMenuItem *item;
89	double total = 0;
90	for (k = 1; (item = (TeamBarMenuItem*)ItemAt(k)) != NULL; k++) {
91		item->BarUpdate();
92		if (item->fKernel < 0) {
93			if (lastRecycle == fRecycleCount) {
94				fRecycleCount += EXTRA;
95				fRecycleList = (TRecycleItem*)realloc(fRecycleList,
96					sizeof(TRecycleItem)*fRecycleCount);
97			}
98			fRecycleList[lastRecycle].index = k;
99			fRecycleList[lastRecycle++].item = item;
100		} else {
101			if (lastRecycle > 0) {
102				RemoveItems(fRecycleList[0].index, lastRecycle, true);
103				k -= lastRecycle;
104				lastRecycle = 0;
105			}
106			total += item->fUser + item->fKernel;
107		}
108	}
109
110	// Look new teams that have appeared. Create an item for them, or recycle from the list.
111	int32 cookie = 0;
112	info_pack infos;
113	item = NULL;
114	while (get_next_team_info(&cookie, &infos.team_info) == B_OK) {
115		int	j = 0;
116		while (j < fTeamCount && infos.team_info.team != fTeamList[j])
117			j++;
118		if (infos.team_info.team != fTeamList[j]) {
119			// new team
120			team_info info;
121			j = 0;
122			while (j < fTeamCount && fTeamList[j] != -1)
123				if (get_team_info(fTeamList[j], &info) != B_OK)
124					fTeamList[j] = -1;
125				else
126					j++;
127			if (j == fTeamCount) {
128				fTeamCount +=  10;
129				fTeamList = (team_id*)realloc(fTeamList, sizeof(team_id) * fTeamCount);
130			}
131			fTeamList[j] = infos.team_info.team;
132			if (!get_team_name_and_icon(infos, true)) {
133				// the team is already gone!
134				delete infos.team_icon;
135				fTeamList[j] = -1;
136			} else {
137				if (!item && firstRecycle < lastRecycle) {
138					item = fRecycleList[firstRecycle++].item;
139				}
140				if (item) {
141					item->Reset(infos.team_name, infos.team_info.team, infos.team_icon, true);
142				} else {
143					BMessage* kill_team = new BMessage('KlTm');
144					kill_team->AddInt32("team", infos.team_info.team);
145					item = new TeamBarMenuItem(new ThreadBarMenu(infos.team_name,
146						infos.team_info.team, infos.team_info.thread_count),
147						kill_team, infos.team_info.team, infos.team_icon, true);
148					item->SetTarget(gPCView);
149					AddItem(item);
150					item->BarUpdate();
151				}
152				if (item->fKernel >= 0) {
153					total += item->fUser + item->fKernel;
154					item = NULL;
155				} else {
156					fTeamList[j] = -1;
157				}
158			}
159		}
160	}
161	if (item) {
162		RemoveItem(item);
163		delete item;
164	}
165
166	// Delete the items that haven't been recycled.
167	if (firstRecycle < lastRecycle)
168		RemoveItems(IndexOf(fRecycleList[firstRecycle].item), lastRecycle - firstRecycle, true);
169
170	total /= gCPUcount;
171	total = 1 - total;
172
173	fLastTotalTime = system_time();
174	NoiseBarMenuItem* noiseItem;
175	if ((noiseItem = (NoiseBarMenuItem*)ItemAt(0)) != NULL) {
176		noiseItem->SetBusyWaiting(0);
177		if (total >= 0)
178			noiseItem->SetLost(total);
179		else
180			noiseItem->SetLost(0);
181		noiseItem->DrawBar(false);
182	}
183
184	if (gCurrentThreadBarMenu && gCurrentThreadBarMenu->LockLooperWithTimeout(25000) == B_OK) {
185		gCurrentThreadBarMenu->Window()->BeginViewTransaction();
186		gCurrentThreadBarMenu->Update();
187		gCurrentThreadBarMenu->Window()->EndViewTransaction();
188		gCurrentThreadBarMenu->Window()->Flush();
189		gCurrentThreadBarMenu->UnlockLooper();
190	}
191
192	Window()->EndViewTransaction();
193	Window()->Flush();
194}
195