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