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