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