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...\n" 460 "You can't turn it off!"), 461 B_TRANSLATE("That's no Fun!"), NULL, NULL, 462 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 463 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 464 alert->Go(); 465 } else 466 _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu)); 467 } 468 break; 469 } 470 471 case 'Schd': 472 { 473 int32 mode; 474 if (message->FindInt32 ("mode", &mode) == B_OK) 475 set_scheduler_mode(mode); 476 break; 477 } 478 479 case B_ABOUT_REQUESTED: 480 AboutRequested(); 481 break; 482 483 default: 484 BView::MessageReceived(message); 485 } 486 } 487 488 489 void 490 ProcessController::AboutRequested() 491 { 492 BAboutWindow* window = new BAboutWindow( 493 B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature); 494 495 const char* extraCopyrights[] = { 496 "2004 beunited.org", 497 "1997-2001 Georges-Edouard Berenger", 498 NULL 499 }; 500 501 const char* authors[] = { 502 "Georges-Edouard Berenger", 503 NULL 504 }; 505 506 window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights); 507 window->AddAuthors(authors); 508 509 window->Show(); 510 } 511 512 513 void 514 ProcessController::DefaultColors() 515 { 516 swap_color.red = 203; 517 swap_color.green = 0; 518 swap_color.blue = 0; 519 swap_color.alpha = 255; 520 bool set = false; 521 522 if (!set) { 523 active_color = kKernelBlue; 524 active_color = tint_color (active_color, B_LIGHTEN_2_TINT); 525 idle_color = active_color; 526 idle_color.green /= 3; 527 idle_color.red /= 3; 528 idle_color.blue /= 3; 529 frame_color = kBlack; 530 mix_colors (memory_color, active_color, swap_color, 0.2); 531 } 532 } 533 534 535 void 536 ProcessController::AttachedToWindow() 537 { 538 BView::AttachedToWindow(); 539 if (Parent()) 540 SetViewColor(B_TRANSPARENT_COLOR); 541 else 542 SetViewColor(kBlack); 543 544 Preferences tPreferences(kPreferencesFileName, NULL, false); 545 DefaultColors(); 546 547 system_info info; 548 get_system_info(&info); 549 gCPUcount = info.cpu_count; 550 Update(); 551 552 gIdleColor = kIdleGreen; 553 gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT); 554 gKernelColor = kKernelBlue; 555 gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT); 556 gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT); 557 gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT); 558 gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 559 B_HIGHLIGHT_BACKGROUND_TINT); 560 gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT); 561 gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR); 562 gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR); 563 gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT); 564 565 BMessenger messenger(this); 566 BMessage message('Puls'); 567 fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1); 568 } 569 570 571 572 void 573 ProcessController::MouseDown(BPoint where) 574 { 575 if (atomic_add(&gPopupFlag, 1) > 0) { 576 atomic_add(&gPopupFlag, -1); 577 return; 578 } 579 580 Tpopup_param* param = new Tpopup_param; 581 ConvertToScreen(&where); 582 param->where = where; 583 param->clickToOpenRect = Frame (); 584 ConvertToScreen (¶m->clickToOpenRect); 585 param->top = where.y < BScreen(this->Window()).Frame().bottom-50; 586 587 gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread", 588 B_URGENT_DISPLAY_PRIORITY, param); 589 resume_thread(gPopupThreadID); 590 } 591 592 593 void 594 ProcessController::Draw(BRect) 595 { 596 SetDrawingMode(B_OP_COPY); 597 DoDraw(true); 598 } 599 600 601 void 602 ProcessController::DoDraw(bool force) 603 { 604 BRect bounds(Bounds()); 605 606 float h = floorf(bounds.Height ()) - 2; 607 float top = 1, left = 1; 608 float bottom = top + h; 609 float barWidth; 610 float barGap; 611 float memWidth; 612 if (gCPUcount <= 12 && bounds.Width() == 15) { 613 // Use fixed sizes for small icon sizes 614 barWidth = layout[gCPUcount].cpu_width; 615 barGap = layout[gCPUcount].cpu_inter; 616 memWidth = layout[gCPUcount].mem_width; 617 } else { 618 memWidth = floorf((bounds.Height() + 1) / 8); 619 barGap = ((bounds.Width() + 1) / gCPUcount) > 3 ? 1 : 0; 620 barWidth = floorf((bounds.Width() - 1 - memWidth - barGap * gCPUcount) 621 / gCPUcount); 622 } 623 // interspace 624 float right = left + gCPUcount * (barWidth + barGap) - barGap; 625 // right of CPU frame... 626 if (force && Parent()) { 627 SetHighColor(Parent()->ViewColor()); 628 FillRect(BRect(right + 1, top - 1, right + 2, 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 float leftMem = bounds.Width() - memWidth; 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 static const char* schedulerModes[] = { B_TRANSLATE_MARK("Low latency"), 844 B_TRANSLATE_MARK("Power saving") }; 845 unsigned int modesCount = sizeof(schedulerModes) / sizeof(const char*); 846 int32 currentMode = get_scheduler_mode(); 847 for (unsigned int i = 0; i < modesCount; i++) { 848 BMessage* m = new BMessage('Schd'); 849 m->AddInt32("mode", i); 850 item = new BMenuItem(B_TRANSLATE(schedulerModes[i]), m); 851 if ((uint32)currentMode == i) 852 item->SetMarked(true); 853 item->SetTarget(gPCView); 854 addtopbottom(item); 855 } 856 addtopbottom(new BSeparatorItem()); 857 858 if (!be_roster->IsRunning(kTrackerSig)) { 859 item = new IconMenuItem(gPCView->fTrackerIcon, 860 B_TRANSLATE("Restart Tracker"), new BMessage('Trac')); 861 item->SetTarget(gPCView); 862 addtopbottom(item); 863 } 864 if (!be_roster->IsRunning(kDeskbarSig)) { 865 item = new IconMenuItem(gPCView->fDeskbarIcon, 866 B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar')); 867 item->SetTarget(gPCView); 868 addtopbottom(item); 869 } 870 871 item = new IconMenuItem(gPCView->fTerminalIcon, 872 B_TRANSLATE("New Terminal"), new BMessage('Term')); 873 item->SetTarget(gPCView); 874 addtopbottom(item); 875 876 addtopbottom(new BSeparatorItem()); 877 878 bool showLiveInDeskbarItem = gInDeskbar; 879 if (!showLiveInDeskbarItem) { 880 int32 cookie = 0; 881 image_info info; 882 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 883 if (info.type == B_APP_IMAGE) { 884 // only show the Live in Deskbar item if a) we're running in 885 // deskbar itself, or b) we're running in PC's team. 886 if (strstr(info.name, "ProcessController") != NULL) { 887 showLiveInDeskbarItem = true; 888 break; 889 } 890 } 891 } 892 } 893 894 if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) { 895 item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"), 896 new BMessage('AlDb')); 897 BDeskbar deskbar; 898 item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName)); 899 item->SetTarget(gPCView); 900 addtopbottom(item); 901 addtopbottom(new BSeparatorItem ()); 902 } 903 904 905 item = new IconMenuItem(gPCView->fProcessControllerIcon, 906 B_TRANSLATE("About ProcessController" B_UTF8_ELLIPSIS), 907 new BMessage(B_ABOUT_REQUESTED)); 908 item->SetTarget(gPCView); 909 addtopbottom(item); 910 911 param->where.x -= 5; 912 param->where.y -= 8; 913 popup->Go(param->where, true, true, param->clickToOpenRect); 914 915 delete popup; 916 for (m = 0; m < systemInfo.used_teams; m++) { 917 if (infos[m].team_info.team >= 0) { 918 delete[] infos[m].thread_info; 919 delete infos[m].team_icon; 920 } 921 } 922 delete[] infos; 923 delete param; 924 atomic_add (&gPopupFlag, -1); 925 gPopupThreadID = 0; 926 927 return B_OK; 928 } 929 930 931 status_t 932 thread_quit_application(void *arg) 933 { 934 BMessenger messenger(NULL, (addr_t)arg); 935 messenger.SendMessage(B_QUIT_REQUESTED); 936 return B_OK; 937 } 938 939 940 status_t 941 thread_debug_thread(void *arg) 942 { 943 Tdebug_thead_param* param = (Tdebug_thead_param*) arg; 944 debug_thread(param->thread); 945 delete param; 946 return B_OK; 947 } 948