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 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 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 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 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 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 595 ProcessController::Draw(BRect) 596 { 597 SetDrawingMode(B_OP_COPY); 598 DoDraw(true); 599 } 600 601 602 void 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 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 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 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 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