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