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* 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 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 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 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 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 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 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* 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 275 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 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 break; 476 } 477 478 case B_ABOUT_REQUESTED: 479 AboutRequested(); 480 break; 481 482 default: 483 BView::MessageReceived(message); 484 } 485 } 486 487 488 void 489 ProcessController::AboutRequested() 490 { 491 BAboutWindow* window = new BAboutWindow( 492 B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature); 493 494 const char* extraCopyrights[] = { 495 "2004 beunited.org", 496 "1997-2001 Georges-Edouard Berenger", 497 NULL 498 }; 499 500 const char* authors[] = { 501 "Georges-Edouard Berenger", 502 NULL 503 }; 504 505 window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights); 506 window->AddAuthors(authors); 507 508 window->Show(); 509 } 510 511 512 void 513 ProcessController::DefaultColors() 514 { 515 swap_color.red = 203; 516 swap_color.green = 0; 517 swap_color.blue = 0; 518 swap_color.alpha = 255; 519 bool set = false; 520 521 if (!set) { 522 active_color = kKernelBlue; 523 active_color = tint_color (active_color, B_LIGHTEN_2_TINT); 524 idle_color = active_color; 525 idle_color.green /= 3; 526 idle_color.red /= 3; 527 idle_color.blue /= 3; 528 frame_color = kBlack; 529 mix_colors (memory_color, active_color, swap_color, 0.2); 530 } 531 } 532 533 534 void 535 ProcessController::AttachedToWindow() 536 { 537 BView::AttachedToWindow(); 538 if (Parent()) 539 SetViewColor(B_TRANSPARENT_COLOR); 540 else 541 SetViewColor(kBlack); 542 543 Preferences tPreferences(kPreferencesFileName, NULL, false); 544 DefaultColors(); 545 546 system_info info; 547 get_system_info(&info); 548 gCPUcount = info.cpu_count; 549 Update(); 550 551 gIdleColor = kIdleGreen; 552 gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT); 553 gKernelColor = kKernelBlue; 554 gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT); 555 gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT); 556 gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT); 557 gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 558 B_HIGHLIGHT_BACKGROUND_TINT); 559 gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT); 560 gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR); 561 gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR); 562 gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT); 563 564 BMessenger messenger(this); 565 BMessage message('Puls'); 566 fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1); 567 } 568 569 570 571 void 572 ProcessController::MouseDown(BPoint where) 573 { 574 if (atomic_add(&gPopupFlag, 1) > 0) { 575 atomic_add(&gPopupFlag, -1); 576 return; 577 } 578 579 Tpopup_param* param = new Tpopup_param; 580 ConvertToScreen(&where); 581 param->where = where; 582 param->clickToOpenRect = Frame (); 583 ConvertToScreen (¶m->clickToOpenRect); 584 param->top = where.y < BScreen(this->Window()).Frame().bottom-50; 585 586 gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread", 587 B_URGENT_DISPLAY_PRIORITY, param); 588 resume_thread(gPopupThreadID); 589 } 590 591 592 void 593 ProcessController::Draw(BRect) 594 { 595 SetDrawingMode(B_OP_COPY); 596 DoDraw(true); 597 } 598 599 600 void 601 ProcessController::DoDraw(bool force) 602 { 603 BRect bounds(Bounds()); 604 605 float h = floorf(bounds.Height ()) - 2; 606 float top = 1, left = 1; 607 float bottom = top + h; 608 float barWidth; 609 float barGap; 610 float memWidth; 611 if (gCPUcount <= 4 && bounds.Width() == 15) { 612 // Use fixed sizes for small CPU counts 613 barWidth = layout[gCPUcount].cpu_width; 614 barGap = layout[gCPUcount].cpu_inter; 615 memWidth = layout[gCPUcount].mem_width; 616 } else { 617 memWidth = floorf((bounds.Height() + 1) / 8); 618 barGap = ((bounds.Width() + 1) / gCPUcount) > 3 ? 1 : 0; 619 barWidth = floorf((bounds.Width() - 1 - memWidth - barGap * gCPUcount) 620 / gCPUcount); 621 } 622 // interspace 623 float right = left + gCPUcount * (barWidth + barGap) - barGap; 624 float leftMem = bounds.Width() - memWidth; 625 // right of CPU frame... 626 if (force && Parent()) { 627 SetHighColor(Parent()->ViewColor()); 628 FillRect(BRect(right + 1, top - 1, leftMem, bottom + 1)); 629 } 630 631 if (force) { 632 SetHighColor(frame_color); 633 StrokeRect(BRect(left - 1, top - 1, right, bottom + 1)); 634 if (gCPUcount > 1 && barGap == 1) { 635 for (unsigned int x = 1; x < gCPUcount; x++) 636 StrokeLine(BPoint(left + x * barWidth + x - 1, top), 637 BPoint(left + x * barWidth + x - 1, bottom)); 638 } 639 } 640 641 if (force) 642 StrokeRect(BRect(leftMem - 1, top - 1, leftMem + memWidth, bottom + 1)); 643 644 for (unsigned int x = 0; x < gCPUcount; x++) { 645 right = left + barWidth - 1; 646 float rem = fCPUTimes[x] * (h + 1); 647 float barHeight = floorf (rem); 648 rem -= barHeight; 649 float limit = bottom - barHeight; // horizontal line 650 float previousLimit = bottom - fLastBarHeight[x]; 651 float idleTop = top; 652 653 if (!force && previousLimit > top) 654 idleTop = previousLimit - 1; 655 if (limit > idleTop) { 656 SetHighColor(idle_color); 657 FillRect(BRect(left, idleTop, right, limit - 1)); 658 } 659 if (barHeight <= h) { 660 rgb_color fraction_color; 661 mix_colors(fraction_color, idle_color, active_color, rem); 662 SetHighColor(fraction_color); 663 StrokeLine(BPoint(left, bottom - barHeight), BPoint(right, 664 bottom - barHeight)); 665 } 666 float active_bottom = bottom; 667 if (!force && previousLimit < bottom) 668 active_bottom = previousLimit + 1; 669 if (limit < active_bottom) { 670 SetHighColor(active_color); 671 FillRect(BRect(left, limit + 1, right, active_bottom)); 672 } 673 left += barWidth + barGap; 674 fLastBarHeight[x] = barHeight; 675 } 676 677 float rightMem = bounds.Width() - 1; 678 float rem = fMemoryUsage * (h + 1); 679 float barHeight = floorf(rem); 680 rem -= barHeight; 681 682 rgb_color used_memory_color; 683 float sq = fMemoryUsage * fMemoryUsage; 684 sq *= sq; 685 sq *= sq; 686 mix_colors(used_memory_color, memory_color, swap_color, sq); 687 688 float limit = bottom - barHeight; // horizontal line 689 float previousLimit = bottom - fLastMemoryHeight; 690 float free_top = top; 691 if (!force && previousLimit > top) 692 free_top = previousLimit - 1; 693 if (limit > free_top) { 694 SetHighColor (idle_color); 695 FillRect(BRect(leftMem, free_top, rightMem, limit - 1)); 696 } 697 if (barHeight <= h) { 698 rgb_color fraction_color; 699 mix_colors(fraction_color, idle_color, used_memory_color, rem); 700 SetHighColor(fraction_color); 701 StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem, 702 bottom - barHeight)); 703 } 704 float usedBottom = bottom; 705 // if (!force && previousLimit < bottom) 706 // usedBottom = previousLimit + 1; 707 if (limit < usedBottom) { 708 SetHighColor(used_memory_color); 709 FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom)); 710 } 711 fLastMemoryHeight = barHeight; 712 } 713 714 715 void 716 ProcessController::Update() 717 { 718 system_info info; 719 get_system_info(&info); 720 bigtime_t now = system_time(); 721 722 cpu_info* cpuInfos = new cpu_info[gCPUcount]; 723 get_cpu_info(0, gCPUcount, cpuInfos); 724 725 fMemoryUsage = float(info.used_pages) / float(info.max_pages); 726 // Calculate work done since last call to Update() for each CPU 727 for (unsigned int x = 0; x < gCPUcount; x++) { 728 bigtime_t load = cpuInfos[x].active_time - fPrevActive[x]; 729 bigtime_t passed = now - fPrevTime; 730 float cpuTime = float(load) / float(passed); 731 732 fPrevActive[x] = cpuInfos[x].active_time; 733 if (load > passed) 734 fPrevActive[x] -= load - passed; // save overload for next period... 735 if (cpuTime < 0) 736 cpuTime = 0; 737 if (cpuTime > 1) 738 cpuTime = 1; 739 fCPUTimes[x] = cpuTime; 740 } 741 fPrevTime = now; 742 743 delete[] cpuInfos; 744 } 745 746 747 // #pragma mark - 748 749 750 status_t 751 thread_popup(void *arg) 752 { 753 Tpopup_param* param = (Tpopup_param*) arg; 754 int32 mcookie, hcookie; 755 unsigned long m; 756 long h; 757 BMenuItem* item; 758 bool top = param->top; 759 760 system_info systemInfo; 761 get_system_info(&systemInfo); 762 info_pack* infos = new info_pack[systemInfo.used_teams]; 763 // TODO: this doesn't necessarily get all teams 764 for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) { 765 infos[m].team_icon = NULL; 766 infos[m].team_name[0] = 0; 767 infos[m].thread_info = NULL; 768 if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) { 769 infos[m].thread_info = new thread_info[infos[m].team_info.thread_count]; 770 for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) { 771 if (get_next_thread_info(infos[m].team_info.team, &hcookie, 772 &infos[m].thread_info[h]) != B_OK) 773 infos[m].thread_info[h].thread = -1; 774 } 775 get_team_name_and_icon(infos[m], true); 776 } else { 777 systemInfo.used_teams = m; 778 infos[m].team_info.team = -1; 779 } 780 } 781 782 BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false); 783 popup->SetFont(be_plain_font); 784 785 // Quit section 786 BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"), 787 infos, systemInfo.used_teams); 788 QuitPopup->SetFont(be_plain_font); 789 popup->AddItem(QuitPopup); 790 791 // Memory Usage section 792 MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"), 793 infos, systemInfo); 794 int64 committedMemory = (int64)systemInfo.used_pages * B_PAGE_SIZE / 1024; 795 for (m = 0; m < systemInfo.used_teams; m++) { 796 if (infos[m].team_info.team >= 0) { 797 MemoryBarMenuItem* memoryItem = 798 new MemoryBarMenuItem(infos[m].team_name, 799 infos[m].team_info.team, infos[m].team_icon, false, NULL); 800 MemoryPopup->AddItem(memoryItem); 801 memoryItem->UpdateSituation(committedMemory); 802 } 803 } 804 805 addtopbottom(MemoryPopup); 806 807 // CPU Load section 808 TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU " 809 "usage"), infos, systemInfo.used_teams); 810 for (m = 0; m < systemInfo.used_teams; m++) { 811 if (infos[m].team_info.team >= 0) { 812 ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name, 813 infos[m].team_info.team, infos[m].team_info.thread_count); 814 BMessage* kill_team = new BMessage('KlTm'); 815 kill_team->AddInt32("team", infos[m].team_info.team); 816 TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team, 817 infos[m].team_info.team, infos[m].team_icon, false); 818 item->SetTarget(gPCView); 819 CPUPopup->AddItem(item); 820 } 821 } 822 823 addtopbottom(CPUPopup); 824 addtopbottom(new BSeparatorItem()); 825 826 // CPU on/off section 827 if (gCPUcount > 1) { 828 for (unsigned int i = 0; i < gCPUcount; i++) { 829 char item_name[32]; 830 sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1); 831 BMessage* m = new BMessage ('CPU '); 832 m->AddInt32 ("cpu", i); 833 item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m); 834 if (_kern_cpu_enabled(i)) 835 item->SetMarked (true); 836 item->SetTarget(gPCView); 837 addtopbottom(item); 838 } 839 addtopbottom (new BSeparatorItem ()); 840 } 841 842 // Scheduler modes 843 int32 currentMode = get_scheduler_mode(); 844 BMessage* msg = new BMessage('Schd'); 845 item = new BMenuItem(B_TRANSLATE("Power saving"), msg); 846 if ((uint32)currentMode == SCHEDULER_MODE_POWER_SAVING) 847 item->SetMarked(true); 848 item->SetTarget(gPCView); 849 addtopbottom(item); 850 addtopbottom(new BSeparatorItem()); 851 852 if (!be_roster->IsRunning(kTrackerSig)) { 853 item = new IconMenuItem(gPCView->fTrackerIcon, 854 B_TRANSLATE("Restart Tracker"), new BMessage('Trac')); 855 item->SetTarget(gPCView); 856 addtopbottom(item); 857 } 858 if (!be_roster->IsRunning(kDeskbarSig)) { 859 item = new IconMenuItem(gPCView->fDeskbarIcon, 860 B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar')); 861 item->SetTarget(gPCView); 862 addtopbottom(item); 863 } 864 865 item = new IconMenuItem(gPCView->fTerminalIcon, 866 B_TRANSLATE("New Terminal"), new BMessage('Term')); 867 item->SetTarget(gPCView); 868 addtopbottom(item); 869 870 addtopbottom(new BSeparatorItem()); 871 872 bool showLiveInDeskbarItem = gInDeskbar; 873 if (!showLiveInDeskbarItem) { 874 int32 cookie = 0; 875 image_info info; 876 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 877 if (info.type == B_APP_IMAGE) { 878 // only show the Live in Deskbar item if a) we're running in 879 // deskbar itself, or b) we're running in PC's team. 880 if (strstr(info.name, "ProcessController") != NULL) { 881 showLiveInDeskbarItem = true; 882 break; 883 } 884 } 885 } 886 } 887 888 if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) { 889 item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"), 890 new BMessage('AlDb')); 891 BDeskbar deskbar; 892 item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName)); 893 item->SetTarget(gPCView); 894 addtopbottom(item); 895 addtopbottom(new BSeparatorItem ()); 896 } 897 898 899 item = new IconMenuItem(gPCView->fProcessControllerIcon, 900 B_TRANSLATE("About ProcessController" B_UTF8_ELLIPSIS), 901 new BMessage(B_ABOUT_REQUESTED)); 902 item->SetTarget(gPCView); 903 addtopbottom(item); 904 905 param->where.x -= 5; 906 param->where.y -= 8; 907 popup->Go(param->where, true, true, param->clickToOpenRect); 908 909 delete popup; 910 for (m = 0; m < systemInfo.used_teams; m++) { 911 if (infos[m].team_info.team >= 0) { 912 delete[] infos[m].thread_info; 913 delete infos[m].team_icon; 914 } 915 } 916 delete[] infos; 917 delete param; 918 atomic_add (&gPopupFlag, -1); 919 gPopupThreadID = 0; 920 921 return B_OK; 922 } 923 924 925 status_t 926 thread_quit_application(void *arg) 927 { 928 BMessenger messenger(NULL, (addr_t)arg); 929 messenger.SendMessage(B_QUIT_REQUESTED); 930 return B_OK; 931 } 932 933 934 status_t 935 thread_debug_thread(void *arg) 936 { 937 Tdebug_thead_param* param = (Tdebug_thead_param*) arg; 938 debug_thread(param->thread); 939 delete param; 940 return B_OK; 941 } 942