diff --git a/Action.c b/Action.c index 4ea6fdfb..c4d71479 100644 --- a/Action.c +++ b/Action.c @@ -37,7 +37,7 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) Settings* settings = st->settings; int y = panel->y; - ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false); + ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, st, false); scr->allowFocusChange = false; ScreenManager_add(scr, list, x - 1); ScreenManager_add(scr, panel, -1); @@ -73,17 +73,17 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) // ---------------------------------------- -static void Action_runSetup(Settings* settings, Header* header, ProcessList* pl) { - ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true); - CategoriesPanel* panelCategories = CategoriesPanel_new(scr, settings, header, pl); +static void Action_runSetup(State* st) { + ScreenManager* scr = ScreenManager_new(0, st->header->height, 0, -1, HORIZONTAL, st->header, st->settings, st, true); + CategoriesPanel* panelCategories = CategoriesPanel_new(scr, st->settings, st->header, st->pl); ScreenManager_add(scr, (Panel*) panelCategories, 16); CategoriesPanel_makeMetersPage(panelCategories); Panel* panelFocus; int ch; ScreenManager_run(scr, &panelFocus, &ch); ScreenManager_delete(scr); - if (settings->changed) { - Header_writeBackToSettings(header); + if (st->settings->changed) { + Header_writeBackToSettings(st->header); } } @@ -168,6 +168,8 @@ static Htop_Reaction sortBy(State* st) { reaction |= Action_setSortKey(st->settings, field->key); } Object_delete(sortPanel); + if (st->pauseProcessUpdate) + ProcessList_sort(st->pl); return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; } @@ -346,7 +348,7 @@ Htop_Reaction Action_follow(State* st) { } static Htop_Reaction actionSetup(State* st) { - Action_runSetup(st->settings, st->header, st->pl); + Action_runSetup(st); // TODO: shouldn't need this, colors should be dynamic int headerHeight = Header_calculateHeight(st->header); Panel_move(st->panel, 0, headerHeight); @@ -392,6 +394,11 @@ static Htop_Reaction actionRedraw(ATTR_UNUSED State *st) { return HTOP_REFRESH | HTOP_REDRAW_BAR; } +static Htop_Reaction actionTogglePauseProcessUpdate(State *st) { + st->pauseProcessUpdate = !st->pauseProcessUpdate; + return HTOP_REFRESH | HTOP_REDRAW_BAR; +} + static const struct { const char* key; const char* info; } helpLeft[] = { { .key = " Arrows: ", .info = "scroll process list" }, { .key = " Digits: ", .info = "incremental PID search" }, @@ -399,6 +406,7 @@ static const struct { const char* key; const char* info; } helpLeft[] = { { .key = " F4 \\: ",.info = "incremental name filtering" }, { .key = " F5 t: ", .info = "tree view" }, { .key = " p: ", .info = "toggle program path" }, + { .key = " Z: ", .info = "pause/resume process updates" }, { .key = " u: ", .info = "show processes of a single user" }, { .key = " H: ", .info = "hide/show user process threads" }, { .key = " K: ", .info = "hide/show kernel threads" }, @@ -491,12 +499,12 @@ static Htop_Reaction actionHelp(State* st) { for (int i = 0; helpLeft[i].key; i++) { mvaddstr(9+i, 0, helpLeft[i].key); } for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); } attrset(CRT_colors[PROCESS_THREAD]); - mvaddstr(16, 32, "threads"); - mvaddstr(17, 26, "threads"); + mvaddstr(17, 32, "threads"); + mvaddstr(18, 26, "threads"); attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[HELP_BOLD]); - mvaddstr(23,0, "Press any key to return."); + mvaddstr(24,0, "Press any key to return."); attrset(CRT_colors[DEFAULT_COLOR]); refresh(); CRT_readKey(); @@ -596,4 +604,5 @@ void Action_setBindings(Htop_Action* keys) { keys['c'] = actionTagAllChildren; keys['e'] = actionShowEnvScreen; keys['w'] = actionShowCommandScreen; + keys['Z'] = actionTogglePauseProcessUpdate; } diff --git a/Action.h b/Action.h index 4f85b481..40300ed4 100644 --- a/Action.h +++ b/Action.h @@ -30,6 +30,7 @@ typedef struct State_ { ProcessList* pl; Panel* panel; Header* header; + bool pauseProcessUpdate; } State; typedef Htop_Reaction (*Htop_Action)(State* st); diff --git a/AffinityPanel.c b/AffinityPanel.c index 0cddd079..82ac12e5 100644 --- a/AffinityPanel.c +++ b/AffinityPanel.c @@ -160,7 +160,7 @@ static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) { Panel* super = (Panel*) this; FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : ""); - FunctionBar_draw(super->currentBar, NULL); + FunctionBar_draw(super->currentBar); int oldSelected = Panel_getSelectedIndex(super); Panel_prune(super); diff --git a/AvailableMetersPanel.c b/AvailableMetersPanel.c index 812d1f3d..b51a9e9f 100644 --- a/AvailableMetersPanel.c +++ b/AvailableMetersPanel.c @@ -29,7 +29,7 @@ static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, c Panel_add(panel, (Object*) Meter_toListItem(meter, false)); Panel_setSelected(panel, Panel_size(panel) - 1); MetersPanel_setMoving((MetersPanel*)panel, true); - FunctionBar_draw(panel->currentBar, NULL); + FunctionBar_draw(panel->currentBar); } static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) { diff --git a/CRT.c b/CRT.c index a9f99545..9159450b 100644 --- a/CRT.c +++ b/CRT.c @@ -87,6 +87,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [PANEL_SELECTION_FOLLOW] = ColorPair(Black,Yellow), [PANEL_SELECTION_UNFOCUS] = ColorPair(Black,White), [FAILED_SEARCH] = ColorPair(Red,Cyan), + [PAUSED] = A_BOLD | ColorPair(Yellow,Cyan), [UPTIME] = A_BOLD | ColorPair(Cyan,Black), [BATTERY] = A_BOLD | ColorPair(Cyan,Black), [LARGE_NUMBER] = A_BOLD | ColorPair(Red,Black), @@ -162,6 +163,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [PANEL_SELECTION_FOLLOW] = A_REVERSE, [PANEL_SELECTION_UNFOCUS] = A_BOLD, [FAILED_SEARCH] = A_REVERSE | A_BOLD, + [PAUSED] = A_BOLD | A_REVERSE, [UPTIME] = A_BOLD, [BATTERY] = A_BOLD, [LARGE_NUMBER] = A_BOLD, @@ -237,6 +239,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [PANEL_SELECTION_FOLLOW] = ColorPair(Black,Yellow), [PANEL_SELECTION_UNFOCUS] = ColorPair(Blue,White), [FAILED_SEARCH] = ColorPair(Red,Cyan), + [PAUSED] = A_BOLD | ColorPair(Yellow,Cyan), [UPTIME] = ColorPair(Yellow,White), [BATTERY] = ColorPair(Yellow,White), [LARGE_NUMBER] = ColorPair(Red,White), @@ -312,6 +315,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [PANEL_SELECTION_FOLLOW] = ColorPair(Black,Yellow), [PANEL_SELECTION_UNFOCUS] = ColorPair(Blue,Black), [FAILED_SEARCH] = ColorPair(Red,Cyan), + [PAUSED] = A_BOLD | ColorPair(Yellow,Cyan), [UPTIME] = ColorPair(Yellow,Black), [BATTERY] = ColorPair(Yellow,Black), [LARGE_NUMBER] = ColorPair(Red,Black), @@ -387,6 +391,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [PANEL_SELECTION_FOLLOW] = ColorPair(Black,Yellow), [PANEL_SELECTION_UNFOCUS] = A_BOLD | ColorPair(Yellow,Blue), [FAILED_SEARCH] = ColorPair(Red,Cyan), + [PAUSED] = A_BOLD | ColorPair(Yellow,Cyan), [UPTIME] = A_BOLD | ColorPair(Yellow,Blue), [BATTERY] = A_BOLD | ColorPair(Yellow,Blue), [LARGE_NUMBER] = A_BOLD | ColorPair(Red,Blue), @@ -461,7 +466,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [PANEL_SELECTION_FOCUS] = ColorPair(Black,Cyan), [PANEL_SELECTION_FOLLOW] = ColorPair(Black,Yellow), [PANEL_SELECTION_UNFOCUS] = ColorPair(Black,White), - [FAILED_SEARCH] = ColorPair(Red,Cyan), + [FAILED_SEARCH] = ColorPair(Red,Green), + [PAUSED] = A_BOLD | ColorPair(Yellow,Green), [UPTIME] = ColorPair(Green,Black), [BATTERY] = ColorPair(Green,Black), [LARGE_NUMBER] = A_BOLD | ColorPair(Red,Black), diff --git a/CRT.h b/CRT.h index e729fb3c..629a8097 100644 --- a/CRT.h +++ b/CRT.h @@ -43,6 +43,7 @@ typedef enum ColorElements_ { FUNCTION_BAR, FUNCTION_KEY, FAILED_SEARCH, + PAUSED, PANEL_HEADER_FOCUS, PANEL_HEADER_UNFOCUS, PANEL_SELECTION_FOCUS, diff --git a/ColorsPanel.c b/ColorsPanel.c index 75d3e654..917be98c 100644 --- a/ColorsPanel.c +++ b/ColorsPanel.c @@ -68,7 +68,7 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) { clear(); Panel* menu = (Panel*) Vector_get(this->scr->panels, 0); Header_draw(header); - FunctionBar_draw(super->currentBar, NULL); + FunctionBar_draw(super->currentBar); RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]); RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]); ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2); diff --git a/FunctionBar.c b/FunctionBar.c index df1fab8f..c67e613c 100644 --- a/FunctionBar.c +++ b/FunctionBar.c @@ -24,6 +24,8 @@ static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_ static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL}; static const int FunctionBar_EnterEscEvents[] = {13, 27}; +static int currentLen = 0; + FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) { const char* functions[] = {enter, esc, NULL}; return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents); @@ -53,7 +55,7 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke this->staticData = true; this->keys.constKeys = FunctionBar_FKeys; this->events = FunctionBar_FEvents; - this->size = 10; + this->size = ARRAYSIZE(FunctionBar_FEvents); } return this; } @@ -83,11 +85,11 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { } } -void FunctionBar_draw(const FunctionBar* this, char* buffer) { - FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]); +void FunctionBar_draw(const FunctionBar* this) { + FunctionBar_drawExtra(this, NULL, -1, false); } -void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) { +void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) { attrset(CRT_colors[FUNCTION_BAR]); mvhline(LINES-1, 0, ' ', COLS); int x = 0; @@ -99,15 +101,36 @@ void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) { mvaddstr(LINES-1, x, this->functions[i]); x += strlen(this->functions[i]); } + if (buffer) { - attrset(attr); + if (attr == -1) + attrset(CRT_colors[FUNCTION_BAR]); + else + attrset(attr); mvaddstr(LINES-1, x, buffer); - CRT_cursorX = x + strlen(buffer); + attrset(CRT_colors[RESET_COLOR]); + x += strlen(buffer); + } + + if (setCursor) { + CRT_cursorX = x; curs_set(1); } else { curs_set(0); } + + currentLen = x; +} + +void FunctionBar_append(const char* buffer, int attr) { + if (attr == -1) + attrset(CRT_colors[FUNCTION_BAR]); + else + attrset(attr); + mvaddstr(LINES-1, currentLen, buffer); attrset(CRT_colors[RESET_COLOR]); + + currentLen += strlen(buffer); } int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) { diff --git a/FunctionBar.h b/FunctionBar.h index c650c1a4..925e323b 100644 --- a/FunctionBar.h +++ b/FunctionBar.h @@ -28,9 +28,11 @@ void FunctionBar_delete(FunctionBar* this); void FunctionBar_setLabel(FunctionBar* this, int event, const char* text); -void FunctionBar_draw(const FunctionBar* this, char* buffer); +void FunctionBar_draw(const FunctionBar* this); -void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr); +void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor); + +void FunctionBar_append(const char* buffer, int attr); int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos); diff --git a/IncSet.c b/IncSet.c index 3e3a1b99..9dda3ce1 100644 --- a/IncSet.c +++ b/IncSet.c @@ -95,10 +95,11 @@ static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelVa break; } } - if (found) - FunctionBar_draw(mode->bar, mode->buffer); - else - FunctionBar_drawAttr(mode->bar, mode->buffer, CRT_colors[FAILED_SEARCH]); + + FunctionBar_drawExtra(mode->bar, + mode->buffer, + found ? -1 : CRT_colors[FAILED_SEARCH], + true); return found; } @@ -177,7 +178,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue } this->active = NULL; Panel_setDefaultBar(panel); - FunctionBar_draw(this->defaultBar, NULL); + FunctionBar_draw(this->defaultBar); doSearch = false; } if (doSearch) { @@ -198,15 +199,15 @@ const char* IncSet_getListItemValue(Panel* panel, int i) { void IncSet_activate(IncSet* this, IncType type, Panel* panel) { this->active = &(this->modes[type]); - FunctionBar_draw(this->active->bar, this->active->buffer); + FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true); panel->currentBar = this->active->bar; } -void IncSet_drawBar(IncSet* this) { +void IncSet_drawBar(const IncSet* this) { if (this->active) { - FunctionBar_draw(this->active->bar, this->active->buffer); + FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true); } else { - FunctionBar_draw(this->defaultBar, NULL); + FunctionBar_draw(this->defaultBar); } } diff --git a/IncSet.h b/IncSet.h index 30b63665..f0589747 100644 --- a/IncSet.h +++ b/IncSet.h @@ -54,7 +54,7 @@ const char* IncSet_getListItemValue(Panel* panel, int i); void IncSet_activate(IncSet* this, IncType type, Panel* panel); -void IncSet_drawBar(IncSet* this); +void IncSet_drawBar(const IncSet* this); int IncSet_synthesizeEvent(IncSet* this, int x); diff --git a/MainPanel.c b/MainPanel.c index 2c89a073..48d869ff 100644 --- a/MainPanel.c +++ b/MainPanel.c @@ -92,6 +92,8 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { if (reaction & HTOP_REDRAW_BAR) { MainPanel_updateTreeFunctions(this, this->state->settings->treeView); IncSet_drawBar(this->inc); + if (this->state->pauseProcessUpdate) + FunctionBar_append("PAUSED", CRT_colors[PAUSED]); } if (reaction & HTOP_UPDATE_PANELHDR) { ProcessList_printHeader(this->state->pl, Panel_getHeader(super)); diff --git a/MetersPanel.c b/MetersPanel.c index 36cc8f45..89c54e0b 100644 --- a/MetersPanel.c +++ b/MetersPanel.c @@ -55,7 +55,7 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) { Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]); super->currentBar = Meters_movingBar; } - FunctionBar_draw(this->super.currentBar, NULL); + FunctionBar_draw(this->super.currentBar); } static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) { diff --git a/ScreenManager.c b/ScreenManager.c index 91ad47f8..4766e069 100644 --- a/ScreenManager.c +++ b/ScreenManager.c @@ -6,10 +6,12 @@ in the source distribution for its full text. */ #include "ScreenManager.h" + +#include "CRT.h" +#include "MainPanel.h" +#include "Object.h" #include "ProcessList.h" -#include "Object.h" -#include "CRT.h" #include #include @@ -17,7 +19,7 @@ in the source distribution for its full text. #include -ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, Header* header, const Settings* settings, bool owner) { +ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, Header* header, const Settings* settings, const State* state, bool owner) { ScreenManager* this; this = xMalloc(sizeof(ScreenManager)); this->x1 = x1; @@ -29,6 +31,7 @@ ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation ori this->panelCount = 0; this->header = header; this->settings = settings; + this->state = state; this->owner = owner; this->allowFocusChange = true; return this; @@ -101,7 +104,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi *timedOut = (newTime - *oldTime > this->settings->delay); *rescan = *rescan || *timedOut; if (newTime < *oldTime) *rescan = true; // clock was adjusted? - if (*rescan) { + if (*rescan && !this->state->pauseProcessUpdate) { *oldTime = newTime; ProcessList_scan(pl); if (*sortTimeout == 0 || this->settings->treeView) { @@ -128,8 +131,11 @@ static void ScreenManager_drawPanels(ScreenManager* this, int focus) { } } -static Panel* setCurrentPanel(Panel* panel) { - FunctionBar_draw(panel->currentBar, NULL); +static Panel* setCurrentPanel(const ScreenManager* this, Panel* panel) { + FunctionBar_draw(panel->currentBar); + if (panel == this->state->panel && this->state->pauseProcessUpdate) + FunctionBar_append("PAUSED", CRT_colors[PAUSED]); + return panel; } @@ -137,7 +143,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { bool quit = false; int focus = 0; - Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); + Panel* panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus)); double oldTime = 0.0; @@ -183,7 +189,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { ch = KEY_MOUSE; if (panel == panelFocus || this->allowFocusChange) { focus = i; - panelFocus = setCurrentPanel(panel); + panelFocus = setCurrentPanel(this, panel); Object* oldSelection = Panel_getSelected(panel); Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1); if (Panel_getSelected(panel) == oldSelection) { @@ -259,7 +265,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { tryLeft: if (focus > 0) focus--; - panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); + panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus)); if (Panel_size(panelFocus) == 0 && focus > 0) goto tryLeft; break; @@ -274,7 +280,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { tryRight: if (focus < this->panelCount - 1) focus++; - panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); + panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus)); if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) goto tryRight; break; diff --git a/ScreenManager.h b/ScreenManager.h index 722fb7f2..ad312930 100644 --- a/ScreenManager.h +++ b/ScreenManager.h @@ -7,9 +7,10 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ +#include "Action.h" #include "Header.h" -#include "Settings.h" #include "Panel.h" +#include "Settings.h" #include "Vector.h" typedef enum Orientation_ { @@ -27,11 +28,12 @@ typedef struct ScreenManager_ { int panelCount; Header* header; const Settings* settings; + const State* state; bool owner; bool allowFocusChange; } ScreenManager; -ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, Header* header, const Settings* settings, bool owner); +ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, Header* header, const Settings* settings, const State* state, bool owner); void ScreenManager_delete(ScreenManager* this); diff --git a/htop.1.in b/htop.1.in index cd5562b6..3e95c201 100644 --- a/htop.1.in +++ b/htop.1.in @@ -209,6 +209,9 @@ userspace processes in the process list. (This is a toggle key.) .B p Show full paths to running programs, where applicable. (This is a toggle key.) .TP +.B Z +Pause/resume process updates. +.TP .B Ctrl-L Refresh: redraw screen and recalculate values. .TP diff --git a/htop.c b/htop.c index 8d17de9b..44182ae1 100644 --- a/htop.c +++ b/htop.c @@ -283,6 +283,7 @@ int main(int argc, char** argv) { .pl = pl, .panel = (Panel*) panel, .header = header, + .pauseProcessUpdate = false, }; MainPanel_setState(panel, &state); @@ -290,7 +291,7 @@ int main(int argc, char** argv) { setCommFilter(&state, &(flags.commFilter)); } - ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true); + ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, &state, true); ScreenManager_add(scr, (Panel*) panel, -1); ProcessList_scan(pl);