repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / processcontroller / ProcessController.cpp
blob22ecdadba2e1e94bcffcc14536672fae24ed9b29
1 /*
2 ProcessController © 2000, Georges-Edouard Berenger, All Rights Reserved.
3 Copyright (C) 2004 beunited.org
4 Copyright (c) 2006-2015, Haiku, Inc. All rights reserved.
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.
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.
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
22 #include "ProcessController.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
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>
45 #include <scheduler.h>
46 #include <syscalls.h>
48 #include "AutoIcon.h"
49 #include "Colors.h"
50 #include "IconMenuItem.h"
51 #include "MemoryBarMenu.h"
52 #include "MemoryBarMenuItem.h"
53 #include "PCWorld.h"
54 #include "Preferences.h"
55 #include "QuitMenu.h"
56 #include "TeamBarMenu.h"
57 #include "TeamBarMenuItem.h"
58 #include "ThreadBarMenu.h"
59 #include "Utilities.h"
62 #undef B_TRANSLATION_CONTEXT
63 #define B_TRANSLATION_CONTEXT "ProcessController"
66 const char* kDeskbarItemName = "ProcessController";
67 const char* kClassName = "ProcessController";
69 const char* kFrameColorPref = "deskbar_frame_color";
70 const char* kIdleColorPref = "deskbar_idle_color";
71 const char* kActiveColorPref = "deskbar_active_color";
73 static const char* const kDebuggerSignature
74 = "application/x-vnd.Haiku-Debugger";
76 const rgb_color kKernelBlue = {20, 20, 231, 255};
77 const rgb_color kIdleGreen = {110, 190,110, 255};
79 ProcessController* gPCView;
80 uint32 gCPUcount;
81 rgb_color gUserColor;
82 rgb_color gUserColorSelected;
83 rgb_color gIdleColor;
84 rgb_color gIdleColorSelected;
85 rgb_color gKernelColor;
86 rgb_color gKernelColorSelected;
87 rgb_color gFrameColor;
88 rgb_color gFrameColorSelected;
89 rgb_color gMenuBackColorSelected;
90 rgb_color gMenuBackColor;
91 rgb_color gWhiteSelected;
92 ThreadBarMenu* gCurrentThreadBarMenu;
93 bool gInDeskbar = false;
95 #define addtopbottom(x) if (top) popup->AddItem(x); else popup->AddItem(x, 0)
97 status_t thread_popup(void *arg);
99 int32 gPopupFlag = 0;
100 thread_id gPopupThreadID = 0;
102 typedef struct {
103 BPoint where;
104 BRect clickToOpenRect;
105 bool top;
106 } Tpopup_param;
108 #define DEBUG_THREADS 1
110 status_t thread_quit_application(void *arg);
111 status_t thread_debug_thread(void *arg);
113 typedef struct {
114 thread_id thread;
115 sem_id sem;
116 time_t totalTime;
117 } Tdebug_thead_param;
119 // Bar layout depending on number of CPUs
121 typedef struct {
122 float cpu_width;
123 float cpu_inter;
124 float mem_width;
125 } layoutT;
127 layoutT layout[] = {
128 { 1, 1, 1 },
129 { 5, 1, 5 }, // 1
130 { 3, 1, 4 }, // 2
131 { 2, 1, 3 },
132 { 2, 0, 3 }, // 4
133 { 1, 1, 1 },
134 { 1, 1, 1 },
135 { 1, 1, 1 },
136 { 1, 0, 3 } // 8
140 extern "C" _EXPORT BView *instantiate_deskbar_item(void);
142 extern "C" _EXPORT BView *
143 instantiate_deskbar_item(void)
145 gInDeskbar = true;
146 return new ProcessController();
150 // #pragma mark -
153 ProcessController::ProcessController(BRect frame, bool temp)
154 : BView(frame, kDeskbarItemName, B_FOLLOW_TOP_BOTTOM,
155 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
156 fProcessControllerIcon(kSignature),
157 fProcessorIcon(k_cpu_mini),
158 fTrackerIcon(kTrackerSig),
159 fDeskbarIcon(kDeskbarSig),
160 fTerminalIcon(kTerminalSig),
161 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)),
162 fTemp(temp),
163 fLastBarHeight(new float[kCPUCount]),
164 fCPUTimes(new double[kCPUCount]),
165 fPrevActive(new bigtime_t[kCPUCount])
167 if (!temp) {
168 Init();
170 frame.OffsetTo(B_ORIGIN);
171 frame.top = frame.bottom - 7;
172 frame.left = frame.right - 7;
173 BDragger* dragger = new BDragger(frame, this, B_FOLLOW_BOTTOM);
174 AddChild(dragger);
178 ProcessController::ProcessController(BMessage *data)
179 : BView(data),
180 fProcessControllerIcon(kSignature),
181 fProcessorIcon(k_cpu_mini),
182 fTrackerIcon(kTrackerSig),
183 fDeskbarIcon(kDeskbarSig),
184 fTerminalIcon(kTerminalSig),
185 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)),
186 fTemp(false),
187 fLastBarHeight(new float[kCPUCount]),
188 fCPUTimes(new double[kCPUCount]),
189 fPrevActive(new bigtime_t[kCPUCount])
191 Init();
195 ProcessController::ProcessController()
196 : BView(BRect (0, 0, 15, 15), kDeskbarItemName, B_FOLLOW_NONE, B_WILL_DRAW),
197 fProcessControllerIcon(kSignature),
198 fProcessorIcon(k_cpu_mini),
199 fTrackerIcon(kTrackerSig),
200 fDeskbarIcon(kDeskbarSig),
201 fTerminalIcon(kTerminalSig),
202 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)),
203 fTemp(false),
204 fLastBarHeight(new float[kCPUCount]),
205 fCPUTimes(new double[kCPUCount]),
206 fPrevActive(new bigtime_t[kCPUCount])
208 Init();
212 ProcessController::~ProcessController()
214 if (!fTemp) {
215 if (gPopupThreadID) {
216 status_t return_value;
217 wait_for_thread (gPopupThreadID, &return_value);
221 delete fMessageRunner;
222 gPCView = NULL;
224 delete[] fPrevActive;
225 delete[] fCPUTimes;
226 delete[] fLastBarHeight;
230 void
231 ProcessController::Init()
233 memset(fLastBarHeight, 0, sizeof(float) * kCPUCount);
234 memset(fCPUTimes, 0, sizeof(double) * kCPUCount);
235 memset(fPrevActive, 0, sizeof(bigtime_t) * kCPUCount);
237 gPCView = this;
238 fMessageRunner = NULL;
239 fLastMemoryHeight = 0;
240 fPrevTime = 0;
244 void
245 ProcessController::_HandleDebugRequest(team_id team, thread_id thread)
247 char paramString[16];
248 char idString[16];
249 strlcpy(paramString, thread > 0 ? "--thread" : "--team",
250 sizeof(paramString));
251 snprintf(idString, sizeof(idString), "%" B_PRId32,
252 thread > 0 ? thread : team);
254 const char* argv[] = {paramString, idString, NULL};
255 status_t error = be_roster->Launch(kDebuggerSignature, 2, argv);
256 if (error != B_OK) {
257 // TODO: notify user
262 ProcessController*
263 ProcessController::Instantiate(BMessage *data)
265 if (!validate_instantiation(data, kClassName))
266 return NULL;
268 return new ProcessController(data);
272 status_t
273 ProcessController::Archive(BMessage *data, bool deep) const
275 BView::Archive(data, deep);
276 data->AddString("add_on", kSignature);
277 data->AddString("class", kClassName);
278 return B_OK;
282 void
283 ProcessController::MessageReceived(BMessage *message)
285 team_id team;
286 thread_id thread;
287 BAlert *alert;
288 char question[1000];
289 switch (message->what) {
290 case 'Puls':
291 Update ();
292 DoDraw (false);
293 break;
295 case 'QtTm':
296 if (message->FindInt32("team", &team) == B_OK) {
297 resume_thread(spawn_thread(thread_quit_application,
298 B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY,
299 (void*)(addr_t)team));
301 break;
303 case 'KlTm':
304 if (message->FindInt32("team", &team) == B_OK) {
305 info_pack infos;
306 if (get_team_info(team, &infos.team_info) == B_OK) {
307 get_team_name_and_icon(infos);
308 snprintf(question, sizeof(question),
309 B_TRANSLATE("What do you want to do with the team \"%s\"?"),
310 infos.team_name);
311 alert = new BAlert(B_TRANSLATE("Please confirm"), question,
312 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this team!"),
313 B_TRANSLATE("Kill this team!"), B_WIDTH_AS_USUAL,
314 B_STOP_ALERT);
315 alert->SetShortcut(0, B_ESCAPE);
316 int result = alert->Go();
317 switch (result) {
318 case 1:
319 _HandleDebugRequest(team, -1);
320 break;
321 case 2:
322 kill_team(team);
323 break;
324 default:
325 break;
327 } else {
328 alert = new BAlert(B_TRANSLATE("Info"),
329 B_TRANSLATE("This team is already gone" B_UTF8_ELLIPSIS),
330 B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL,
331 B_STOP_ALERT);
332 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
333 alert->Go();
336 break;
338 case 'KlTh':
339 if (message->FindInt32("thread", &thread) == B_OK) {
340 thread_info thinfo;
341 if (get_thread_info(thread, &thinfo) == B_OK) {
342 #if DEBUG_THREADS
343 snprintf(question, sizeof(question),
344 B_TRANSLATE("What do you want to do "
345 "with the thread \"%s\"?"), thinfo.name);
346 alert = new BAlert(B_TRANSLATE("Please confirm"), question,
347 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"),
348 B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL,
349 B_STOP_ALERT);
350 alert->SetShortcut(0, B_ESCAPE);
352 #define KILL 2
353 #else
354 snprintf(question, sizeof(question),
355 B_TRANSLATE("Are you sure you want "
356 "to kill the thread \"%s\"?"), thinfo.name);
357 alert = new BAlert(B_TRANSLATE("Please confirm"), question,
358 B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"),
359 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
360 alert->SetShortcut(0, B_ESCAPE);
362 #define KILL 1
363 #endif
364 alert->SetShortcut(0, B_ESCAPE);
365 int r = alert->Go();
366 if (r == KILL)
367 kill_thread(thread);
368 #if DEBUG_THREADS
369 else if (r == 1)
370 _HandleDebugRequest(thinfo.team, thinfo.thread);
371 #endif
372 } else {
373 alert = new BAlert(B_TRANSLATE("Info"),
374 B_TRANSLATE("This thread is already gone" B_UTF8_ELLIPSIS),
375 B_TRANSLATE("Ok!"), NULL, NULL,
376 B_WIDTH_AS_USUAL, B_STOP_ALERT);
377 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
378 alert->Go();
381 break;
383 case 'PrTh':
384 if (message->FindInt32("thread", &thread) == B_OK) {
385 int32 new_priority;
386 if (message->FindInt32("priority", &new_priority) == B_OK)
387 set_thread_priority(thread, new_priority);
389 break;
391 case 'Trac':
393 BPath trackerPath;
394 if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK
395 && trackerPath.Append("Tracker") == B_OK) {
396 launch(kTrackerSig, trackerPath.Path());
398 break;
401 case 'Dbar':
403 BPath deskbarPath;
404 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK
405 && deskbarPath.Append("Deskbar") == B_OK) {
406 launch(kDeskbarSig, deskbarPath.Path());
408 break;
411 case 'Term':
413 BPath terminalPath;
414 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK
415 && terminalPath.Append("Terminal") == B_OK) {
416 launch(kTerminalSig, terminalPath.Path());
418 break;
421 case 'AlDb':
423 if (!be_roster->IsRunning(kDeskbarSig)) {
424 BPath deskbarPath;
425 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK
426 && deskbarPath.Append("Deskbar") == B_OK) {
427 launch(kDeskbarSig, deskbarPath.Path());
430 BDeskbar deskbar;
431 if (gInDeskbar || deskbar.HasItem (kDeskbarItemName))
432 deskbar.RemoveItem (kDeskbarItemName);
433 else
434 move_to_deskbar(deskbar);
435 break;
438 case 'CPU ':
440 uint32 cpu;
441 if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) {
442 bool last = true;
443 for (unsigned int p = 0; p < gCPUcount; p++) {
444 if (p != cpu && _kern_cpu_enabled(p)) {
445 last = false;
446 break;
449 if (last) {
450 alert = new BAlert(B_TRANSLATE("Info"),
451 B_TRANSLATE("This is the last active processor...\n"
452 "You can't turn it off!"),
453 B_TRANSLATE("That's no Fun!"), NULL, NULL,
454 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
455 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
456 alert->Go();
457 } else
458 _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu));
460 break;
463 case 'Schd':
465 int32 mode;
466 if (message->FindInt32 ("mode", &mode) == B_OK)
467 set_scheduler_mode(mode);
468 break;
471 case B_ABOUT_REQUESTED:
472 AboutRequested();
473 break;
475 default:
476 BView::MessageReceived(message);
481 void
482 ProcessController::AboutRequested()
484 BAboutWindow* window = new BAboutWindow(
485 B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature);
487 const char* extraCopyrights[] = {
488 "2004 beunited.org",
489 "1997-2001 Georges-Edouard Berenger",
490 NULL
493 const char* authors[] = {
494 "Georges-Edouard Berenger",
495 NULL
498 window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights);
499 window->AddAuthors(authors);
501 window->Show();
505 void
506 ProcessController::DefaultColors()
508 swap_color.red = 203;
509 swap_color.green = 0;
510 swap_color.blue = 0;
511 swap_color.alpha = 255;
512 bool set = false;
514 if (!set) {
515 active_color = kKernelBlue;
516 active_color = tint_color (active_color, B_LIGHTEN_2_TINT);
517 idle_color = active_color;
518 idle_color.green /= 3;
519 idle_color.red /= 3;
520 idle_color.blue /= 3;
521 frame_color = kBlack;
522 mix_colors (memory_color, active_color, swap_color, 0.2);
527 void
528 ProcessController::AttachedToWindow()
530 BView::AttachedToWindow();
531 if (Parent())
532 SetViewColor(B_TRANSPARENT_COLOR);
533 else
534 SetViewColor(kBlack);
536 Preferences tPreferences(kPreferencesFileName, NULL, false);
537 DefaultColors();
539 system_info info;
540 get_system_info(&info);
541 gCPUcount = info.cpu_count;
542 Update();
544 gIdleColor = kIdleGreen;
545 gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT);
546 gKernelColor = kKernelBlue;
547 gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT);
548 gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT);
549 gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT);
550 gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
551 B_HIGHLIGHT_BACKGROUND_TINT);
552 gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT);
553 gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR);
554 gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR);
555 gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT);
557 BMessenger messenger(this);
558 BMessage message('Puls');
559 fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1);
564 void
565 ProcessController::MouseDown(BPoint where)
567 if (atomic_add(&gPopupFlag, 1) > 0) {
568 atomic_add(&gPopupFlag, -1);
569 return;
572 Tpopup_param* param = new Tpopup_param;
573 ConvertToScreen(&where);
574 param->where = where;
575 param->clickToOpenRect = Frame ();
576 ConvertToScreen (&param->clickToOpenRect);
577 param->top = where.y < BScreen(this->Window()).Frame().bottom-50;
579 gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread",
580 B_URGENT_DISPLAY_PRIORITY, param);
581 resume_thread(gPopupThreadID);
585 void
586 ProcessController::Draw(BRect)
588 SetDrawingMode(B_OP_COPY);
589 DoDraw(true);
593 void
594 ProcessController::DoDraw(bool force)
596 BRect bounds(Bounds());
598 float h = floorf(bounds.Height ()) - 2;
599 float top = 1, left = 1;
600 float bottom = top + h;
601 float barWidth = layout[gCPUcount].cpu_width;
602 // interspace
603 float right = left + gCPUcount * (barWidth + layout[gCPUcount].cpu_inter)
604 - layout[gCPUcount].cpu_inter; // right of CPU frame...
605 if (force && Parent()) {
606 SetHighColor(Parent()->ViewColor());
607 FillRect(BRect(right + 1, top - 1, right + 2, bottom + 1));
610 if (force) {
611 SetHighColor(frame_color);
612 StrokeRect(BRect(left - 1, top - 1, right, bottom + 1));
613 if (gCPUcount > 1 && layout[gCPUcount].cpu_inter == 1) {
614 for (unsigned int x = 1; x < gCPUcount; x++)
615 StrokeLine(BPoint(left + x * barWidth + x - 1, top),
616 BPoint(left + x * barWidth + x - 1, bottom));
619 float leftMem = bounds.Width() - layout[gCPUcount].mem_width;
620 if (force)
621 StrokeRect(BRect(leftMem - 1, top - 1,
622 leftMem + layout[gCPUcount].mem_width, bottom + 1));
624 for (unsigned int x = 0; x < gCPUcount; x++) {
625 right = left + barWidth - 1;
626 float rem = fCPUTimes[x] * (h + 1);
627 float barHeight = floorf (rem);
628 rem -= barHeight;
629 float limit = bottom - barHeight; // horizontal line
630 float previousLimit = bottom - fLastBarHeight[x];
631 float idleTop = top;
633 if (!force && previousLimit > top)
634 idleTop = previousLimit - 1;
635 if (limit > idleTop) {
636 SetHighColor(idle_color);
637 FillRect(BRect(left, idleTop, right, limit - 1));
639 if (barHeight <= h) {
640 rgb_color fraction_color;
641 mix_colors(fraction_color, idle_color, active_color, rem);
642 SetHighColor(fraction_color);
643 StrokeLine(BPoint(left, bottom - barHeight), BPoint(right,
644 bottom - barHeight));
646 float active_bottom = bottom;
647 if (!force && previousLimit < bottom)
648 active_bottom = previousLimit + 1;
649 if (limit < active_bottom) {
650 SetHighColor(active_color);
651 FillRect(BRect(left, limit + 1, right, active_bottom));
653 left += layout[gCPUcount].cpu_width + layout[gCPUcount].cpu_inter;
654 fLastBarHeight[x] = barHeight;
657 float rightMem = bounds.Width() - 1;
658 float rem = fMemoryUsage * (h + 1);
659 float barHeight = floorf(rem);
660 rem -= barHeight;
662 rgb_color used_memory_color;
663 float sq = fMemoryUsage * fMemoryUsage;
664 sq *= sq;
665 sq *= sq;
666 mix_colors(used_memory_color, memory_color, swap_color, sq);
668 float limit = bottom - barHeight; // horizontal line
669 float previousLimit = bottom - fLastMemoryHeight;
670 float free_top = top;
671 if (!force && previousLimit > top)
672 free_top = previousLimit - 1;
673 if (limit > free_top) {
674 SetHighColor (idle_color);
675 FillRect(BRect(leftMem, free_top, rightMem, limit - 1));
677 if (barHeight <= h) {
678 rgb_color fraction_color;
679 mix_colors(fraction_color, idle_color, used_memory_color, rem);
680 SetHighColor(fraction_color);
681 StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem,
682 bottom - barHeight));
684 float usedBottom = bottom;
685 // if (!force && previousLimit < bottom)
686 // usedBottom = previousLimit + 1;
687 if (limit < usedBottom) {
688 SetHighColor(used_memory_color);
689 FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom));
691 fLastMemoryHeight = barHeight;
695 void
696 ProcessController::Update()
698 system_info info;
699 get_system_info(&info);
700 bigtime_t now = system_time();
702 cpu_info* cpuInfos = new cpu_info[gCPUcount];
703 get_cpu_info(0, gCPUcount, cpuInfos);
705 fMemoryUsage = float(info.used_pages) / float(info.max_pages);
706 // Calculate work done since last call to Update() for each CPU
707 for (unsigned int x = 0; x < gCPUcount; x++) {
708 bigtime_t load = cpuInfos[x].active_time - fPrevActive[x];
709 bigtime_t passed = now - fPrevTime;
710 float cpuTime = float(load) / float(passed);
712 fPrevActive[x] = cpuInfos[x].active_time;
713 if (load > passed)
714 fPrevActive[x] -= load - passed; // save overload for next period...
715 if (cpuTime < 0)
716 cpuTime = 0;
717 if (cpuTime > 1)
718 cpuTime = 1;
719 fCPUTimes[x] = cpuTime;
721 fPrevTime = now;
723 delete[] cpuInfos;
727 // #pragma mark -
730 status_t
731 thread_popup(void *arg)
733 Tpopup_param* param = (Tpopup_param*) arg;
734 int32 mcookie, hcookie;
735 unsigned long m;
736 long h;
737 BMenuItem* item;
738 bool top = param->top;
740 system_info systemInfo;
741 get_system_info(&systemInfo);
742 info_pack* infos = new info_pack[systemInfo.used_teams];
743 // TODO: this doesn't necessarily get all teams
744 for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) {
745 infos[m].team_icon = NULL;
746 infos[m].team_name[0] = 0;
747 infos[m].thread_info = NULL;
748 if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) {
749 infos[m].thread_info = new thread_info[infos[m].team_info.thread_count];
750 for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) {
751 if (get_next_thread_info(infos[m].team_info.team, &hcookie,
752 &infos[m].thread_info[h]) != B_OK)
753 infos[m].thread_info[h].thread = -1;
755 get_team_name_and_icon(infos[m], true);
756 } else {
757 systemInfo.used_teams = m;
758 infos[m].team_info.team = -1;
762 BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false);
763 popup->SetFont(be_plain_font);
765 // Quit section
766 BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"),
767 infos, systemInfo.used_teams);
768 QuitPopup->SetFont(be_plain_font);
769 popup->AddItem(QuitPopup);
771 // Memory Usage section
772 MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"),
773 infos, systemInfo);
774 int64 committedMemory = (int64)systemInfo.used_pages * B_PAGE_SIZE / 1024;
775 for (m = 0; m < systemInfo.used_teams; m++) {
776 if (infos[m].team_info.team >= 0) {
777 MemoryBarMenuItem* memoryItem =
778 new MemoryBarMenuItem(infos[m].team_name,
779 infos[m].team_info.team, infos[m].team_icon, false, NULL);
780 MemoryPopup->AddItem(memoryItem);
781 memoryItem->UpdateSituation(committedMemory);
785 addtopbottom(MemoryPopup);
787 // CPU Load section
788 TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU "
789 "usage"), infos, systemInfo.used_teams);
790 for (m = 0; m < systemInfo.used_teams; m++) {
791 if (infos[m].team_info.team >= 0) {
792 ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name,
793 infos[m].team_info.team, infos[m].team_info.thread_count);
794 BMessage* kill_team = new BMessage('KlTm');
795 kill_team->AddInt32("team", infos[m].team_info.team);
796 TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team,
797 infos[m].team_info.team, infos[m].team_icon, false);
798 item->SetTarget(gPCView);
799 CPUPopup->AddItem(item);
803 addtopbottom(CPUPopup);
804 addtopbottom(new BSeparatorItem());
806 // CPU on/off section
807 if (gCPUcount > 1) {
808 for (unsigned int i = 0; i < gCPUcount; i++) {
809 char item_name[32];
810 sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1);
811 BMessage* m = new BMessage ('CPU ');
812 m->AddInt32 ("cpu", i);
813 item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m);
814 if (_kern_cpu_enabled(i))
815 item->SetMarked (true);
816 item->SetTarget(gPCView);
817 addtopbottom(item);
819 addtopbottom (new BSeparatorItem ());
822 // Scheduler modes
823 static const char* schedulerModes[] = { B_TRANSLATE_MARK("Low latency"),
824 B_TRANSLATE_MARK("Power saving") };
825 unsigned int modesCount = sizeof(schedulerModes) / sizeof(const char*);
826 int32 currentMode = get_scheduler_mode();
827 for (unsigned int i = 0; i < modesCount; i++) {
828 BMessage* m = new BMessage('Schd');
829 m->AddInt32("mode", i);
830 item = new BMenuItem(B_TRANSLATE(schedulerModes[i]), m);
831 if ((uint32)currentMode == i)
832 item->SetMarked(true);
833 item->SetTarget(gPCView);
834 addtopbottom(item);
836 addtopbottom(new BSeparatorItem());
838 if (!be_roster->IsRunning(kTrackerSig)) {
839 item = new IconMenuItem(gPCView->fTrackerIcon,
840 B_TRANSLATE("Restart Tracker"), new BMessage('Trac'));
841 item->SetTarget(gPCView);
842 addtopbottom(item);
844 if (!be_roster->IsRunning(kDeskbarSig)) {
845 item = new IconMenuItem(gPCView->fDeskbarIcon,
846 B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar'));
847 item->SetTarget(gPCView);
848 addtopbottom(item);
851 item = new IconMenuItem(gPCView->fTerminalIcon,
852 B_TRANSLATE("New Terminal"), new BMessage('Term'));
853 item->SetTarget(gPCView);
854 addtopbottom(item);
856 addtopbottom(new BSeparatorItem());
858 bool showLiveInDeskbarItem = gInDeskbar;
859 if (!showLiveInDeskbarItem) {
860 int32 cookie = 0;
861 image_info info;
862 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
863 if (info.type == B_APP_IMAGE) {
864 // only show the Live in Deskbar item if a) we're running in
865 // deskbar itself, or b) we're running in PC's team.
866 if (strstr(info.name, "ProcessController") != NULL) {
867 showLiveInDeskbarItem = true;
868 break;
874 if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) {
875 item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"),
876 new BMessage('AlDb'));
877 BDeskbar deskbar;
878 item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName));
879 item->SetTarget(gPCView);
880 addtopbottom(item);
881 addtopbottom(new BSeparatorItem ());
885 item = new IconMenuItem(gPCView->fProcessControllerIcon,
886 B_TRANSLATE("About ProcessController" B_UTF8_ELLIPSIS),
887 new BMessage(B_ABOUT_REQUESTED));
888 item->SetTarget(gPCView);
889 addtopbottom(item);
891 param->where.x -= 5;
892 param->where.y -= 8;
893 popup->Go(param->where, true, true, param->clickToOpenRect);
895 delete popup;
896 for (m = 0; m < systemInfo.used_teams; m++) {
897 if (infos[m].team_info.team >= 0) {
898 delete[] infos[m].thread_info;
899 delete infos[m].team_icon;
902 delete[] infos;
903 delete param;
904 atomic_add (&gPopupFlag, -1);
905 gPopupThreadID = 0;
907 return B_OK;
911 status_t
912 thread_quit_application(void *arg)
914 BMessenger messenger(NULL, (addr_t)arg);
915 messenger.SendMessage(B_QUIT_REQUESTED);
916 return B_OK;
920 status_t
921 thread_debug_thread(void *arg)
923 Tdebug_thead_param* param = (Tdebug_thead_param*) arg;
924 debug_thread(param->thread);
925 delete param;
926 return B_OK;