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