xref: /haiku/src/apps/processcontroller/ProcessController.cpp (revision 1c09002cbee8e797a0f8bbfc5678dfadd39ee1a7)
1 /*
2 	ProcessController © 2000, Georges-Edouard Berenger, All Rights Reserved.
3 	Copyright (C) 2004 beunited.org
4 	Copyright (c) 2006-2009, Haiku, Inc. All rights reserved.
5 
6 	This library is free software; you can redistribute it and/or
7 	modify it under the terms of the GNU Lesser General Public
8 	License as published by the Free Software Foundation; either
9 	version 2.1 of the License, or (at your option) any later version.
10 
11 	This library is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 	Lesser General Public License for more details.
15 
16 	You should have received a copy of the GNU Lesser General Public
17 	License along with this library; if not, write to the Free Software
18 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 
22 #include "ProcessController.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <AboutWindow.h>
29 #include <Alert.h>
30 #include <Bitmap.h>
31 #include <Catalog.h>
32 #include <debugger.h>
33 #include <Deskbar.h>
34 #include <Directory.h>
35 #include <Dragger.h>
36 #include <File.h>
37 #include <FindDirectory.h>
38 #include <MessageRunner.h>
39 #include <Path.h>
40 #include <PopUpMenu.h>
41 #include <Roster.h>
42 #include <Screen.h>
43 #include <TextView.h>
44 
45 #include <syscalls.h>
46 
47 #include "AutoIcon.h"
48 #include "Colors.h"
49 #include "IconMenuItem.h"
50 #include "MemoryBarMenu.h"
51 #include "MemoryBarMenuItem.h"
52 #include "PCWorld.h"
53 #include "Preferences.h"
54 #include "QuitMenu.h"
55 #include "TeamBarMenu.h"
56 #include "TeamBarMenuItem.h"
57 #include "ThreadBarMenu.h"
58 #include "Utilities.h"
59 
60 
61 #undef B_TRANSLATE_CONTEXT
62 #define B_TRANSLATE_CONTEXT "ProcessController"
63 
64 
65 const char* kDeskbarItemName = "ProcessController";
66 const char* kClassName = "ProcessController";
67 
68 const char* kFrameColorPref = "deskbar_frame_color";
69 const char* kIdleColorPref = "deskbar_idle_color";
70 const char* kActiveColorPref = "deskbar_active_color";
71 
72 const rgb_color kKernelBlue = {20, 20, 231,	255};
73 const rgb_color kIdleGreen = {110, 190,110,	255};
74 
75 ProcessController* gPCView;
76 int32 gCPUcount;
77 rgb_color gUserColor;
78 rgb_color gUserColorSelected;
79 rgb_color gIdleColor;
80 rgb_color gIdleColorSelected;
81 rgb_color gKernelColor;
82 rgb_color gKernelColorSelected;
83 rgb_color gFrameColor;
84 rgb_color gFrameColorSelected;
85 rgb_color gMenuBackColorSelected;
86 rgb_color gMenuBackColor;
87 rgb_color gWhiteSelected;
88 ThreadBarMenu* gCurrentThreadBarMenu;
89 bool gInDeskbar = false;
90 
91 #define addtopbottom(x) if (top) popup->AddItem(x); else popup->AddItem(x, 0)
92 
93 long thread_popup(void *arg);
94 
95 int32			gPopupFlag = 0;
96 thread_id		gPopupThreadID = 0;
97 
98 typedef struct {
99 	BPoint		where;
100 	BRect		clickToOpenRect;
101 	bool		top;
102 } Tpopup_param;
103 
104 #define DEBUG_THREADS 1
105 
106 long thread_quit_application(void *arg);
107 long thread_debug_thread(void *arg);
108 
109 typedef struct {
110 	thread_id	thread;
111 	sem_id		sem;
112 	time_t		totalTime;
113 } Tdebug_thead_param;
114 
115 // Bar layout depending on number of CPUs
116 
117 typedef struct {
118 	float	cpu_width;
119 	float	cpu_inter;
120 	float	mem_width;
121 } layoutT;
122 
123 layoutT layout[] = {
124 	{ 1, 1, 1 },
125 	{ 5, 1, 5 },	// 1
126 	{ 3, 1, 4 },	// 2
127 	{ 1, 1, 1 },
128 	{ 2, 0, 3 },	// 4
129 	{ 1, 1, 1 },
130 	{ 1, 1, 1 },
131 	{ 1, 1, 1 },
132 	{ 1, 0, 3 }		// 8
133 };
134 
135 
136 extern "C" _EXPORT BView *instantiate_deskbar_item(void);
137 
138 extern "C" _EXPORT BView *
139 instantiate_deskbar_item(void)
140 {
141 	gInDeskbar = true;
142 	return new ProcessController();
143 }
144 
145 
146 //	#pragma mark -
147 
148 
149 ProcessController::ProcessController(BRect frame, bool temp)
150 	: BView(frame, kDeskbarItemName, B_FOLLOW_TOP_BOTTOM,
151 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
152 	fProcessControllerIcon(kSignature),
153 	fProcessorIcon(k_cpu_mini),
154 	fTrackerIcon(kTrackerSig),
155 	fDeskbarIcon(kDeskbarSig),
156 	fTerminalIcon(kTerminalSig),
157 	fTemp(temp)
158 {
159 	if (!temp) {
160 		Init();
161 
162 		frame.OffsetTo(B_ORIGIN);
163 		frame.top = frame.bottom - 7;
164 		frame.left = frame.right - 7;
165 		BDragger* dragger = new BDragger(frame, this, B_FOLLOW_BOTTOM);
166 		AddChild(dragger);
167 	}
168 }
169 
170 ProcessController::ProcessController(BMessage *data)
171 	: BView(data),
172 	fProcessControllerIcon(kSignature),
173 	fProcessorIcon(k_cpu_mini),
174 	fTrackerIcon(kTrackerSig),
175 	fDeskbarIcon(kDeskbarSig),
176 	fTerminalIcon(kTerminalSig),
177 	fTemp(false)
178 {
179 	Init();
180 }
181 
182 
183 ProcessController::ProcessController()
184 	: BView(BRect (0, 0, 15, 15), kDeskbarItemName, B_FOLLOW_NONE, B_WILL_DRAW),
185 	fProcessControllerIcon(kSignature),
186 	fProcessorIcon(k_cpu_mini),
187 	fTrackerIcon(kTrackerSig),
188 	fDeskbarIcon(kDeskbarSig),
189 	fTerminalIcon(kTerminalSig),
190 	fTemp(false)
191 {
192 	Init();
193 }
194 
195 
196 ProcessController::~ProcessController()
197 {
198 	if (!fTemp) {
199 		if (gPopupThreadID) {
200 			status_t return_value;
201 			wait_for_thread (gPopupThreadID, &return_value);
202 		}
203 	}
204 
205 	delete fMessageRunner;
206 	gPCView = NULL;
207 }
208 
209 
210 void
211 ProcessController::Init()
212 {
213 	gPCView = this;
214 	fMessageRunner = NULL;
215 	memset(fLastBarHeight, 0, sizeof(fLastBarHeight));
216 	fLastMemoryHeight = 0;
217 	memset(fCPUTimes, 0, sizeof(fCPUTimes));
218 	memset(fPrevActive, 0, sizeof(fPrevActive));
219 	fPrevTime = 0;
220 }
221 
222 
223 ProcessController *
224 ProcessController::Instantiate(BMessage *data)
225 {
226 	if (!validate_instantiation(data, kClassName))
227 		return NULL;
228 
229 	return new ProcessController(data);
230 }
231 
232 
233 status_t
234 ProcessController::Archive(BMessage *data, bool deep) const
235 {
236 	BView::Archive(data, deep);
237 	data->AddString("add_on", kSignature);
238 	data->AddString("class", kClassName);
239 	return B_OK;
240 }
241 
242 
243 void
244 ProcessController::MessageReceived(BMessage *message)
245 {
246 	team_id team;
247 	thread_id thread;
248 	BAlert *alert;
249 	char	question[1000];
250 	switch (message->what) {
251 		case 'Puls':
252 			Update ();
253 			DoDraw (false);
254 			break;
255 
256 		case 'QtTm':
257 			if (message->FindInt32("team", &team) == B_OK) {
258 				resume_thread(spawn_thread(thread_quit_application,
259 					B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY,
260 					(void*) team));
261 			}
262 			break;
263 
264 		case 'KlTm':
265 			if (message->FindInt32("team", &team) == B_OK) {
266 				info_pack infos;
267 				if (get_team_info(team, &infos.team_info) == B_OK) {
268 					get_team_name_and_icon(infos);
269 					snprintf(question, sizeof(question),
270 					B_TRANSLATE("Do you really want to kill the team \"%s\"?"),
271 					infos.team_name);
272 					alert = new BAlert(B_TRANSLATE("Please confirm"), question,
273 					B_TRANSLATE("Cancel"), B_TRANSLATE("Yes, kill this team!"),
274 					NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
275 					alert->SetShortcut(0, B_ESCAPE);
276 					if (alert->Go())
277 						kill_team(team);
278 				} else {
279 					alert = new BAlert(B_TRANSLATE("Info"),
280 						B_TRANSLATE("This team is already gone"B_UTF8_ELLIPSIS),
281 						B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL,
282 						B_STOP_ALERT);
283 					alert->SetShortcut(0, B_ESCAPE);
284 					alert->Go();
285 				}
286 			}
287 			break;
288 
289 		case 'KlTh':
290 			if (message->FindInt32("thread", &thread) == B_OK) {
291 				thread_info	thinfo;
292 				if (get_thread_info(thread, &thinfo) == B_OK) {
293 					#if DEBUG_THREADS
294 					snprintf(question, sizeof(question),
295 						B_TRANSLATE("What do you want to do "
296 						"with the thread \"%s\"?"), thinfo.name);
297 					alert = new BAlert(B_TRANSLATE("Please confirm"), question,
298 						B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"),
299 						B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL,
300 						B_STOP_ALERT);
301 					#define KILL 2
302 					#else
303 					snprintf(question, sizeof(question),
304 						B_TRANSLATE("Are you sure you want "
305 						"to kill the thread \"%s\"?"), thinfo.name);
306 					alert = new BAlert(B_TRANSLATE("Please confirm"), question,
307 						B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"),
308 						NULL, B_WIDTH_AS_USUAL,	B_STOP_ALERT);
309 					#define KILL 1
310 					#endif
311 					alert->SetShortcut(0, B_ESCAPE);
312 					int r = alert->Go();
313 					if (r == KILL)
314 						kill_thread(thread);
315 					#if DEBUG_THREADS
316 					else if (r == 1) {
317 						Tdebug_thead_param* param = new Tdebug_thead_param;
318 						param->thread = thread;
319 						if (thinfo.state == B_THREAD_WAITING)
320 							param->sem = thinfo.sem;
321 						else
322 							param->sem = -1;
323 						param->totalTime = thinfo.user_time+thinfo.kernel_time;
324 						resume_thread(spawn_thread(thread_debug_thread,
325 						B_TRANSLATE("Debug thread"), B_NORMAL_PRIORITY, param));
326 					}
327 					#endif
328 				} else {
329 					alert = new BAlert(B_TRANSLATE("Info"),
330 						B_TRANSLATE("This thread is already gone"B_UTF8_ELLIPSIS),
331 						B_TRANSLATE("Ok!"),	NULL, NULL,
332 						B_WIDTH_AS_USUAL, B_STOP_ALERT);
333 					alert->SetShortcut(0, B_ESCAPE);
334 					alert->Go();
335 				}
336 			}
337 			break;
338 
339 		case 'PrTh':
340 			if (message->FindInt32("thread", &thread) == B_OK) {
341 				long new_priority;
342 				if (message->FindInt32("priority", &new_priority) == B_OK)
343 					set_thread_priority(thread, new_priority);
344 			}
345 			break;
346 
347 		case 'Trac':
348 			launch(kTrackerSig, "/boot/system/Tracker");
349 			break;
350 
351 		case 'Dbar':
352 			launch(kDeskbarSig, "/boot/system/Deskbar");
353 			break;
354 
355 		case 'Term':
356 			launch(kTerminalSig, "/boot/system/apps/Terminal");
357 			break;
358 
359 		case 'AlDb':
360 		{
361 			if (!be_roster->IsRunning(kDeskbarSig))
362 				launch(kDeskbarSig, "/boot/system/Deskbar");
363 			BDeskbar deskbar;
364 			if (gInDeskbar || deskbar.HasItem (kDeskbarItemName))
365 				deskbar.RemoveItem (kDeskbarItemName);
366 			else
367 				move_to_deskbar(deskbar);
368 			break;
369 		}
370 
371 		case 'CPU ':
372 		{
373 			int32 cpu;
374 			if (message->FindInt32 ("cpu", &cpu) == B_OK) {
375 				bool last = true;
376 				for (int p = 0; p < gCPUcount; p++) {
377 					if (p != cpu && _kern_cpu_enabled(p)) {
378 						last = false;
379 						break;
380 					}
381 				}
382 				if (last) {
383 					alert = new BAlert(B_TRANSLATE("Info"),
384 						B_TRANSLATE("This is the last active processor...\n"
385 						"You can't turn it off!"),
386 						B_TRANSLATE("That's no Fun!"), NULL, NULL,
387 						B_WIDTH_AS_USUAL, B_WARNING_ALERT);
388 					alert->SetShortcut(0, B_ESCAPE);
389 					alert->Go();
390 				} else
391 					_kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu));
392 			}
393 			break;
394 		}
395 
396 		case B_ABOUT_REQUESTED:
397 			AboutRequested();
398 			break;
399 
400 		default:
401 			BView::MessageReceived(message);
402 	}
403 }
404 
405 
406 void
407 ProcessController::AboutRequested()
408 {
409 	const char* authors[] = {
410 		"Georges-Edouard Berenger",
411 		NULL
412 	};
413 
414 	BAboutWindow about(B_TRANSLATE_SYSTEM_NAME("ProcessController"), 2007, authors,
415 		"Copyright 1997-2001\n"
416 		"Georges-Edouard Berenger.");
417 	about.Show();
418 }
419 
420 
421 void
422 ProcessController::DefaultColors()
423 {
424 	swap_color.red = 203;
425 	swap_color.green = 0;
426 	swap_color.blue = 0;
427 	swap_color.alpha = 255;
428 	bool set = false;
429 
430 	if (!set) {
431 		active_color = kKernelBlue;
432 		active_color = tint_color (active_color, B_LIGHTEN_2_TINT);
433 		idle_color = active_color;
434 		idle_color.green /= 3;
435 		idle_color.red /= 3;
436 		idle_color.blue /= 3;
437 		frame_color = kBlack;
438 		mix_colors (memory_color, active_color, swap_color, 0.2);
439 	}
440 }
441 
442 
443 void
444 ProcessController::AttachedToWindow()
445 {
446 	BView::AttachedToWindow();
447 	if (Parent())
448 		SetViewColor(B_TRANSPARENT_COLOR);
449 	else
450 		SetViewColor(kBlack);
451 
452 	Preferences tPreferences(kPreferencesFileName, NULL, false);
453 	DefaultColors();
454 
455 	system_info info;
456 	get_system_info(&info);
457 	gCPUcount = info.cpu_count;
458 	Update();
459 
460 	gIdleColor = kIdleGreen;
461 	gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT);
462 	gKernelColor = kKernelBlue;
463 	gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT);
464 	gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT);
465 	gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT);
466 	gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
467 		B_HIGHLIGHT_BACKGROUND_TINT);
468 	gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT);
469 	gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR);
470 	gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR);
471 	gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT);
472 
473 	BMessenger messenger(this);
474 	BMessage message('Puls');
475 	fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1);
476 }
477 
478 
479 
480 void
481 ProcessController::MouseDown(BPoint where)
482 {
483 	if (atomic_add(&gPopupFlag, 1) > 0) {
484 		atomic_add(&gPopupFlag, -1);
485 		return;
486 	}
487 
488 	Tpopup_param* param = new Tpopup_param;
489 	ConvertToScreen(&where);
490 	param->where = where;
491 	param->clickToOpenRect = Frame ();
492 	ConvertToScreen (&param->clickToOpenRect);
493 	param->top = where.y < BScreen(this->Window()).Frame().bottom-50;
494 
495 	gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread",
496 		B_URGENT_DISPLAY_PRIORITY, param);
497 	resume_thread(gPopupThreadID);
498 }
499 
500 
501 void
502 ProcessController::Draw(BRect)
503 {
504 	SetDrawingMode(B_OP_COPY);
505 	DoDraw(true);
506 }
507 
508 
509 void
510 ProcessController::DoDraw(bool force)
511 {
512 	BRect bounds(Bounds());
513 
514 	float h = floorf(bounds.Height ()) - 2;
515 	float top = 1, left = 1;
516 	float bottom = top + h;
517 	float barWidth = layout[gCPUcount].cpu_width;
518 	// interspace
519 	float right = left + gCPUcount * (barWidth + layout[gCPUcount].cpu_inter)
520 		- layout[gCPUcount].cpu_inter; // right of CPU frame...
521 	if (force && Parent()) {
522 		SetHighColor(Parent()->ViewColor ());
523 		FillRect(BRect(right + 1, top - 1, right + 2, bottom + 1));
524 	}
525 
526 	if (force) {
527 		SetHighColor(frame_color);
528 		StrokeRect(BRect(left - 1, top - 1, right, bottom + 1));
529 		if (gCPUcount == 2) {
530 			StrokeLine(BPoint(left + barWidth, top), BPoint(left + barWidth,
531 				bottom));
532 		}
533 	}
534 	float leftMem = bounds.Width() - layout[gCPUcount].mem_width;
535 	if (force)
536 		StrokeRect(BRect(leftMem - 1, top - 1,
537 			leftMem + layout[gCPUcount].mem_width, bottom + 1));
538 
539 	for (int x = 0; x < gCPUcount; x++) {
540 		right = left + barWidth - 1;
541 		float rem = fCPUTimes[x] * (h + 1);
542 		float barHeight = floorf (rem);
543 		rem -= barHeight;
544 		float limit = bottom - barHeight;	// horizontal line
545 		float previousLimit = bottom - fLastBarHeight[x];
546 		float idleTop = top;
547 
548 		if (!force && previousLimit > top)
549 			idleTop = previousLimit - 1;
550 		if (limit > idleTop) {
551 			SetHighColor(idle_color);
552 			FillRect(BRect(left, idleTop, right, limit - 1));
553 		}
554 		if (barHeight <= h) {
555 			rgb_color fraction_color;
556 			mix_colors(fraction_color, idle_color, active_color, rem);
557 			SetHighColor(fraction_color);
558 			StrokeLine(BPoint(left, bottom - barHeight), BPoint(right,
559 				bottom - barHeight));
560 		}
561 		float active_bottom = bottom;
562 		if (!force && previousLimit < bottom)
563 			active_bottom = previousLimit + 1;
564 		if (limit < active_bottom) {
565 			SetHighColor(active_color);
566 			FillRect(BRect(left, limit + 1, right, active_bottom));
567 		}
568 		left += layout[gCPUcount].cpu_width + layout[gCPUcount].cpu_inter;
569 		fLastBarHeight[x] = barHeight;
570 	}
571 
572 	float rightMem = bounds.Width () - 1;
573 	float rem = fMemoryUsage * (h + 1);
574 	float barHeight = floorf (rem);
575 	rem -= barHeight;
576 
577 	rgb_color used_memory_color;
578 	float sq = fMemoryUsage * fMemoryUsage;
579 	sq *= sq;
580 	sq *= sq;
581 	mix_colors(used_memory_color, memory_color, swap_color, sq);
582 
583 	float limit = bottom - barHeight;	// horizontal line
584 	float previousLimit = bottom - fLastMemoryHeight;
585 	float free_top = top;
586 	if (!force && previousLimit > top)
587 		free_top = previousLimit - 1;
588 	if (limit > free_top) {
589 		SetHighColor (idle_color);
590 		FillRect(BRect(leftMem, free_top, rightMem, limit - 1));
591 	}
592 	if (barHeight <= h) {
593 		rgb_color fraction_color;
594 		mix_colors(fraction_color, idle_color, used_memory_color, rem);
595 		SetHighColor(fraction_color);
596 		StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem,
597 			bottom - barHeight));
598 	}
599 	float usedBottom = bottom;
600 //	if (!force && previousLimit < bottom)
601 //		usedBottom = previousLimit + 1;
602 	if (limit < usedBottom) {
603 		SetHighColor(used_memory_color);
604 		FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom));
605 	}
606 	fLastMemoryHeight = barHeight;
607 }
608 
609 
610 void
611 ProcessController::Update()
612 {
613 	system_info info;
614 	get_system_info(&info);
615 	bigtime_t now = system_time();
616 
617 	fMemoryUsage = float(info.used_pages) / float(info.max_pages);
618 	// Calculate work done since last call to Update() for each CPU
619 	for (int x = 0; x < gCPUcount; x++) {
620 		bigtime_t load = info.cpu_infos[x].active_time - fPrevActive[x];
621 		bigtime_t passed = now - fPrevTime;
622 		float cpuTime = float(load) / float(passed);
623 
624 		fPrevActive[x] = info.cpu_infos[x].active_time;
625 		if (load > passed)
626 			fPrevActive[x] -= load - passed; // save overload for next period...
627 		if (cpuTime < 0)
628 			cpuTime = 0;
629 		if (cpuTime > 1)
630 			cpuTime = 1;
631 		fCPUTimes[x] = cpuTime;
632 	}
633 	fPrevTime = now;
634 }
635 
636 
637 //	#pragma mark -
638 
639 
640 long
641 thread_popup(void *arg)
642 {
643 	Tpopup_param* param = (Tpopup_param*) arg;
644 	int32 mcookie, hcookie;
645 	long m, h;
646 	BMenuItem* item;
647 	bool top = param->top;
648 
649 	system_info systemInfo;
650 	get_system_info(&systemInfo);
651 	info_pack* infos = new info_pack[systemInfo.used_teams];
652 	// TODO: this doesn't necessarily get all teams
653 	for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) {
654 		infos[m].team_icon = NULL;
655 		infos[m].team_name[0] = 0;
656 		infos[m].thread_info = NULL;
657 		if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) {
658 			infos[m].thread_info = new thread_info[infos[m].team_info.thread_count];
659 			for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) {
660 				if (get_next_thread_info(infos[m].team_info.team, &hcookie,
661 						&infos[m].thread_info[h]) != B_OK)
662 					infos[m].thread_info[h].thread = -1;
663 			}
664 			get_team_name_and_icon(infos[m], true);
665 		} else {
666 			systemInfo.used_teams = m;
667 			infos[m].team_info.team = -1;
668 		}
669 	}
670 
671 	BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false);
672 	popup->SetFont(be_plain_font);
673 
674 	// Quit section
675 	BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"),
676 	infos, systemInfo.used_teams);
677 	QuitPopup->SetFont(be_plain_font);
678 	popup->AddItem(QuitPopup);
679 
680 	// Memory Usage section
681 	MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"),
682 	infos, systemInfo);
683 	int commitedMemory = int(systemInfo.used_pages * B_PAGE_SIZE / 1024);
684 	for (m = 0; m < systemInfo.used_teams; m++) {
685 		if (infos[m].team_info.team >= 0) {
686 			MemoryBarMenuItem* memoryItem =
687 				new MemoryBarMenuItem(infos[m].team_name,
688 					infos[m].team_info.team, infos[m].team_icon, false, NULL);
689 			MemoryPopup->AddItem(memoryItem);
690 			memoryItem->UpdateSituation(commitedMemory);
691 		}
692 	}
693 
694 	addtopbottom(MemoryPopup);
695 
696 	// CPU Load section
697 	TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU "
698 	"usage"), infos, systemInfo.used_teams);
699 	for (m = 0; m < systemInfo.used_teams; m++) {
700 		if (infos[m].team_info.team >= 0) {
701 			ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name,
702 				infos[m].team_info.team, infos[m].team_info.thread_count);
703 			BMessage* kill_team = new BMessage('KlTm');
704 			kill_team->AddInt32("team", infos[m].team_info.team);
705 			TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team,
706 				infos[m].team_info.team, infos[m].team_icon, false);
707 			item->SetTarget(gPCView);
708 			CPUPopup->AddItem(item);
709 		}
710 	}
711 
712 	addtopbottom(CPUPopup);
713 	addtopbottom(new BSeparatorItem());
714 
715 	// CPU on/off section
716 	if (gCPUcount > 1) {
717 		for (int i = 0; i < gCPUcount; i++) {
718 			char item_name[32];
719 			sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1);
720 			BMessage* m = new BMessage ('CPU ');
721 			m->AddInt32 ("cpu", i);
722 			item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m);
723 			if (_kern_cpu_enabled(i))
724 				item->SetMarked (true);
725 			item->SetTarget(gPCView);
726 			addtopbottom(item);
727 		}
728 		addtopbottom (new BSeparatorItem ());
729 	}
730 
731 	if (!be_roster->IsRunning(kTrackerSig)) {
732 		item = new IconMenuItem(gPCView->fTrackerIcon,
733 		B_TRANSLATE("Restart Tracker"), new BMessage('Trac'));
734 		item->SetTarget(gPCView);
735 		addtopbottom(item);
736 	}
737 	if (!be_roster->IsRunning(kDeskbarSig)) {
738 		item = new IconMenuItem(gPCView->fDeskbarIcon,
739 		B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar'));
740 		item->SetTarget(gPCView);
741 		addtopbottom(item);
742 	}
743 
744 	item = new IconMenuItem(gPCView->fTerminalIcon,
745 	B_TRANSLATE("New Terminal"), new BMessage('Term'));
746 	item->SetTarget(gPCView);
747 	addtopbottom(item);
748 
749 	addtopbottom(new BSeparatorItem());
750 
751 	if (be_roster->IsRunning(kDeskbarSig)) {
752 		item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"),
753 		new BMessage('AlDb'));
754 		BDeskbar deskbar;
755 		item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName));
756 		item->SetTarget(gPCView);
757 		addtopbottom(item);
758 		addtopbottom(new BSeparatorItem ());
759 	}
760 
761 	item = new IconMenuItem(gPCView->fProcessControllerIcon,
762 	B_TRANSLATE("About ProcessController"B_UTF8_ELLIPSIS),
763 		new BMessage(B_ABOUT_REQUESTED));
764 	item->SetTarget(gPCView);
765 	addtopbottom(item);
766 
767 	param->where.x -= 5;
768 	param->where.y -= 8;
769 	popup->Go(param->where, true, true, param->clickToOpenRect);
770 
771 	delete popup;
772 	for (m = 0; m < systemInfo.used_teams; m++) {
773 		if (infos[m].team_info.team >= 0) {
774 			delete[] infos[m].thread_info;
775 			delete infos[m].team_icon;
776 		}
777 	}
778 	delete[] infos;
779 	delete param;
780 	atomic_add (&gPopupFlag, -1);
781 	gPopupThreadID = 0;
782 
783 	return B_OK;
784 }
785 
786 
787 long
788 thread_quit_application(void *arg)
789 {
790 	BMessenger messenger(NULL, (team_id)arg);
791 	messenger.SendMessage(B_QUIT_REQUESTED);
792 	return B_OK;
793 }
794 
795 
796 long
797 thread_debug_thread(void *arg)
798 {
799 	Tdebug_thead_param*	param = (Tdebug_thead_param*) arg;
800 #ifdef __HAIKU__
801 	debug_thread(param->thread);
802 #else	// !__HAIKU__
803 	thread_info	thinfo;
804 	get_thread_info(param->thread, &thinfo);
805 	char text[4096];
806 	sprintf(text, "db %d", int(param->thread));
807 	system(text);
808 	if (param->sem >= 0 && thinfo.state == B_THREAD_WAITING && param->sem
809 			== thinfo.sem) {
810 		snooze(1000000);
811 		get_thread_info(param->thread, &thinfo);
812 		if (thinfo.state == B_THREAD_WAITING
813 			&& param->sem == thinfo.sem
814 			&& param->totalTime == thinfo.user_time + thinfo.kernel_time) {
815 			// the thread has been waiting for this semaphore since the before
816 			// the alert, not doing anything... Let's push it out of there!
817 			sem_info sinfo;
818 			thread_info thinfo;
819 			info_pack infos;
820 
821 			if (get_sem_info(param->sem, &sinfo) == B_OK
822 				&& get_thread_info(param->thread, &thinfo) == B_OK
823 				&& get_team_info(thinfo.team, &infos.team_info) == B_OK) {
824 				sprintf (text, "This thread is waiting for the "
825 					"semaphore called \"%s\". As long as it waits for this "
826 					"semaphore, you won't be able to debug that thread.\n",
827 						sinfo.name);
828 				if (sinfo.team == thinfo.team)
829 					strcat(text, "This semaphore belongs to the "
830 						"thread's team.\n\nShould I release this semaphore?\n");
831 				else {
832 					get_team_name_and_icon(infos);
833 					char moreText[1024];
834 					sprintf(moreText, "\nWARNING! This semaphore "
835 						"belongs to the team \"%s\"!\n\nShould I release this "
836 						"semaphore anyway?\n",
837 						infos.team_name);
838 					strcat(text, moreText);
839 				}
840 
841 				BAlert* alert = new BAlert("", text, "Cancel", "Release",
842 						NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
843 				alert->SetShortcut(0, B_ESCAPE);
844 				if (alert->Go()) {
845 					get_thread_info (param->thread, &thinfo);
846 					if (thinfo.state == B_THREAD_WAITING && param->sem
847 							== thinfo.sem
848 						&& param->totalTime == thinfo.user_time
849 							+ thinfo.kernel_time)
850 						release_sem(param->sem);
851 					else {
852 						alert = new BAlert("", "The semaphore wasn't released, "
853 							"because it wasn't necessary anymore!",
854 							"OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
855 						alert->Go();
856 					}
857 				}
858 			}
859 		}
860 	}
861 #endif	// !__HAIKU__
862 	delete param;
863 	return B_OK;
864 }
865