1 /* 2 ProcessController © 2000, Georges-Edouard Berenger, All Rights Reserved. 3 Copyright (C) 2004 beunited.org 4 Copyright (c) 2006-2018, Haiku, Inc. All rights reserved. 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 22 #include "ProcessController.h" 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include <AboutWindow.h> 29 #include <Alert.h> 30 #include <Bitmap.h> 31 #include <Catalog.h> 32 #include <debugger.h> 33 #include <Deskbar.h> 34 #include <Directory.h> 35 #include <Dragger.h> 36 #include <File.h> 37 #include <FindDirectory.h> 38 #include <MessageRunner.h> 39 #include <Path.h> 40 #include <PopUpMenu.h> 41 #include <Roster.h> 42 #include <Screen.h> 43 #include <TextView.h> 44 45 #include <scheduler.h> 46 #include <syscalls.h> 47 48 #include "AutoIcon.h" 49 #include "Colors.h" 50 #include "IconMenuItem.h" 51 #include "MemoryBarMenu.h" 52 #include "MemoryBarMenuItem.h" 53 #include "PCWorld.h" 54 #include "Preferences.h" 55 #include "QuitMenu.h" 56 #include "TeamBarMenu.h" 57 #include "TeamBarMenuItem.h" 58 #include "ThreadBarMenu.h" 59 #include "Utilities.h" 60 61 62 #undef B_TRANSLATION_CONTEXT 63 #define B_TRANSLATION_CONTEXT "ProcessController" 64 65 66 const char* kDeskbarItemName = "ProcessController"; 67 const char* kClassName = "ProcessController"; 68 69 const char* kFrameColorPref = "deskbar_frame_color"; 70 const char* kIdleColorPref = "deskbar_idle_color"; 71 const char* kActiveColorPref = "deskbar_active_color"; 72 73 static const char* const kDebuggerSignature 74 = "application/x-vnd.Haiku-Debugger"; 75 76 const rgb_color kKernelBlue = {20, 20, 231, 255}; 77 const rgb_color kIdleGreen = {110, 190,110, 255}; 78 79 ProcessController* gPCView; 80 uint32 gCPUcount; 81 rgb_color gUserColor; 82 rgb_color gUserColorSelected; 83 rgb_color gIdleColor; 84 rgb_color gIdleColorSelected; 85 rgb_color gKernelColor; 86 rgb_color gKernelColorSelected; 87 rgb_color gFrameColor; 88 rgb_color gFrameColorSelected; 89 rgb_color gMenuBackColorSelected; 90 rgb_color gMenuBackColor; 91 rgb_color gWhiteSelected; 92 ThreadBarMenu* gCurrentThreadBarMenu; 93 bool gInDeskbar = false; 94 95 #define addtopbottom(x) if (top) popup->AddItem(x); else popup->AddItem(x, 0) 96 97 status_t thread_popup(void *arg); 98 99 int32 gPopupFlag = 0; 100 thread_id gPopupThreadID = 0; 101 102 typedef struct { 103 BPoint where; 104 BRect clickToOpenRect; 105 bool top; 106 } Tpopup_param; 107 108 #define DEBUG_THREADS 1 109 110 status_t thread_quit_application(void *arg); 111 status_t thread_debug_thread(void *arg); 112 113 typedef struct { 114 thread_id thread; 115 sem_id sem; 116 time_t totalTime; 117 } Tdebug_thead_param; 118 119 // Bar layout depending on number of CPUs 120 // This is used only in case the replicant width is 16 121 122 typedef struct { 123 float cpu_width; 124 float cpu_inter; 125 float mem_width; 126 } layoutT; 127 128 layoutT layout[] = { 129 { 1, 1, 1 }, 130 { 5, 1, 5 }, // 1 131 { 3, 1, 4 }, // 2 132 { 2, 1, 3 }, 133 { 2, 0, 3 }, // 4 134 { 1, 1, 1 }, 135 { 1, 1, 2 }, 136 { 1, 1, 1 }, 137 { 1, 0, 3 }, // 8 138 { 1, 1, 1 }, 139 { 1, 0, 3 }, 140 { 1, 0, 2 }, 141 { 1, 0, 1 } // 12 142 }; 143 144 145 extern "C" _EXPORT BView* instantiate_deskbar_item(float maxWidth, 146 float maxHeight); 147 148 extern "C" _EXPORT BView* 149 instantiate_deskbar_item(float maxWidth, float maxHeight) 150 { 151 gInDeskbar = true; 152 return new ProcessController(maxHeight - 1, maxHeight - 1); 153 } 154 155 156 // #pragma mark - 157 158 159 ProcessController::ProcessController(BRect frame, bool temp) 160 : BView(frame, kDeskbarItemName, B_FOLLOW_TOP_BOTTOM, 161 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 162 fProcessControllerIcon(kSignature), 163 fProcessorIcon(k_cpu_mini), 164 fTrackerIcon(kTrackerSig), 165 fDeskbarIcon(kDeskbarSig), 166 fTerminalIcon(kTerminalSig), 167 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), 168 fTemp(temp), 169 fLastBarHeight(new float[kCPUCount]), 170 fCPUTimes(new double[kCPUCount]), 171 fPrevActive(new bigtime_t[kCPUCount]) 172 { 173 if (!temp) { 174 Init(); 175 176 frame.OffsetTo(B_ORIGIN); 177 frame.top = frame.bottom - 7; 178 frame.left = frame.right - 7; 179 BDragger* dragger = new BDragger(frame, this, B_FOLLOW_BOTTOM); 180 AddChild(dragger); 181 } 182 } 183 184 ProcessController::ProcessController(BMessage *data) 185 : BView(data), 186 fProcessControllerIcon(kSignature), 187 fProcessorIcon(k_cpu_mini), 188 fTrackerIcon(kTrackerSig), 189 fDeskbarIcon(kDeskbarSig), 190 fTerminalIcon(kTerminalSig), 191 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), 192 fTemp(false), 193 fLastBarHeight(new float[kCPUCount]), 194 fCPUTimes(new double[kCPUCount]), 195 fPrevActive(new bigtime_t[kCPUCount]) 196 { 197 Init(); 198 } 199 200 201 ProcessController::ProcessController(float width, float height) 202 : 203 BView(BRect (0, 0, width, height), kDeskbarItemName, B_FOLLOW_NONE, 204 B_WILL_DRAW), 205 fProcessControllerIcon(kSignature), 206 fProcessorIcon(k_cpu_mini), 207 fTrackerIcon(kTrackerSig), 208 fDeskbarIcon(kDeskbarSig), 209 fTerminalIcon(kTerminalSig), 210 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), 211 fTemp(false), 212 fLastBarHeight(new float[kCPUCount]), 213 fCPUTimes(new double[kCPUCount]), 214 fPrevActive(new bigtime_t[kCPUCount]) 215 { 216 Init(); 217 } 218 219 220 ProcessController::~ProcessController() 221 { 222 if (!fTemp) { 223 if (gPopupThreadID) { 224 status_t return_value; 225 wait_for_thread (gPopupThreadID, &return_value); 226 } 227 } 228 229 delete fMessageRunner; 230 gPCView = NULL; 231 232 delete[] fPrevActive; 233 delete[] fCPUTimes; 234 delete[] fLastBarHeight; 235 } 236 237 238 void 239 ProcessController::Init() 240 { 241 memset(fLastBarHeight, 0, sizeof(float) * kCPUCount); 242 memset(fCPUTimes, 0, sizeof(double) * kCPUCount); 243 memset(fPrevActive, 0, sizeof(bigtime_t) * kCPUCount); 244 245 gPCView = this; 246 fMessageRunner = NULL; 247 fLastMemoryHeight = 0; 248 fPrevTime = 0; 249 } 250 251 252 void 253 ProcessController::_HandleDebugRequest(team_id team, thread_id thread) 254 { 255 char paramString[16]; 256 char idString[16]; 257 strlcpy(paramString, thread > 0 ? "--thread" : "--team", 258 sizeof(paramString)); 259 snprintf(idString, sizeof(idString), "%" B_PRId32, 260 thread > 0 ? thread : team); 261 262 const char* argv[] = {paramString, idString, NULL}; 263 status_t error = be_roster->Launch(kDebuggerSignature, 2, argv); 264 if (error != B_OK) { 265 // TODO: notify user 266 } 267 } 268 269 270 ProcessController* 271 ProcessController::Instantiate(BMessage *data) 272 { 273 if (!validate_instantiation(data, kClassName)) 274 return NULL; 275 276 return new ProcessController(data); 277 } 278 279 280 status_t 281 ProcessController::Archive(BMessage *data, bool deep) const 282 { 283 BView::Archive(data, deep); 284 data->AddString("add_on", kSignature); 285 data->AddString("class", kClassName); 286 return B_OK; 287 } 288 289 290 void 291 ProcessController::MessageReceived(BMessage *message) 292 { 293 team_id team; 294 thread_id thread; 295 BAlert *alert; 296 char question[1000]; 297 switch (message->what) { 298 case 'Puls': 299 Update (); 300 DoDraw (false); 301 break; 302 303 case 'QtTm': 304 if (message->FindInt32("team", &team) == B_OK) { 305 resume_thread(spawn_thread(thread_quit_application, 306 B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY, 307 (void*)(addr_t)team)); 308 } 309 break; 310 311 case 'KlTm': 312 if (message->FindInt32("team", &team) == B_OK) { 313 info_pack infos; 314 if (get_team_info(team, &infos.team_info) == B_OK) { 315 get_team_name_and_icon(infos); 316 snprintf(question, sizeof(question), 317 B_TRANSLATE("What do you want to do with the team \"%s\"?"), 318 infos.team_name); 319 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 320 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this team!"), 321 B_TRANSLATE("Kill this team!"), B_WIDTH_AS_USUAL, 322 B_STOP_ALERT); 323 alert->SetShortcut(0, B_ESCAPE); 324 int result = alert->Go(); 325 switch (result) { 326 case 1: 327 _HandleDebugRequest(team, -1); 328 break; 329 case 2: 330 kill_team(team); 331 break; 332 default: 333 break; 334 } 335 } else { 336 alert = new BAlert(B_TRANSLATE("Info"), 337 B_TRANSLATE("This team is already gone" B_UTF8_ELLIPSIS), 338 B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL, 339 B_STOP_ALERT); 340 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 341 alert->Go(); 342 } 343 } 344 break; 345 346 case 'KlTh': 347 if (message->FindInt32("thread", &thread) == B_OK) { 348 thread_info thinfo; 349 if (get_thread_info(thread, &thinfo) == B_OK) { 350 #if DEBUG_THREADS 351 snprintf(question, sizeof(question), 352 B_TRANSLATE("What do you want to do " 353 "with the thread \"%s\"?"), thinfo.name); 354 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 355 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"), 356 B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL, 357 B_STOP_ALERT); 358 alert->SetShortcut(0, B_ESCAPE); 359 360 #define KILL 2 361 #else 362 snprintf(question, sizeof(question), 363 B_TRANSLATE("Are you sure you want " 364 "to kill the thread \"%s\"?"), thinfo.name); 365 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 366 B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"), 367 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 368 alert->SetShortcut(0, B_ESCAPE); 369 370 #define KILL 1 371 #endif 372 alert->SetShortcut(0, B_ESCAPE); 373 int r = alert->Go(); 374 if (r == KILL) 375 kill_thread(thread); 376 #if DEBUG_THREADS 377 else if (r == 1) 378 _HandleDebugRequest(thinfo.team, thinfo.thread); 379 #endif 380 } else { 381 alert = new BAlert(B_TRANSLATE("Info"), 382 B_TRANSLATE("This thread is already gone" B_UTF8_ELLIPSIS), 383 B_TRANSLATE("Ok!"), NULL, NULL, 384 B_WIDTH_AS_USUAL, B_STOP_ALERT); 385 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 386 alert->Go(); 387 } 388 } 389 break; 390 391 case 'PrTh': 392 if (message->FindInt32("thread", &thread) == B_OK) { 393 int32 new_priority; 394 if (message->FindInt32("priority", &new_priority) == B_OK) 395 set_thread_priority(thread, new_priority); 396 } 397 break; 398 399 case 'Trac': 400 { 401 BPath trackerPath; 402 if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK 403 && trackerPath.Append("Tracker") == B_OK) { 404 launch(kTrackerSig, trackerPath.Path()); 405 } 406 break; 407 } 408 409 case 'Dbar': 410 { 411 BPath deskbarPath; 412 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK 413 && deskbarPath.Append("Deskbar") == B_OK) { 414 launch(kDeskbarSig, deskbarPath.Path()); 415 } 416 break; 417 } 418 419 case 'Term': 420 { 421 BPath terminalPath; 422 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK 423 && terminalPath.Append("Terminal") == B_OK) { 424 launch(kTerminalSig, terminalPath.Path()); 425 } 426 break; 427 } 428 429 case 'AlDb': 430 { 431 if (!be_roster->IsRunning(kDeskbarSig)) { 432 BPath deskbarPath; 433 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK 434 && deskbarPath.Append("Deskbar") == B_OK) { 435 launch(kDeskbarSig, deskbarPath.Path()); 436 } 437 } 438 BDeskbar deskbar; 439 if (gInDeskbar || deskbar.HasItem (kDeskbarItemName)) 440 deskbar.RemoveItem (kDeskbarItemName); 441 else 442 move_to_deskbar(deskbar); 443 break; 444 } 445 446 case 'CPU ': 447 { 448 uint32 cpu; 449 if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) { 450 bool last = true; 451 for (unsigned int p = 0; p < gCPUcount; p++) { 452 if (p != cpu && _kern_cpu_enabled(p)) { 453 last = false; 454 break; 455 } 456 } 457 if (last) { 458 alert = new BAlert(B_TRANSLATE("Info"), 459 B_TRANSLATE("This is the last active processor" 460 B_UTF8_ELLIPSIS "\n" 461 "You can't turn it off!"), 462 B_TRANSLATE("That's no Fun!"), NULL, NULL, 463 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 464 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 465 alert->Go(); 466 } else 467 _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu)); 468 } 469 break; 470 } 471 472 case 'Schd': 473 { 474 int32 mode; 475 if (message->FindInt32 ("mode", &mode) == B_OK) 476 set_scheduler_mode(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 <= 12 && bounds.Width() == 15) { 614 // Use fixed sizes for small icon sizes 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 static const char* schedulerModes[] = { B_TRANSLATE_MARK("Low latency"), 846 B_TRANSLATE_MARK("Power saving") }; 847 unsigned int modesCount = sizeof(schedulerModes) / sizeof(const char*); 848 int32 currentMode = get_scheduler_mode(); 849 for (unsigned int i = 0; i < modesCount; i++) { 850 BMessage* m = new BMessage('Schd'); 851 m->AddInt32("mode", i); 852 item = new BMenuItem(B_TRANSLATE(schedulerModes[i]), m); 853 if ((uint32)currentMode == i) 854 item->SetMarked(true); 855 item->SetTarget(gPCView); 856 addtopbottom(item); 857 } 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