1 /*
2 * Copyright 2000, Georges-Edouard Berenger. All rights reserved.
3 * Copyright 2006-2018, Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include "ProcessController.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <AboutWindow.h>
15 #include <Alert.h>
16 #include <Bitmap.h>
17 #include <Catalog.h>
18 #include <debugger.h>
19 #include <Deskbar.h>
20 #include <Directory.h>
21 #include <Dragger.h>
22 #include <File.h>
23 #include <FindDirectory.h>
24 #include <MessageRunner.h>
25 #include <Path.h>
26 #include <PopUpMenu.h>
27 #include <Roster.h>
28 #include <Screen.h>
29 #include <TextView.h>
30
31 #include <scheduler.h>
32 #include <syscalls.h>
33
34 #include "AutoIcon.h"
35 #include "Colors.h"
36 #include "IconMenuItem.h"
37 #include "MemoryBarMenu.h"
38 #include "MemoryBarMenuItem.h"
39 #include "PCWorld.h"
40 #include "Preferences.h"
41 #include "QuitMenu.h"
42 #include "TeamBarMenu.h"
43 #include "TeamBarMenuItem.h"
44 #include "ThreadBarMenu.h"
45 #include "Utilities.h"
46
47
48 #undef B_TRANSLATION_CONTEXT
49 #define B_TRANSLATION_CONTEXT "ProcessController"
50
51
52 const char* kDeskbarItemName = "ProcessController";
53 const char* kClassName = "ProcessController";
54
55 const char* kFrameColorPref = "deskbar_frame_color";
56 const char* kIdleColorPref = "deskbar_idle_color";
57 const char* kActiveColorPref = "deskbar_active_color";
58
59 static const char* const kDebuggerSignature
60 = "application/x-vnd.Haiku-Debugger";
61
62 const rgb_color kKernelBlue = {20, 20, 231, 255};
63 const rgb_color kIdleGreen = {110, 190,110, 255};
64
65 ProcessController* gPCView;
66 uint32 gCPUcount;
67 rgb_color gUserColor;
68 rgb_color gUserColorSelected;
69 rgb_color gIdleColor;
70 rgb_color gIdleColorSelected;
71 rgb_color gKernelColor;
72 rgb_color gKernelColorSelected;
73 rgb_color gFrameColor;
74 rgb_color gFrameColorSelected;
75 rgb_color gMenuBackColorSelected;
76 rgb_color gMenuBackColor;
77 rgb_color gWhiteSelected;
78 ThreadBarMenu* gCurrentThreadBarMenu;
79 bool gInDeskbar = false;
80
81 #define addtopbottom(x) if (top) popup->AddItem(x); else popup->AddItem(x, 0)
82
83 status_t thread_popup(void *arg);
84
85 int32 gPopupFlag = 0;
86 thread_id gPopupThreadID = 0;
87
88 typedef struct {
89 BPoint where;
90 BRect clickToOpenRect;
91 bool top;
92 } Tpopup_param;
93
94 #define DEBUG_THREADS 1
95
96 status_t thread_quit_application(void *arg);
97 status_t thread_debug_thread(void *arg);
98
99 typedef struct {
100 thread_id thread;
101 sem_id sem;
102 time_t totalTime;
103 } Tdebug_thead_param;
104
105 // Bar layout depending on number of CPUs
106 // This is used only in case the replicant width is 16
107
108 typedef struct {
109 float cpu_width;
110 float cpu_inter;
111 float mem_width;
112 } layoutT;
113
114 layoutT layout[] = {
115 { 1, 1, 1 },
116 { 5, 1, 5 }, // 1
117 { 3, 1, 4 }, // 2
118 { 2, 1, 3 },
119 { 2, 0, 3 }, // 4
120 };
121
122
123 extern "C" _EXPORT BView* instantiate_deskbar_item(float maxWidth,
124 float maxHeight);
125
126 extern "C" _EXPORT BView*
instantiate_deskbar_item(float maxWidth,float maxHeight)127 instantiate_deskbar_item(float maxWidth, float maxHeight)
128 {
129 gInDeskbar = true;
130
131 system_info info;
132 get_system_info(&info);
133 int width = 4;
134 if (info.cpu_count > 4)
135 width = info.cpu_count;
136 if (info.cpu_count <= 16)
137 width *= 2;
138
139 // For the memory bar
140 width += 8;
141
142 // Damn, you got a lot of CPU
143 if (width > maxWidth)
144 width = (int)maxWidth;
145
146 return new ProcessController(width - 1, maxHeight - 1);
147 }
148
149
150 // #pragma mark -
151
152
ProcessController(BRect frame,bool temp)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])
166 {
167 if (!temp) {
168 Init();
169
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);
175 }
176 }
177
ProcessController(BMessage * data)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])
190 {
191 Init();
192 }
193
194
ProcessController(float width,float height)195 ProcessController::ProcessController(float width, float height)
196 :
197 BView(BRect (0, 0, width, height), kDeskbarItemName, B_FOLLOW_NONE,
198 B_WILL_DRAW),
199 fProcessControllerIcon(kSignature),
200 fProcessorIcon(k_cpu_mini),
201 fTrackerIcon(kTrackerSig),
202 fDeskbarIcon(kDeskbarSig),
203 fTerminalIcon(kTerminalSig),
204 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)),
205 fTemp(false),
206 fLastBarHeight(new float[kCPUCount]),
207 fCPUTimes(new double[kCPUCount]),
208 fPrevActive(new bigtime_t[kCPUCount])
209 {
210 Init();
211 }
212
213
~ProcessController()214 ProcessController::~ProcessController()
215 {
216 if (!fTemp) {
217 if (gPopupThreadID) {
218 status_t return_value;
219 wait_for_thread (gPopupThreadID, &return_value);
220 }
221 }
222
223 delete fMessageRunner;
224 gPCView = NULL;
225
226 delete[] fPrevActive;
227 delete[] fCPUTimes;
228 delete[] fLastBarHeight;
229 }
230
231
232 void
Init()233 ProcessController::Init()
234 {
235 memset(fLastBarHeight, 0, sizeof(float) * kCPUCount);
236 memset(fCPUTimes, 0, sizeof(double) * kCPUCount);
237 memset(fPrevActive, 0, sizeof(bigtime_t) * kCPUCount);
238
239 gPCView = this;
240 fMessageRunner = NULL;
241 fLastMemoryHeight = 0;
242 fPrevTime = 0;
243 }
244
245
246 void
_HandleDebugRequest(team_id team,thread_id thread)247 ProcessController::_HandleDebugRequest(team_id team, thread_id thread)
248 {
249 char paramString[16];
250 char idString[16];
251 strlcpy(paramString, thread > 0 ? "--thread" : "--team",
252 sizeof(paramString));
253 snprintf(idString, sizeof(idString), "%" B_PRId32,
254 thread > 0 ? thread : team);
255
256 const char* argv[] = {paramString, idString, NULL};
257 status_t error = be_roster->Launch(kDebuggerSignature, 2, argv);
258 if (error != B_OK) {
259 // TODO: notify user
260 }
261 }
262
263
264 ProcessController*
Instantiate(BMessage * data)265 ProcessController::Instantiate(BMessage *data)
266 {
267 if (!validate_instantiation(data, kClassName))
268 return NULL;
269
270 return new ProcessController(data);
271 }
272
273
274 status_t
Archive(BMessage * data,bool deep) const275 ProcessController::Archive(BMessage *data, bool deep) const
276 {
277 BView::Archive(data, deep);
278 data->AddString("add_on", kSignature);
279 data->AddString("class", kClassName);
280 return B_OK;
281 }
282
283
284 void
MessageReceived(BMessage * message)285 ProcessController::MessageReceived(BMessage *message)
286 {
287 team_id team;
288 thread_id thread;
289 BAlert *alert;
290 char question[1000];
291 switch (message->what) {
292 case 'Puls':
293 Update ();
294 DoDraw (false);
295 break;
296
297 case 'QtTm':
298 if (message->FindInt32("team", &team) == B_OK) {
299 resume_thread(spawn_thread(thread_quit_application,
300 B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY,
301 (void*)(addr_t)team));
302 }
303 break;
304
305 case 'KlTm':
306 if (message->FindInt32("team", &team) == B_OK) {
307 info_pack infos;
308 if (get_team_info(team, &infos.team_info) == B_OK) {
309 get_team_name_and_icon(infos);
310 snprintf(question, sizeof(question),
311 B_TRANSLATE("What do you want to do with the team \"%s\"?"),
312 infos.team_name);
313 alert = new BAlert(B_TRANSLATE("Please confirm"), question,
314 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this team!"),
315 B_TRANSLATE("Kill this team!"), B_WIDTH_AS_USUAL,
316 B_STOP_ALERT);
317 alert->SetShortcut(0, B_ESCAPE);
318 int result = alert->Go();
319 switch (result) {
320 case 1:
321 _HandleDebugRequest(team, -1);
322 break;
323 case 2:
324 kill_team(team);
325 break;
326 default:
327 break;
328 }
329 } else {
330 alert = new BAlert(B_TRANSLATE("Info"),
331 B_TRANSLATE("This team is already gone" B_UTF8_ELLIPSIS),
332 B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL,
333 B_STOP_ALERT);
334 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
335 alert->Go();
336 }
337 }
338 break;
339
340 case 'KlTh':
341 if (message->FindInt32("thread", &thread) == B_OK) {
342 thread_info thinfo;
343 if (get_thread_info(thread, &thinfo) == B_OK) {
344 #if DEBUG_THREADS
345 snprintf(question, sizeof(question),
346 B_TRANSLATE("What do you want to do "
347 "with the thread \"%s\"?"), thinfo.name);
348 alert = new BAlert(B_TRANSLATE("Please confirm"), question,
349 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"),
350 B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL,
351 B_STOP_ALERT);
352 alert->SetShortcut(0, B_ESCAPE);
353
354 #define KILL 2
355 #else
356 snprintf(question, sizeof(question),
357 B_TRANSLATE("Are you sure you want "
358 "to kill the thread \"%s\"?"), thinfo.name);
359 alert = new BAlert(B_TRANSLATE("Please confirm"), question,
360 B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"),
361 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
362 alert->SetShortcut(0, B_ESCAPE);
363
364 #define KILL 1
365 #endif
366 alert->SetShortcut(0, B_ESCAPE);
367 int r = alert->Go();
368 if (r == KILL)
369 kill_thread(thread);
370 #if DEBUG_THREADS
371 else if (r == 1)
372 _HandleDebugRequest(thinfo.team, thinfo.thread);
373 #endif
374 } else {
375 alert = new BAlert(B_TRANSLATE("Info"),
376 B_TRANSLATE("This thread is already gone" B_UTF8_ELLIPSIS),
377 B_TRANSLATE("Ok!"), NULL, NULL,
378 B_WIDTH_AS_USUAL, B_STOP_ALERT);
379 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
380 alert->Go();
381 }
382 }
383 break;
384
385 case 'PrTh':
386 if (message->FindInt32("thread", &thread) == B_OK) {
387 int32 new_priority;
388 if (message->FindInt32("priority", &new_priority) == B_OK)
389 set_thread_priority(thread, new_priority);
390 }
391 break;
392
393 case 'Trac':
394 {
395 BPath trackerPath;
396 if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK
397 && trackerPath.Append("Tracker") == B_OK) {
398 launch(kTrackerSig, trackerPath.Path());
399 }
400 break;
401 }
402
403 case 'Dbar':
404 {
405 BPath deskbarPath;
406 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK
407 && deskbarPath.Append("Deskbar") == B_OK) {
408 launch(kDeskbarSig, deskbarPath.Path());
409 }
410 break;
411 }
412
413 case 'Term':
414 {
415 BPath terminalPath;
416 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK
417 && terminalPath.Append("Terminal") == B_OK) {
418 launch(kTerminalSig, terminalPath.Path());
419 }
420 break;
421 }
422
423 case 'AlDb':
424 {
425 if (!be_roster->IsRunning(kDeskbarSig)) {
426 BPath deskbarPath;
427 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK
428 && deskbarPath.Append("Deskbar") == B_OK) {
429 launch(kDeskbarSig, deskbarPath.Path());
430 }
431 }
432 BDeskbar deskbar;
433 if (gInDeskbar || deskbar.HasItem (kDeskbarItemName))
434 deskbar.RemoveItem (kDeskbarItemName);
435 else
436 move_to_deskbar(deskbar);
437 break;
438 }
439
440 case 'CPU ':
441 {
442 uint32 cpu;
443 if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) {
444 bool last = true;
445 for (unsigned int p = 0; p < gCPUcount; p++) {
446 if (p != cpu && _kern_cpu_enabled(p)) {
447 last = false;
448 break;
449 }
450 }
451 if (last) {
452 alert = new BAlert(B_TRANSLATE("Info"),
453 B_TRANSLATE("This is the last active processor"
454 B_UTF8_ELLIPSIS "\n"
455 "You can't turn it off!"),
456 B_TRANSLATE("That's no Fun!"), NULL, NULL,
457 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
458 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
459 alert->Go();
460 } else
461 _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu));
462 }
463 break;
464 }
465
466 case 'Schd':
467 {
468 BMenuItem* source;
469 if (message->FindPointer("source", (void**)&source) != B_OK)
470 break;
471 if (!source->IsMarked())
472 set_scheduler_mode(SCHEDULER_MODE_POWER_SAVING);
473 else
474 set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY);
475 Preferences preferences(kPreferencesFileName);
476 preferences.SaveInt32(get_scheduler_mode(), "scheduler_mode");
477 break;
478 }
479
480 case B_ABOUT_REQUESTED:
481 AboutRequested();
482 break;
483
484 default:
485 BView::MessageReceived(message);
486 }
487 }
488
489
490 void
AboutRequested()491 ProcessController::AboutRequested()
492 {
493 BAboutWindow* window = new BAboutWindow(
494 B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature);
495
496 const char* extraCopyrights[] = {
497 "2004 beunited.org",
498 "1997-2001 Georges-Edouard Berenger",
499 NULL
500 };
501
502 const char* authors[] = {
503 "Georges-Edouard Berenger",
504 NULL
505 };
506
507 window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights);
508 window->AddAuthors(authors);
509
510 window->Show();
511 }
512
513
514 void
DefaultColors()515 ProcessController::DefaultColors()
516 {
517 swap_color.red = 203;
518 swap_color.green = 0;
519 swap_color.blue = 0;
520 swap_color.alpha = 255;
521 bool set = false;
522
523 if (!set) {
524 active_color = kKernelBlue;
525 active_color = tint_color (active_color, B_LIGHTEN_2_TINT);
526 idle_color = active_color;
527 idle_color.green /= 3;
528 idle_color.red /= 3;
529 idle_color.blue /= 3;
530 frame_color = kBlack;
531 mix_colors (memory_color, active_color, swap_color, 0.2);
532 }
533 }
534
535
536 void
AttachedToWindow()537 ProcessController::AttachedToWindow()
538 {
539 BView::AttachedToWindow();
540 if (Parent())
541 SetViewColor(B_TRANSPARENT_COLOR);
542 else
543 SetViewColor(kBlack);
544
545 Preferences tPreferences(kPreferencesFileName, NULL, false);
546 DefaultColors();
547
548 system_info info;
549 get_system_info(&info);
550 gCPUcount = info.cpu_count;
551 Update();
552
553 gIdleColor = kIdleGreen;
554 gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT);
555 gKernelColor = kKernelBlue;
556 gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT);
557 gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT);
558 gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT);
559 gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
560 B_HIGHLIGHT_BACKGROUND_TINT);
561 gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT);
562 gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR);
563 gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR);
564 gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT);
565
566 BMessenger messenger(this);
567 BMessage message('Puls');
568 fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1);
569 }
570
571
572
573 void
MouseDown(BPoint where)574 ProcessController::MouseDown(BPoint where)
575 {
576 if (atomic_add(&gPopupFlag, 1) > 0) {
577 atomic_add(&gPopupFlag, -1);
578 return;
579 }
580
581 Tpopup_param* param = new Tpopup_param;
582 ConvertToScreen(&where);
583 param->where = where;
584 param->clickToOpenRect = Frame ();
585 ConvertToScreen (¶m->clickToOpenRect);
586 param->top = where.y < BScreen(this->Window()).Frame().bottom-50;
587
588 gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread",
589 B_URGENT_DISPLAY_PRIORITY, param);
590 resume_thread(gPopupThreadID);
591 }
592
593
594 void
Draw(BRect)595 ProcessController::Draw(BRect)
596 {
597 SetDrawingMode(B_OP_COPY);
598 DoDraw(true);
599 }
600
601
602 void
DoDraw(bool force)603 ProcessController::DoDraw(bool force)
604 {
605 BRect bounds(Bounds());
606
607 float h = floorf(bounds.Height ()) - 2;
608 float top = 1, left = 1;
609 float bottom = top + h;
610 float barWidth;
611 float barGap;
612 float memWidth;
613 if (gCPUcount <= 4 && bounds.Width() == 15) {
614 // Use fixed sizes for small CPU counts
615 barWidth = layout[gCPUcount].cpu_width;
616 barGap = layout[gCPUcount].cpu_inter;
617 memWidth = layout[gCPUcount].mem_width;
618 } else {
619 memWidth = floorf((bounds.Height() + 1) / 8);
620 barGap = ((bounds.Width() + 1) / gCPUcount) > 3 ? 1 : 0;
621 barWidth = floorf((bounds.Width() - 1 - memWidth - barGap * gCPUcount)
622 / gCPUcount);
623 }
624 // interspace
625 float right = left + gCPUcount * (barWidth + barGap) - barGap;
626 float leftMem = bounds.Width() - memWidth;
627 // right of CPU frame...
628 if (force && Parent()) {
629 SetHighColor(Parent()->ViewColor());
630 FillRect(BRect(right + 1, top - 1, leftMem, bottom + 1));
631 }
632
633 if (force) {
634 SetHighColor(frame_color);
635 StrokeRect(BRect(left - 1, top - 1, right, bottom + 1));
636 if (gCPUcount > 1 && barGap == 1) {
637 for (unsigned int x = 1; x < gCPUcount; x++)
638 StrokeLine(BPoint(left + x * barWidth + x - 1, top),
639 BPoint(left + x * barWidth + x - 1, bottom));
640 }
641 }
642
643 if (force)
644 StrokeRect(BRect(leftMem - 1, top - 1, leftMem + memWidth, bottom + 1));
645
646 for (unsigned int x = 0; x < gCPUcount; x++) {
647 right = left + barWidth - 1;
648 float rem = fCPUTimes[x] * (h + 1);
649 float barHeight = floorf (rem);
650 rem -= barHeight;
651 float limit = bottom - barHeight; // horizontal line
652 float previousLimit = bottom - fLastBarHeight[x];
653 float idleTop = top;
654
655 if (!force && previousLimit > top)
656 idleTop = previousLimit - 1;
657 if (limit > idleTop) {
658 SetHighColor(idle_color);
659 FillRect(BRect(left, idleTop, right, limit - 1));
660 }
661 if (barHeight <= h) {
662 rgb_color fraction_color;
663 mix_colors(fraction_color, idle_color, active_color, rem);
664 SetHighColor(fraction_color);
665 StrokeLine(BPoint(left, bottom - barHeight), BPoint(right,
666 bottom - barHeight));
667 }
668 float active_bottom = bottom;
669 if (!force && previousLimit < bottom)
670 active_bottom = previousLimit + 1;
671 if (limit < active_bottom) {
672 SetHighColor(active_color);
673 FillRect(BRect(left, limit + 1, right, active_bottom));
674 }
675 left += barWidth + barGap;
676 fLastBarHeight[x] = barHeight;
677 }
678
679 float rightMem = bounds.Width() - 1;
680 float rem = fMemoryUsage * (h + 1);
681 float barHeight = floorf(rem);
682 rem -= barHeight;
683
684 rgb_color used_memory_color;
685 float sq = fMemoryUsage * fMemoryUsage;
686 sq *= sq;
687 sq *= sq;
688 mix_colors(used_memory_color, memory_color, swap_color, sq);
689
690 float limit = bottom - barHeight; // horizontal line
691 float previousLimit = bottom - fLastMemoryHeight;
692 float free_top = top;
693 if (!force && previousLimit > top)
694 free_top = previousLimit - 1;
695 if (limit > free_top) {
696 SetHighColor (idle_color);
697 FillRect(BRect(leftMem, free_top, rightMem, limit - 1));
698 }
699 if (barHeight <= h) {
700 rgb_color fraction_color;
701 mix_colors(fraction_color, idle_color, used_memory_color, rem);
702 SetHighColor(fraction_color);
703 StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem,
704 bottom - barHeight));
705 }
706 float usedBottom = bottom;
707 // if (!force && previousLimit < bottom)
708 // usedBottom = previousLimit + 1;
709 if (limit < usedBottom) {
710 SetHighColor(used_memory_color);
711 FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom));
712 }
713 fLastMemoryHeight = barHeight;
714 }
715
716
717 void
Update()718 ProcessController::Update()
719 {
720 system_info info;
721 get_system_info(&info);
722 bigtime_t now = system_time();
723
724 cpu_info* cpuInfos = new cpu_info[gCPUcount];
725 get_cpu_info(0, gCPUcount, cpuInfos);
726
727 fMemoryUsage = float(info.used_pages) / float(info.max_pages);
728 // Calculate work done since last call to Update() for each CPU
729 for (unsigned int x = 0; x < gCPUcount; x++) {
730 bigtime_t load = cpuInfos[x].active_time - fPrevActive[x];
731 bigtime_t passed = now - fPrevTime;
732 float cpuTime = float(load) / float(passed);
733
734 fPrevActive[x] = cpuInfos[x].active_time;
735 if (load > passed)
736 fPrevActive[x] -= load - passed; // save overload for next period...
737 if (cpuTime < 0)
738 cpuTime = 0;
739 if (cpuTime > 1)
740 cpuTime = 1;
741 fCPUTimes[x] = cpuTime;
742 }
743 fPrevTime = now;
744
745 delete[] cpuInfos;
746 }
747
748
749 // #pragma mark -
750
751
752 status_t
thread_popup(void * arg)753 thread_popup(void *arg)
754 {
755 Tpopup_param* param = (Tpopup_param*) arg;
756 int32 mcookie, hcookie;
757 unsigned long m;
758 long h;
759 BMenuItem* item;
760 bool top = param->top;
761
762 system_info systemInfo;
763 get_system_info(&systemInfo);
764 info_pack* infos = new info_pack[systemInfo.used_teams];
765 // TODO: this doesn't necessarily get all teams
766 for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) {
767 infos[m].team_icon = NULL;
768 infos[m].team_name[0] = 0;
769 infos[m].thread_info = NULL;
770 if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) {
771 infos[m].thread_info = new thread_info[infos[m].team_info.thread_count];
772 for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) {
773 if (get_next_thread_info(infos[m].team_info.team, &hcookie,
774 &infos[m].thread_info[h]) != B_OK)
775 infos[m].thread_info[h].thread = -1;
776 }
777 get_team_name_and_icon(infos[m], true);
778 } else {
779 systemInfo.used_teams = m;
780 infos[m].team_info.team = -1;
781 }
782 }
783
784 BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false);
785 popup->SetFont(be_plain_font);
786
787 // Quit section
788 BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"),
789 infos, systemInfo.used_teams);
790 QuitPopup->SetFont(be_plain_font);
791 popup->AddItem(QuitPopup);
792
793 // Memory Usage section
794 MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"),
795 infos, systemInfo);
796 int64 committedMemory = (int64)systemInfo.used_pages * B_PAGE_SIZE / 1024;
797 for (m = 0; m < systemInfo.used_teams; m++) {
798 if (infos[m].team_info.team >= 0) {
799 MemoryBarMenuItem* memoryItem =
800 new MemoryBarMenuItem(infos[m].team_name,
801 infos[m].team_info.team, infos[m].team_icon, false, NULL);
802 MemoryPopup->AddItem(memoryItem);
803 memoryItem->UpdateSituation(committedMemory);
804 }
805 }
806
807 addtopbottom(MemoryPopup);
808
809 // CPU Load section
810 TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU "
811 "usage"), infos, systemInfo.used_teams);
812 for (m = 0; m < systemInfo.used_teams; m++) {
813 if (infos[m].team_info.team >= 0) {
814 ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name,
815 infos[m].team_info.team, infos[m].team_info.thread_count);
816 BMessage* kill_team = new BMessage('KlTm');
817 kill_team->AddInt32("team", infos[m].team_info.team);
818 TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team,
819 infos[m].team_info.team, infos[m].team_icon, false);
820 item->SetTarget(gPCView);
821 CPUPopup->AddItem(item);
822 }
823 }
824
825 addtopbottom(CPUPopup);
826 addtopbottom(new BSeparatorItem());
827
828 // CPU on/off section
829 if (gCPUcount > 1) {
830 for (unsigned int i = 0; i < gCPUcount; i++) {
831 char item_name[32];
832 sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1);
833 BMessage* m = new BMessage ('CPU ');
834 m->AddInt32 ("cpu", i);
835 item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m);
836 if (_kern_cpu_enabled(i))
837 item->SetMarked (true);
838 item->SetTarget(gPCView);
839 addtopbottom(item);
840 }
841 addtopbottom (new BSeparatorItem ());
842 }
843
844 // Scheduler modes
845 int32 currentMode = get_scheduler_mode();
846 Preferences preferences(kPreferencesFileName, NULL, false);
847 int32 savedMode;
848 if (preferences.ReadInt32(savedMode, "scheduler_mode") && currentMode != savedMode) {
849 set_scheduler_mode(savedMode);
850 currentMode = get_scheduler_mode();
851 }
852 BMessage* msg = new BMessage('Schd');
853 item = new BMenuItem(B_TRANSLATE("Power saving"), msg);
854 if ((uint32)currentMode == SCHEDULER_MODE_POWER_SAVING)
855 item->SetMarked(true);
856 item->SetTarget(gPCView);
857 addtopbottom(item);
858 addtopbottom(new BSeparatorItem());
859
860 if (!be_roster->IsRunning(kTrackerSig)) {
861 item = new IconMenuItem(gPCView->fTrackerIcon,
862 B_TRANSLATE("Restart Tracker"), new BMessage('Trac'));
863 item->SetTarget(gPCView);
864 addtopbottom(item);
865 }
866 if (!be_roster->IsRunning(kDeskbarSig)) {
867 item = new IconMenuItem(gPCView->fDeskbarIcon,
868 B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar'));
869 item->SetTarget(gPCView);
870 addtopbottom(item);
871 }
872
873 item = new IconMenuItem(gPCView->fTerminalIcon,
874 B_TRANSLATE("New Terminal"), new BMessage('Term'));
875 item->SetTarget(gPCView);
876 addtopbottom(item);
877
878 addtopbottom(new BSeparatorItem());
879
880 bool showLiveInDeskbarItem = gInDeskbar;
881 if (!showLiveInDeskbarItem) {
882 int32 cookie = 0;
883 image_info info;
884 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
885 if (info.type == B_APP_IMAGE) {
886 // only show the Live in Deskbar item if a) we're running in
887 // deskbar itself, or b) we're running in PC's team.
888 if (strstr(info.name, "ProcessController") != NULL) {
889 showLiveInDeskbarItem = true;
890 break;
891 }
892 }
893 }
894 }
895
896 if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) {
897 item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"),
898 new BMessage('AlDb'));
899 BDeskbar deskbar;
900 item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName));
901 item->SetTarget(gPCView);
902 addtopbottom(item);
903 addtopbottom(new BSeparatorItem ());
904 }
905
906
907 item = new IconMenuItem(gPCView->fProcessControllerIcon,
908 B_TRANSLATE("About ProcessController" B_UTF8_ELLIPSIS),
909 new BMessage(B_ABOUT_REQUESTED));
910 item->SetTarget(gPCView);
911 addtopbottom(item);
912
913 param->where.x -= 5;
914 param->where.y -= 8;
915 popup->Go(param->where, true, true, param->clickToOpenRect);
916
917 delete popup;
918 for (m = 0; m < systemInfo.used_teams; m++) {
919 if (infos[m].team_info.team >= 0) {
920 delete[] infos[m].thread_info;
921 delete infos[m].team_icon;
922 }
923 }
924 delete[] infos;
925 delete param;
926 atomic_add (&gPopupFlag, -1);
927 gPopupThreadID = 0;
928
929 return B_OK;
930 }
931
932
933 status_t
thread_quit_application(void * arg)934 thread_quit_application(void *arg)
935 {
936 BMessenger messenger(NULL, (addr_t)arg);
937 messenger.SendMessage(B_QUIT_REQUESTED);
938 return B_OK;
939 }
940
941
942 status_t
thread_debug_thread(void * arg)943 thread_debug_thread(void *arg)
944 {
945 Tdebug_thead_param* param = (Tdebug_thead_param*) arg;
946 debug_thread(param->thread);
947 delete param;
948 return B_OK;
949 }
950