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