diff --git a/Action.c b/Action.c index 84d0864f..e4f7cbea 100644 --- a/Action.c +++ b/Action.c @@ -26,6 +26,7 @@ in the source distribution for its full text. #include #include #include +#include #include #include #include @@ -80,7 +81,7 @@ Object* Action_pickFromVector(State* st, Panel* list, int x) { header->pl->following = pid; unfollow = true; } - ScreenManager_run(scr, &panelFocus, &ch); + ScreenManager_run(scr, &panelFocus, &ch, NULL); if (unfollow) { header->pl->following = -1; } @@ -106,7 +107,7 @@ static void Action_runSetup(Settings* settings, const Header* header, ProcessLis CategoriesPanel_makeMetersPage(panelCategories); Panel* panelFocus; int ch; - ScreenManager_run(scr, &panelFocus, &ch); + ScreenManager_run(scr, &panelFocus, &ch, "Setup"); ScreenManager_delete(scr); if (settings->changed) { Header_writeBackToSettings(header); @@ -307,14 +308,33 @@ static Htop_Reaction actionNextScreen(State* st) { static Htop_Reaction actionPrevScreen(State* st) { Settings* settings = st->settings; - settings->ssIndex--; - if (settings->ssIndex == -1) { + if (settings->ssIndex == 0) { settings->ssIndex = settings->nScreens - 1; + } else { + settings->ssIndex--; } settings->ss = settings->screens[settings->ssIndex]; return HTOP_REFRESH; } +Htop_Reaction Action_setScreenTab(Settings* settings, int x) { + int s = 2; + for (unsigned int i = 0; i < settings->nScreens; i++) { + if (x < s) { + return 0; + } + const char* name = settings->screens[i]->name; + int len = strlen(name); + if (x <= s + len + 1) { + settings->ssIndex = i; + settings->ss = settings->screens[i]; + return HTOP_REFRESH; + } + s += len + 3; + } + return 0; +} + static Htop_Reaction actionSetAffinity(State* st) { if (st->pl->cpuCount == 1) return HTOP_OK; diff --git a/Action.h b/Action.h index 1dfdcb47..7f55eb24 100644 --- a/Action.h +++ b/Action.h @@ -49,6 +49,8 @@ Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey); // ---------------------------------------- +Htop_Reaction Action_setScreenTab(Settings* settings, int x); + Htop_Reaction Action_follow(State* st); diff --git a/CRT.c b/CRT.c index 15d3c808..90596f64 100644 --- a/CRT.c +++ b/CRT.c @@ -130,6 +130,10 @@ typedef enum ColorElements_ { CPU_STEAL, CPU_GUEST, PANEL_EDIT, + SCREENS_OTH_BORDER, + SCREENS_OTH_TEXT, + SCREENS_CUR_BORDER, + SCREENS_CUR_TEXT, LAST_COLORELEMENT } ColorElements; @@ -235,6 +239,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_STEAL] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black), [PANEL_EDIT] = ColorPair(White,Blue), + [SCREENS_OTH_BORDER] = ColorPair(Blue,Blue), + [SCREENS_OTH_TEXT] = ColorPair(Black,Blue), + [SCREENS_CUR_BORDER] = ColorPair(Green,Green), + [SCREENS_CUR_TEXT] = ColorPair(Black,Green), }, [COLORSCHEME_MONOCHROME] = { [RESET_COLOR] = A_NORMAL, @@ -295,6 +303,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_STEAL] = A_REVERSE, [CPU_GUEST] = A_REVERSE, [PANEL_EDIT] = A_BOLD, + [SCREENS_OTH_BORDER] = A_DIM, + [SCREENS_OTH_TEXT] = A_DIM, + [SCREENS_CUR_BORDER] = A_REVERSE, + [SCREENS_CUR_TEXT] = A_REVERSE, }, [COLORSCHEME_BLACKONWHITE] = { [RESET_COLOR] = ColorPair(Black,White), @@ -355,6 +367,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_STEAL] = ColorPair(Cyan,White), [CPU_GUEST] = ColorPair(Cyan,White), [PANEL_EDIT] = ColorPair(White,Blue), + [SCREENS_OTH_BORDER] = A_BOLD | ColorPair(Black,White), + [SCREENS_OTH_TEXT] = A_BOLD | ColorPair(Black,White), + [SCREENS_CUR_BORDER] = ColorPair(Green,Green), + [SCREENS_CUR_TEXT] = ColorPair(Black,Green), }, [COLORSCHEME_LIGHTTERMINAL] = { [RESET_COLOR] = ColorPair(Black,Black), @@ -415,6 +431,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_STEAL] = ColorPair(Black,Black), [CPU_GUEST] = ColorPair(Black,Black), [PANEL_EDIT] = ColorPair(White,Blue), + [SCREENS_OTH_BORDER] = ColorPair(Blue,Black), + [SCREENS_OTH_TEXT] = ColorPair(Blue,Black), + [SCREENS_CUR_BORDER] = ColorPair(Green,Green), + [SCREENS_CUR_TEXT] = ColorPair(Black,Green), }, [COLORSCHEME_MIDNIGHT] = { [RESET_COLOR] = ColorPair(White,Blue), @@ -475,6 +495,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_STEAL] = ColorPair(White,Blue), [CPU_GUEST] = ColorPair(White,Blue), [PANEL_EDIT] = ColorPair(White,Blue), + [SCREENS_OTH_BORDER] = A_BOLD | ColorPair(Yellow,Blue), + [SCREENS_OTH_TEXT] = ColorPair(Cyan,Blue), + [SCREENS_CUR_BORDER] = ColorPair(Cyan,Cyan), + [SCREENS_CUR_TEXT] = ColorPair(Black,Cyan), }, [COLORSCHEME_BLACKNIGHT] = { [RESET_COLOR] = ColorPair(Cyan,Black), @@ -535,6 +559,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_STEAL] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black), [PANEL_EDIT] = ColorPair(White,Cyan), + [SCREENS_OTH_BORDER] = ColorPair(White,Black), + [SCREENS_OTH_TEXT] = ColorPair(Cyan,Black), + [SCREENS_CUR_BORDER] = A_BOLD | ColorPair(White,Black), + [SCREENS_CUR_TEXT] = A_BOLD | ColorPair(Green,Black), }, [COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated. }; diff --git a/CRT.h b/CRT.h index fb9e00a1..06a5fccb 100644 --- a/CRT.h +++ b/CRT.h @@ -118,6 +118,10 @@ typedef enum ColorElements_ { CPU_STEAL, CPU_GUEST, PANEL_EDIT, + SCREENS_OTH_BORDER, + SCREENS_OTH_TEXT, + SCREENS_CUR_BORDER, + SCREENS_CUR_TEXT, LAST_COLORELEMENT } ColorElements; diff --git a/CategoriesPanel.c b/CategoriesPanel.c index 9cab3e96..b8855d40 100644 --- a/CategoriesPanel.c +++ b/CategoriesPanel.c @@ -145,7 +145,7 @@ CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Hea this->settings = settings; this->header = header; this->pl = pl; - Panel_setHeader(super, "Setup"); + Panel_setHeader(super, "Categories"); Panel_add(super, (Object*) ListItem_new("Meters", 0)); Panel_add(super, (Object*) ListItem_new("Display options", 0)); Panel_add(super, (Object*) ListItem_new("Colors", 0)); diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index c3b1e746..cad250a7 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -96,5 +96,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero))); Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames))); Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter))); + Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show tabs for screens"), &(settings->screenTabs))); return this; } diff --git a/Header.c b/Header.c index 2193e980..42fa7ffc 100644 --- a/Header.c +++ b/Header.c @@ -211,6 +211,9 @@ int Header_calculateHeight(Header* this) { } maxHeight = MAX(maxHeight, height); } + if (this->settings->screenTabs) { + maxHeight++; + } this->height = maxHeight; this->pad = pad; return maxHeight; diff --git a/MainPanel.c b/MainPanel.c index 51953d8f..c625efdf 100644 --- a/MainPanel.c +++ b/MainPanel.c @@ -88,6 +88,10 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { } reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS; result = HANDLED; + } else if (EVENT_IS_SCREEN_TAB_CLICK(ch)) { + int x = EVENT_SCREEN_TAB_GET_X(ch); + reaction |= Action_setScreenTab(settings, x); + result = HANDLED; } else if (ch != ERR && this->inc->active) { bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL); if (filterChanged) { diff --git a/Panel.c b/Panel.c index e9d69ecb..09513777 100644 --- a/Panel.c +++ b/Panel.c @@ -40,8 +40,12 @@ typedef enum HandlerResult_ { #define EVENT_SET_SELECTED -1 #define EVENT_HEADER_CLICK(x_) (-10000 + x_) -#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000) #define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000) +#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ < -9000) + +#define EVENT_SCREEN_TAB_CLICK(x_) (-20000 + x_) +#define EVENT_SCREEN_TAB_GET_X(ev_) (ev_ + 20000) +#define EVENT_IS_SCREEN_TAB_CLICK(ev_) (ev_ >= -20000 && ev_ < -10000) typedef HandlerResult(*Panel_EventHandler)(Panel*, int); diff --git a/Panel.h b/Panel.h index 1ebeedf7..e9066489 100644 --- a/Panel.h +++ b/Panel.h @@ -29,8 +29,12 @@ typedef enum HandlerResult_ { #define EVENT_SET_SELECTED -1 #define EVENT_HEADER_CLICK(x_) (-10000 + x_) -#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000) #define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000) +#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ < -9000) + +#define EVENT_SCREEN_TAB_CLICK(x_) (-20000 + x_) +#define EVENT_SCREEN_TAB_GET_X(ev_) (ev_ + 20000) +#define EVENT_IS_SCREEN_TAB_CLICK(ev_) (ev_ >= -20000 && ev_ < -10000) typedef HandlerResult(*Panel_EventHandler)(Panel*, int); diff --git a/ScreenManager.c b/ScreenManager.c index 081d887a..9a979f7a 100644 --- a/ScreenManager.c +++ b/ScreenManager.c @@ -13,6 +13,7 @@ in the source distribution for its full text. #include #include +#include #include #include @@ -35,6 +36,7 @@ typedef struct ScreenManager_ { int y2; Orientation orientation; Vector* panels; + const char* name; int panelCount; const Header* header; const Settings* settings; @@ -160,7 +162,50 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi *rescan = false; } +static inline bool drawTab(int* y, int* x, int l, const char* name, bool cur) { + attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]); + mvaddch(*y, *x, '['); + (*x)++; + if (*x >= l) return false; + int nameLen = strlen(name); + int n = MIN(l - *x, nameLen); + attrset(CRT_colors[cur ? SCREENS_CUR_TEXT : SCREENS_OTH_TEXT]); + mvaddnstr(*y, *x, name, n); + *x += n; + if (*x >= l) return false; + attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]); + mvaddch(*y, *x, ']'); + *x += 2; + if (*x >= l) return false; + return true; +} + +static void ScreenManager_drawScreenTabs(ScreenManager* this) { + ScreenSettings** screens = this->settings->screens; + int cur = this->settings->ssIndex; + int l = COLS; + Panel* panel = (Panel*) Vector_get(this->panels, 0); + int y = panel->y - 1; + int x = 2; + + if (this->name) { + drawTab(&y, &x, l, this->name, true); + return; + } + + for (int s = 0; screens[s]; s++) { + bool ok = drawTab(&y, &x, l, screens[s]->name, s == cur); + if (!ok) { + break; + } + } + attrset(CRT_colors[RESET_COLOR]); +} + static void ScreenManager_drawPanels(ScreenManager* this, int focus) { + if (this->settings->screenTabs) { + ScreenManager_drawScreenTabs(this); + } int nPanels = this->panelCount; for (int i = 0; i < nPanels; i++) { Panel* panel = (Panel*) Vector_get(this->panels, i); @@ -179,7 +224,7 @@ static Panel* setCurrentPanel(ScreenManager* this, int focus) { return panel; } -void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { +void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, char* name) { bool quit = false; int focus = 0; @@ -195,6 +240,8 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { bool rescan = false; int sortTimeout = 0; int resetSortTimeout = 5; + + this->name = name; while (!quit) { if (this->header) { @@ -224,6 +271,9 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { if (mevent.y == panel->y) { ch = EVENT_HEADER_CLICK(mevent.x - panel->x); break; + } else if (this->settings->screenTabs && mevent.y == panel->y - 1) { + ch = EVENT_SCREEN_TAB_CLICK(mevent.x); + break; } else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) { ch = KEY_MOUSE; if (panel == panelFocus || this->allowFocusChange) { diff --git a/ScreenManager.h b/ScreenManager.h index ebaf0bf6..1be3c161 100644 --- a/ScreenManager.h +++ b/ScreenManager.h @@ -27,6 +27,7 @@ typedef struct ScreenManager_ { int y2; Orientation orientation; Vector* panels; + const char* name; int panelCount; const Header* header; const Settings* settings; @@ -49,6 +50,6 @@ Panel* ScreenManager_remove(ScreenManager* this, int idx); void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2); -void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey); +void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, char* name); #endif diff --git a/ScreensPanel.c b/ScreensPanel.c index 47ec62b0..c3ba2b74 100644 --- a/ScreensPanel.c +++ b/ScreensPanel.c @@ -149,6 +149,7 @@ static void rebuildSettingsArray(Panel* super) { ScreenListItem* item = (ScreenListItem*) Panel_get(super, i); this->settings->screens[i] = item->ss; } + this->settings->nScreens = n; } static void addNewScreen(Panel* super) { diff --git a/Settings.c b/Settings.c index 2d96f568..66340ad8 100644 --- a/Settings.c +++ b/Settings.c @@ -73,6 +73,7 @@ typedef struct Settings_ { bool updateProcessNames; bool accountGuestInCPUMeter; bool headerMargin; + bool screenTabs; bool changed; } Settings; @@ -267,6 +268,7 @@ ScreenSettings* Settings_newScreen(Settings* this, const char* name, const char* ss->direction = 1; ss->treeView = 0; readFields(ss->fields, &(ss->flags), line); + ss->sortKey = ss->fields[0]; this->screens[this->nScreens] = ss; this->nScreens++; this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1)); @@ -331,6 +333,8 @@ static bool Settings_read(Settings* this, const char* fileName) { this->highlightThreads = atoi(option[1]); } else if (String_eq(option[0], "header_margin")) { this->headerMargin = atoi(option[1]); + } else if (String_eq(option[0], "screen_tabs")) { + this->screenTabs = atoi(option[1]); } else if (String_eq(option[0], "expand_system_time")) { // Compatibility option. this->detailedCPUTime = atoi(option[1]); @@ -443,6 +447,7 @@ bool Settings_write(Settings* this) { fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes); fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads); fprintf(fd, "header_margin=%d\n", (int) this->headerMargin); + fprintf(fd, "screen_tabs=%d\n", (int) this->screenTabs); fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime); fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero); fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames); @@ -559,6 +564,7 @@ Settings* Settings_new(int cpuCount) { this->highlightMegabytes = true; this->highlightThreads = true; this->headerMargin = true; + this->screenTabs = true; } this->ssIndex = 0; diff --git a/Settings.h b/Settings.h index 22729aa9..cddbdee7 100644 --- a/Settings.h +++ b/Settings.h @@ -64,6 +64,7 @@ typedef struct Settings_ { bool updateProcessNames; bool accountGuestInCPUMeter; bool headerMargin; + bool screenTabs; bool changed; } Settings; diff --git a/darwin/Platform.c b/darwin/Platform.c index 16c89585..60e71429 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -38,7 +38,7 @@ typedef enum DarwinProcessFields { ScreenDefaults Platform_defaultScreens[] = { { - .name = "Default", + .name = "Main", .columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command", .sortKey = "PERCENT_CPU", }, diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c index 716c99e7..3103e910 100644 --- a/dragonflybsd/Platform.c +++ b/dragonflybsd/Platform.c @@ -42,7 +42,7 @@ extern ProcessFieldData Process_fields[]; ScreenDefaults Platform_defaultScreens[] = { { - .name = "Default", + .name = "Main", .columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command", .sortKey = "PERCENT_CPU", }, diff --git a/freebsd/Platform.c b/freebsd/Platform.c index eb7164a7..369f7789 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -41,7 +41,7 @@ extern ProcessFieldData Process_fields[]; ScreenDefaults Platform_defaultScreens[] = { { - .name = "Default", + .name = "Main", .columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command", .sortKey = "PERCENT_CPU", }, diff --git a/htop.c b/htop.c index e7940427..df218abb 100644 --- a/htop.c +++ b/htop.c @@ -237,7 +237,7 @@ int main(int argc, char** argv) { millisleep(75); ProcessList_scan(pl); - ScreenManager_run(scr, NULL, NULL); + ScreenManager_run(scr, NULL, NULL, NULL); attron(CRT_colors[RESET_COLOR]); mvhline(LINES-1, 0, ' ', COLS); diff --git a/linux/Platform.c b/linux/Platform.c index cfaa0f14..e9468c6e 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -84,7 +84,7 @@ const SignalItem Platform_signals[] = { ScreenDefaults Platform_defaultScreens[] = { { - .name = "Default", + .name = "Main", .columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command", .sortKey = "PERCENT_CPU", }, diff --git a/openbsd/Platform.c b/openbsd/Platform.c index 34aa6aad..06c48b79 100644 --- a/openbsd/Platform.c +++ b/openbsd/Platform.c @@ -98,7 +98,7 @@ static int percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_ ScreenDefaults Platform_defaultScreens[] = { { - .name = "Default", + .name = "Main", .columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command", .sortKey = "PERCENT_CPU", }, diff --git a/unsupported/Platform.c b/unsupported/Platform.c index f487c497..259a1af8 100644 --- a/unsupported/Platform.c +++ b/unsupported/Platform.c @@ -31,7 +31,7 @@ const unsigned int Platform_numberOfSignals = sizeof(Platform_signals)/sizeof(Si ScreenDefaults Platform_defaultScreens[] = { { - .name = "Default", + .name = "Main", .columns = "PID LWPID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command", .sortKey = "PERCENT_CPU", },