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