/* * Copyright 2000, Georges-Edouard Berenger. All rights reserved. * Copyright 2006-2018, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #include "ProcessController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AutoIcon.h" #include "Colors.h" #include "IconMenuItem.h" #include "MemoryBarMenu.h" #include "MemoryBarMenuItem.h" #include "PCWorld.h" #include "Preferences.h" #include "QuitMenu.h" #include "TeamBarMenu.h" #include "TeamBarMenuItem.h" #include "ThreadBarMenu.h" #include "Utilities.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "ProcessController" const char* kDeskbarItemName = "ProcessController"; const char* kClassName = "ProcessController"; const char* kFrameColorPref = "deskbar_frame_color"; const char* kIdleColorPref = "deskbar_idle_color"; const char* kActiveColorPref = "deskbar_active_color"; static const char* const kDebuggerSignature = "application/x-vnd.Haiku-Debugger"; const rgb_color kKernelBlue = {20, 20, 231, 255}; const rgb_color kIdleGreen = {110, 190,110, 255}; ProcessController* gPCView; uint32 gCPUcount; rgb_color gUserColor; rgb_color gUserColorSelected; rgb_color gIdleColor; rgb_color gIdleColorSelected; rgb_color gKernelColor; rgb_color gKernelColorSelected; rgb_color gFrameColor; rgb_color gFrameColorSelected; rgb_color gMenuBackColorSelected; rgb_color gMenuBackColor; rgb_color gWhiteSelected; ThreadBarMenu* gCurrentThreadBarMenu; bool gInDeskbar = false; #define addtopbottom(x) if (top) popup->AddItem(x); else popup->AddItem(x, 0) status_t thread_popup(void *arg); int32 gPopupFlag = 0; thread_id gPopupThreadID = 0; typedef struct { BPoint where; BRect clickToOpenRect; bool top; } Tpopup_param; #define DEBUG_THREADS 1 status_t thread_quit_application(void *arg); status_t thread_debug_thread(void *arg); typedef struct { thread_id thread; sem_id sem; time_t totalTime; } Tdebug_thead_param; // Bar layout depending on number of CPUs // This is used only in case the replicant width is 16 typedef struct { float cpu_width; float cpu_inter; float mem_width; } layoutT; layoutT layout[] = { { 1, 1, 1 }, { 5, 1, 5 }, // 1 { 3, 1, 4 }, // 2 { 2, 1, 3 }, { 2, 0, 3 }, // 4 }; extern "C" _EXPORT BView* instantiate_deskbar_item(float maxWidth, float maxHeight); extern "C" _EXPORT BView* instantiate_deskbar_item(float maxWidth, float maxHeight) { gInDeskbar = true; system_info info; get_system_info(&info); int width = 4; if (info.cpu_count > 4) width = info.cpu_count; if (info.cpu_count <= 16) width *= 2; // For the memory bar width += 8; // Damn, you got a lot of CPU if (width > maxWidth) width = (int)maxWidth; return new ProcessController(width - 1, maxHeight - 1); } // #pragma mark - ProcessController::ProcessController(BRect frame, bool temp) : BView(frame, kDeskbarItemName, B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), fProcessControllerIcon(kSignature), fProcessorIcon(k_cpu_mini), fTrackerIcon(kTrackerSig), fDeskbarIcon(kDeskbarSig), fTerminalIcon(kTerminalSig), kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), fTemp(temp), fLastBarHeight(new float[kCPUCount]), fCPUTimes(new double[kCPUCount]), fPrevActive(new bigtime_t[kCPUCount]) { if (!temp) { Init(); frame.OffsetTo(B_ORIGIN); frame.top = frame.bottom - 7; frame.left = frame.right - 7; BDragger* dragger = new BDragger(frame, this, B_FOLLOW_BOTTOM); AddChild(dragger); } } ProcessController::ProcessController(BMessage *data) : BView(data), fProcessControllerIcon(kSignature), fProcessorIcon(k_cpu_mini), fTrackerIcon(kTrackerSig), fDeskbarIcon(kDeskbarSig), fTerminalIcon(kTerminalSig), kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), fTemp(false), fLastBarHeight(new float[kCPUCount]), fCPUTimes(new double[kCPUCount]), fPrevActive(new bigtime_t[kCPUCount]) { Init(); } ProcessController::ProcessController(float width, float height) : BView(BRect (0, 0, width, height), kDeskbarItemName, B_FOLLOW_NONE, B_WILL_DRAW), fProcessControllerIcon(kSignature), fProcessorIcon(k_cpu_mini), fTrackerIcon(kTrackerSig), fDeskbarIcon(kDeskbarSig), fTerminalIcon(kTerminalSig), kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), fTemp(false), fLastBarHeight(new float[kCPUCount]), fCPUTimes(new double[kCPUCount]), fPrevActive(new bigtime_t[kCPUCount]) { Init(); } ProcessController::~ProcessController() { if (!fTemp) { if (gPopupThreadID) { status_t return_value; wait_for_thread (gPopupThreadID, &return_value); } } delete fMessageRunner; gPCView = NULL; delete[] fPrevActive; delete[] fCPUTimes; delete[] fLastBarHeight; } void ProcessController::Init() { memset(fLastBarHeight, 0, sizeof(float) * kCPUCount); memset(fCPUTimes, 0, sizeof(double) * kCPUCount); memset(fPrevActive, 0, sizeof(bigtime_t) * kCPUCount); gPCView = this; fMessageRunner = NULL; fLastMemoryHeight = 0; fPrevTime = 0; } void ProcessController::_HandleDebugRequest(team_id team, thread_id thread) { char paramString[16]; char idString[16]; strlcpy(paramString, thread > 0 ? "--thread" : "--team", sizeof(paramString)); snprintf(idString, sizeof(idString), "%" B_PRId32, thread > 0 ? thread : team); const char* argv[] = {paramString, idString, NULL}; status_t error = be_roster->Launch(kDebuggerSignature, 2, argv); if (error != B_OK) { // TODO: notify user } } ProcessController* ProcessController::Instantiate(BMessage *data) { if (!validate_instantiation(data, kClassName)) return NULL; return new ProcessController(data); } status_t ProcessController::Archive(BMessage *data, bool deep) const { BView::Archive(data, deep); data->AddString("add_on", kSignature); data->AddString("class", kClassName); return B_OK; } void ProcessController::MessageReceived(BMessage *message) { team_id team; thread_id thread; BAlert *alert; char question[1000]; switch (message->what) { case 'Puls': Update (); DoDraw (false); break; case 'QtTm': if (message->FindInt32("team", &team) == B_OK) { resume_thread(spawn_thread(thread_quit_application, B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY, (void*)(addr_t)team)); } break; case 'KlTm': if (message->FindInt32("team", &team) == B_OK) { info_pack infos; if (get_team_info(team, &infos.team_info) == B_OK) { get_team_name_and_icon(infos); snprintf(question, sizeof(question), B_TRANSLATE("What do you want to do with the team \"%s\"?"), infos.team_name); alert = new BAlert(B_TRANSLATE("Please confirm"), question, B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this team!"), B_TRANSLATE("Kill this team!"), B_WIDTH_AS_USUAL, B_STOP_ALERT); alert->SetShortcut(0, B_ESCAPE); int result = alert->Go(); switch (result) { case 1: _HandleDebugRequest(team, -1); break; case 2: kill_team(team); break; default: break; } } else { alert = new BAlert(B_TRANSLATE("Info"), B_TRANSLATE("This team is already gone" B_UTF8_ELLIPSIS), B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); } } break; case 'KlTh': if (message->FindInt32("thread", &thread) == B_OK) { thread_info thinfo; if (get_thread_info(thread, &thinfo) == B_OK) { #if DEBUG_THREADS snprintf(question, sizeof(question), B_TRANSLATE("What do you want to do " "with the thread \"%s\"?"), thinfo.name); alert = new BAlert(B_TRANSLATE("Please confirm"), question, B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"), B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL, B_STOP_ALERT); alert->SetShortcut(0, B_ESCAPE); #define KILL 2 #else snprintf(question, sizeof(question), B_TRANSLATE("Are you sure you want " "to kill the thread \"%s\"?"), thinfo.name); alert = new BAlert(B_TRANSLATE("Please confirm"), question, B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"), NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); alert->SetShortcut(0, B_ESCAPE); #define KILL 1 #endif alert->SetShortcut(0, B_ESCAPE); int r = alert->Go(); if (r == KILL) kill_thread(thread); #if DEBUG_THREADS else if (r == 1) _HandleDebugRequest(thinfo.team, thinfo.thread); #endif } else { alert = new BAlert(B_TRANSLATE("Info"), B_TRANSLATE("This thread is already gone" B_UTF8_ELLIPSIS), B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); } } break; case 'PrTh': if (message->FindInt32("thread", &thread) == B_OK) { int32 new_priority; if (message->FindInt32("priority", &new_priority) == B_OK) set_thread_priority(thread, new_priority); } break; case 'Trac': { BPath trackerPath; if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK && trackerPath.Append("Tracker") == B_OK) { launch(kTrackerSig, trackerPath.Path()); } break; } case 'Dbar': { BPath deskbarPath; if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK && deskbarPath.Append("Deskbar") == B_OK) { launch(kDeskbarSig, deskbarPath.Path()); } break; } case 'Term': { BPath terminalPath; if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK && terminalPath.Append("Terminal") == B_OK) { launch(kTerminalSig, terminalPath.Path()); } break; } case 'AlDb': { if (!be_roster->IsRunning(kDeskbarSig)) { BPath deskbarPath; if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK && deskbarPath.Append("Deskbar") == B_OK) { launch(kDeskbarSig, deskbarPath.Path()); } } BDeskbar deskbar; if (gInDeskbar || deskbar.HasItem (kDeskbarItemName)) deskbar.RemoveItem (kDeskbarItemName); else move_to_deskbar(deskbar); break; } case 'CPU ': { uint32 cpu; if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) { bool last = true; for (unsigned int p = 0; p < gCPUcount; p++) { if (p != cpu && _kern_cpu_enabled(p)) { last = false; break; } } if (last) { alert = new BAlert(B_TRANSLATE("Info"), B_TRANSLATE("This is the last active processor" B_UTF8_ELLIPSIS "\n" "You can't turn it off!"), B_TRANSLATE("That's no Fun!"), NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); } else _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu)); } break; } case 'Schd': { BMenuItem* source; if (message->FindPointer("source", (void**)&source) != B_OK) break; if (!source->IsMarked()) set_scheduler_mode(SCHEDULER_MODE_POWER_SAVING); else set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY); break; } case B_ABOUT_REQUESTED: AboutRequested(); break; default: BView::MessageReceived(message); } } void ProcessController::AboutRequested() { BAboutWindow* window = new BAboutWindow( B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature); const char* extraCopyrights[] = { "2004 beunited.org", "1997-2001 Georges-Edouard Berenger", NULL }; const char* authors[] = { "Georges-Edouard Berenger", NULL }; window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights); window->AddAuthors(authors); window->Show(); } void ProcessController::DefaultColors() { swap_color.red = 203; swap_color.green = 0; swap_color.blue = 0; swap_color.alpha = 255; bool set = false; if (!set) { active_color = kKernelBlue; active_color = tint_color (active_color, B_LIGHTEN_2_TINT); idle_color = active_color; idle_color.green /= 3; idle_color.red /= 3; idle_color.blue /= 3; frame_color = kBlack; mix_colors (memory_color, active_color, swap_color, 0.2); } } void ProcessController::AttachedToWindow() { BView::AttachedToWindow(); if (Parent()) SetViewColor(B_TRANSPARENT_COLOR); else SetViewColor(kBlack); Preferences tPreferences(kPreferencesFileName, NULL, false); DefaultColors(); system_info info; get_system_info(&info); gCPUcount = info.cpu_count; Update(); gIdleColor = kIdleGreen; gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT); gKernelColor = kKernelBlue; gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT); gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT); gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT); gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_HIGHLIGHT_BACKGROUND_TINT); gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT); gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR); gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR); gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT); BMessenger messenger(this); BMessage message('Puls'); fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1); } void ProcessController::MouseDown(BPoint where) { if (atomic_add(&gPopupFlag, 1) > 0) { atomic_add(&gPopupFlag, -1); return; } Tpopup_param* param = new Tpopup_param; ConvertToScreen(&where); param->where = where; param->clickToOpenRect = Frame (); ConvertToScreen (¶m->clickToOpenRect); param->top = where.y < BScreen(this->Window()).Frame().bottom-50; gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread", B_URGENT_DISPLAY_PRIORITY, param); resume_thread(gPopupThreadID); } void ProcessController::Draw(BRect) { SetDrawingMode(B_OP_COPY); DoDraw(true); } void ProcessController::DoDraw(bool force) { BRect bounds(Bounds()); float h = floorf(bounds.Height ()) - 2; float top = 1, left = 1; float bottom = top + h; float barWidth; float barGap; float memWidth; if (gCPUcount <= 4 && bounds.Width() == 15) { // Use fixed sizes for small CPU counts barWidth = layout[gCPUcount].cpu_width; barGap = layout[gCPUcount].cpu_inter; memWidth = layout[gCPUcount].mem_width; } else { memWidth = floorf((bounds.Height() + 1) / 8); barGap = ((bounds.Width() + 1) / gCPUcount) > 3 ? 1 : 0; barWidth = floorf((bounds.Width() - 1 - memWidth - barGap * gCPUcount) / gCPUcount); } // interspace float right = left + gCPUcount * (barWidth + barGap) - barGap; float leftMem = bounds.Width() - memWidth; // right of CPU frame... if (force && Parent()) { SetHighColor(Parent()->ViewColor()); FillRect(BRect(right + 1, top - 1, leftMem, bottom + 1)); } if (force) { SetHighColor(frame_color); StrokeRect(BRect(left - 1, top - 1, right, bottom + 1)); if (gCPUcount > 1 && barGap == 1) { for (unsigned int x = 1; x < gCPUcount; x++) StrokeLine(BPoint(left + x * barWidth + x - 1, top), BPoint(left + x * barWidth + x - 1, bottom)); } } if (force) StrokeRect(BRect(leftMem - 1, top - 1, leftMem + memWidth, bottom + 1)); for (unsigned int x = 0; x < gCPUcount; x++) { right = left + barWidth - 1; float rem = fCPUTimes[x] * (h + 1); float barHeight = floorf (rem); rem -= barHeight; float limit = bottom - barHeight; // horizontal line float previousLimit = bottom - fLastBarHeight[x]; float idleTop = top; if (!force && previousLimit > top) idleTop = previousLimit - 1; if (limit > idleTop) { SetHighColor(idle_color); FillRect(BRect(left, idleTop, right, limit - 1)); } if (barHeight <= h) { rgb_color fraction_color; mix_colors(fraction_color, idle_color, active_color, rem); SetHighColor(fraction_color); StrokeLine(BPoint(left, bottom - barHeight), BPoint(right, bottom - barHeight)); } float active_bottom = bottom; if (!force && previousLimit < bottom) active_bottom = previousLimit + 1; if (limit < active_bottom) { SetHighColor(active_color); FillRect(BRect(left, limit + 1, right, active_bottom)); } left += barWidth + barGap; fLastBarHeight[x] = barHeight; } float rightMem = bounds.Width() - 1; float rem = fMemoryUsage * (h + 1); float barHeight = floorf(rem); rem -= barHeight; rgb_color used_memory_color; float sq = fMemoryUsage * fMemoryUsage; sq *= sq; sq *= sq; mix_colors(used_memory_color, memory_color, swap_color, sq); float limit = bottom - barHeight; // horizontal line float previousLimit = bottom - fLastMemoryHeight; float free_top = top; if (!force && previousLimit > top) free_top = previousLimit - 1; if (limit > free_top) { SetHighColor (idle_color); FillRect(BRect(leftMem, free_top, rightMem, limit - 1)); } if (barHeight <= h) { rgb_color fraction_color; mix_colors(fraction_color, idle_color, used_memory_color, rem); SetHighColor(fraction_color); StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem, bottom - barHeight)); } float usedBottom = bottom; // if (!force && previousLimit < bottom) // usedBottom = previousLimit + 1; if (limit < usedBottom) { SetHighColor(used_memory_color); FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom)); } fLastMemoryHeight = barHeight; } void ProcessController::Update() { system_info info; get_system_info(&info); bigtime_t now = system_time(); cpu_info* cpuInfos = new cpu_info[gCPUcount]; get_cpu_info(0, gCPUcount, cpuInfos); fMemoryUsage = float(info.used_pages) / float(info.max_pages); // Calculate work done since last call to Update() for each CPU for (unsigned int x = 0; x < gCPUcount; x++) { bigtime_t load = cpuInfos[x].active_time - fPrevActive[x]; bigtime_t passed = now - fPrevTime; float cpuTime = float(load) / float(passed); fPrevActive[x] = cpuInfos[x].active_time; if (load > passed) fPrevActive[x] -= load - passed; // save overload for next period... if (cpuTime < 0) cpuTime = 0; if (cpuTime > 1) cpuTime = 1; fCPUTimes[x] = cpuTime; } fPrevTime = now; delete[] cpuInfos; } // #pragma mark - status_t thread_popup(void *arg) { Tpopup_param* param = (Tpopup_param*) arg; int32 mcookie, hcookie; unsigned long m; long h; BMenuItem* item; bool top = param->top; system_info systemInfo; get_system_info(&systemInfo); info_pack* infos = new info_pack[systemInfo.used_teams]; // TODO: this doesn't necessarily get all teams for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) { infos[m].team_icon = NULL; infos[m].team_name[0] = 0; infos[m].thread_info = NULL; if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) { infos[m].thread_info = new thread_info[infos[m].team_info.thread_count]; for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) { if (get_next_thread_info(infos[m].team_info.team, &hcookie, &infos[m].thread_info[h]) != B_OK) infos[m].thread_info[h].thread = -1; } get_team_name_and_icon(infos[m], true); } else { systemInfo.used_teams = m; infos[m].team_info.team = -1; } } BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false); popup->SetFont(be_plain_font); // Quit section BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"), infos, systemInfo.used_teams); QuitPopup->SetFont(be_plain_font); popup->AddItem(QuitPopup); // Memory Usage section MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"), infos, systemInfo); int64 committedMemory = (int64)systemInfo.used_pages * B_PAGE_SIZE / 1024; for (m = 0; m < systemInfo.used_teams; m++) { if (infos[m].team_info.team >= 0) { MemoryBarMenuItem* memoryItem = new MemoryBarMenuItem(infos[m].team_name, infos[m].team_info.team, infos[m].team_icon, false, NULL); MemoryPopup->AddItem(memoryItem); memoryItem->UpdateSituation(committedMemory); } } addtopbottom(MemoryPopup); // CPU Load section TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU " "usage"), infos, systemInfo.used_teams); for (m = 0; m < systemInfo.used_teams; m++) { if (infos[m].team_info.team >= 0) { ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name, infos[m].team_info.team, infos[m].team_info.thread_count); BMessage* kill_team = new BMessage('KlTm'); kill_team->AddInt32("team", infos[m].team_info.team); TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team, infos[m].team_info.team, infos[m].team_icon, false); item->SetTarget(gPCView); CPUPopup->AddItem(item); } } addtopbottom(CPUPopup); addtopbottom(new BSeparatorItem()); // CPU on/off section if (gCPUcount > 1) { for (unsigned int i = 0; i < gCPUcount; i++) { char item_name[32]; sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1); BMessage* m = new BMessage ('CPU '); m->AddInt32 ("cpu", i); item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m); if (_kern_cpu_enabled(i)) item->SetMarked (true); item->SetTarget(gPCView); addtopbottom(item); } addtopbottom (new BSeparatorItem ()); } // Scheduler modes int32 currentMode = get_scheduler_mode(); BMessage* msg = new BMessage('Schd'); item = new BMenuItem(B_TRANSLATE("Power saving"), msg); if ((uint32)currentMode == SCHEDULER_MODE_POWER_SAVING) item->SetMarked(true); item->SetTarget(gPCView); addtopbottom(item); addtopbottom(new BSeparatorItem()); if (!be_roster->IsRunning(kTrackerSig)) { item = new IconMenuItem(gPCView->fTrackerIcon, B_TRANSLATE("Restart Tracker"), new BMessage('Trac')); item->SetTarget(gPCView); addtopbottom(item); } if (!be_roster->IsRunning(kDeskbarSig)) { item = new IconMenuItem(gPCView->fDeskbarIcon, B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar')); item->SetTarget(gPCView); addtopbottom(item); } item = new IconMenuItem(gPCView->fTerminalIcon, B_TRANSLATE("New Terminal"), new BMessage('Term')); item->SetTarget(gPCView); addtopbottom(item); addtopbottom(new BSeparatorItem()); bool showLiveInDeskbarItem = gInDeskbar; if (!showLiveInDeskbarItem) { int32 cookie = 0; image_info info; while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { if (info.type == B_APP_IMAGE) { // only show the Live in Deskbar item if a) we're running in // deskbar itself, or b) we're running in PC's team. if (strstr(info.name, "ProcessController") != NULL) { showLiveInDeskbarItem = true; break; } } } } if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) { item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"), new BMessage('AlDb')); BDeskbar deskbar; item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName)); item->SetTarget(gPCView); addtopbottom(item); addtopbottom(new BSeparatorItem ()); } item = new IconMenuItem(gPCView->fProcessControllerIcon, B_TRANSLATE("About ProcessController" B_UTF8_ELLIPSIS), new BMessage(B_ABOUT_REQUESTED)); item->SetTarget(gPCView); addtopbottom(item); param->where.x -= 5; param->where.y -= 8; popup->Go(param->where, true, true, param->clickToOpenRect); delete popup; for (m = 0; m < systemInfo.used_teams; m++) { if (infos[m].team_info.team >= 0) { delete[] infos[m].thread_info; delete infos[m].team_icon; } } delete[] infos; delete param; atomic_add (&gPopupFlag, -1); gPopupThreadID = 0; return B_OK; } status_t thread_quit_application(void *arg) { BMessenger messenger(NULL, (addr_t)arg); messenger.SendMessage(B_QUIT_REQUESTED); return B_OK; } status_t thread_debug_thread(void *arg) { Tdebug_thead_param* param = (Tdebug_thead_param*) arg; debug_thread(param->thread); delete param; return B_OK; }