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