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