diff --git a/Action.c b/Action.c index 1cb59aa0..dc830b57 100644 --- a/Action.c +++ b/Action.c @@ -156,9 +156,10 @@ static bool expandCollapse(Panel* panel) { } Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) { - settings->sortKey = sortKey; - settings->direction = 1; - settings->treeView = false; + ScreenSettings* ss = settings->ss; + ss->sortKey = sortKey; + ss->direction = 1; + ss->treeView = false; return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING; } @@ -166,11 +167,12 @@ static Htop_Reaction sortBy(State* st) { Htop_Reaction reaction = HTOP_OK; Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel ")); Panel_setHeader(sortPanel, "Sort by"); - ProcessField* fields = st->settings->fields; + ScreenSettings* ss = st->settings->ss; + ProcessField* fields = ss->fields; for (int i = 0; fields[i]; i++) { char* name = String_trim(Process_fields[fields[i]].name); Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i])); - if (fields[i] == st->settings->sortKey) + if (fields[i] == ss->sortKey) Panel_setSelected(sortPanel, i); free(name); } @@ -219,8 +221,9 @@ static Htop_Reaction actionToggleProgramPath(State* st) { } static Htop_Reaction actionToggleTreeView(State* st) { - st->settings->treeView = !st->settings->treeView; - if (st->settings->treeView) st->settings->direction = 1; + ScreenSettings* ss = st->settings->ss; + ss->treeView = !ss->treeView; + if (ss->treeView) ss->direction = 1; ProcessList_expandTree(st->pl); return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; } @@ -248,7 +251,7 @@ static Htop_Reaction actionLowerPriority(State* st) { } static Htop_Reaction actionInvertSortOrder(State* st) { - Settings_invertSortOrder(st->settings); + ScreenSettings_invertSortOrder(st->settings->ss); return HTOP_REFRESH | HTOP_SAVE_SETTINGS; } @@ -262,13 +265,23 @@ static Htop_Reaction actionExpandOrCollapse(State* st) { } static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) { - return st->settings->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st); + return st->settings->ss->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st); } static Htop_Reaction actionQuit() { return HTOP_QUIT; } +static Htop_Reaction actionNextScreen(State* st) { + Settings* settings = st->settings; + settings->ssIndex++; + if (settings->ssIndex == settings->nScreens) { + settings->ssIndex = 0; + } + settings->ss = settings->screens[settings->ssIndex]; + return HTOP_REFRESH; +} + static Htop_Reaction actionSetAffinity(State* st) { if (st->pl->cpuCount == 1) return HTOP_OK; @@ -572,5 +585,6 @@ void Action_setBindings(Htop_Action* keys) { keys['U'] = actionUntagAll; keys['c'] = actionTagAllChildren; keys['e'] = actionShowEnvScreen; + keys['\t'] = actionNextScreen; } diff --git a/CategoriesPanel.c b/CategoriesPanel.c index 64e9933a..9cab3e96 100644 --- a/CategoriesPanel.c +++ b/CategoriesPanel.c @@ -10,7 +10,6 @@ in the source distribution for its full text. #include "AvailableMetersPanel.h" #include "MetersPanel.h" #include "DisplayOptionsPanel.h" -#include "ColumnsPanel.h" #include "ScreensPanel.h" #include "ColorsPanel.h" #include "AvailableColumnsPanel.h" @@ -67,7 +66,7 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) { static void CategoriesPanel_makeScreensPage(CategoriesPanel* this) { Panel* screens = (Panel*) ScreensPanel_new(this->settings); - Panel* columns = (Panel*) ColumnsPanel_new(this->settings); + Panel* columns = (Panel*) ((ScreensPanel*)screens)->columns; Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns); ScreenManager_add(this->scr, screens, 20); ScreenManager_add(this->scr, columns, 20); diff --git a/ColumnsPanel.c b/ColumnsPanel.c index 8974ffdc..60bd56db 100644 --- a/ColumnsPanel.c +++ b/ColumnsPanel.c @@ -22,8 +22,9 @@ in the source distribution for its full text. typedef struct ColumnsPanel_ { Panel super; + ScreenSettings* ss; + bool* changed; - Settings* settings; bool moving; } ColumnsPanel; @@ -123,22 +124,31 @@ PanelClass ColumnsPanel_class = { .eventHandler = ColumnsPanel_eventHandler }; -ColumnsPanel* ColumnsPanel_new(Settings* settings) { - ColumnsPanel* this = AllocThis(ColumnsPanel); +void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss) { Panel* super = (Panel*) this; - FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL); - Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); - - this->settings = settings; - this->moving = false; - Panel_setHeader(super, "Active Columns"); - - ProcessField* fields = this->settings->fields; + Panel_prune(super); + ProcessField* fields = ss->fields; for (; *fields; fields++) { if (Process_fields[*fields].name) { Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields)); } } + this->ss = ss; +} + +ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed) { + ColumnsPanel* this = AllocThis(ColumnsPanel); + Panel* super = (Panel*) this; + FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL); + Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); + + this->ss = ss; + this->changed = changed; + this->moving = false; + Panel_setHeader(super, "Active Columns"); + + ColumnsPanel_fill(this, ss); + return this; } @@ -154,14 +164,14 @@ int ColumnsPanel_fieldNameToIndex(const char* name) { void ColumnsPanel_update(Panel* super) { ColumnsPanel* this = (ColumnsPanel*) super; int size = Panel_size(super); - this->settings->changed = true; - this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size+1)); - this->settings->flags = 0; + *(this->changed) = true; + this->ss->fields = xRealloc(this->ss->fields, sizeof(ProcessField) * (size+1)); + this->ss->flags = 0; for (int i = 0; i < size; i++) { int key = ((ListItem*) Panel_get(super, i))->key; - this->settings->fields[i] = key; - this->settings->flags |= Process_fields[key].flags; + this->ss->fields[i] = key; + this->ss->flags |= key < 1000 ? Process_fields[key].flags : 0; } - this->settings->fields[size] = 0; + this->ss->fields[size] = 0; } diff --git a/ColumnsPanel.h b/ColumnsPanel.h index 0da674a8..054880c1 100644 --- a/ColumnsPanel.h +++ b/ColumnsPanel.h @@ -14,15 +14,18 @@ in the source distribution for its full text. typedef struct ColumnsPanel_ { Panel super; + ScreenSettings* ss; + bool* changed; - Settings* settings; bool moving; } ColumnsPanel; extern PanelClass ColumnsPanel_class; -ColumnsPanel* ColumnsPanel_new(Settings* settings); +void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss); + +ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed); int ColumnsPanel_fieldNameToIndex(const char* name); diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index 0ff54e33..c3b1e746 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -83,7 +83,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* this->scr = scr; Panel_setHeader(super, "Display options"); - Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Tree view"), &(settings->treeView))); Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Shadow other users' processes"), &(settings->shadowOtherUsers))); Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide kernel threads"), &(settings->hideKernelThreads))); Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads))); diff --git a/Header.c b/Header.c index e048ee55..2193e980 100644 --- a/Header.c +++ b/Header.c @@ -62,7 +62,7 @@ void Header_delete(Header* this) { void Header_populateFromSettings(Header* this) { Header_forEachColumn(this, col) { - MeterColumnSettings* colSettings = &this->settings->columns[col]; + MeterColumnSettings* colSettings = &this->settings->meterColumns[col]; for (int i = 0; i < colSettings->len; i++) { Header_addMeterByName(this, colSettings->names[i], col); if (colSettings->modes[i] != 0) { @@ -75,7 +75,7 @@ void Header_populateFromSettings(Header* this) { void Header_writeBackToSettings(const Header* this) { Header_forEachColumn(this, col) { - MeterColumnSettings* colSettings = &this->settings->columns[col]; + MeterColumnSettings* colSettings = &this->settings->meterColumns[col]; String_freeArray(colSettings->names); free(colSettings->modes); diff --git a/ListItem.c b/ListItem.c index 05c5c0b3..55c73433 100644 --- a/ListItem.c +++ b/ListItem.c @@ -27,13 +27,13 @@ typedef struct ListItem_ { }*/ -static void ListItem_delete(Object* cast) { +void ListItem_delete(Object* cast) { ListItem* this = (ListItem*)cast; free(this->value); free(this); } -static void ListItem_display(Object* cast, RichString* out) { +void ListItem_display(Object* cast, RichString* out) { ListItem* const this = (ListItem*)cast; assert (this != NULL); /* @@ -59,11 +59,15 @@ ObjectClass ListItem_class = { .compare = ListItem_compare }; -ListItem* ListItem_new(const char* value, int key) { - ListItem* this = AllocThis(ListItem); +void ListItem_init(ListItem* this, const char* value, int key) { this->value = xStrdup(value); this->key = key; this->moving = false; +} + +ListItem* ListItem_new(const char* value, int key) { + ListItem* this = AllocThis(ListItem); + ListItem_init(this, value, key); return this; } diff --git a/ListItem.h b/ListItem.h index b48f0acd..ba159502 100644 --- a/ListItem.h +++ b/ListItem.h @@ -19,8 +19,14 @@ typedef struct ListItem_ { } ListItem; +void ListItem_delete(Object* cast); + +void ListItem_display(Object* cast, RichString* out); + extern ObjectClass ListItem_class; +void ListItem_init(ListItem* this, const char* value, int key); + ListItem* ListItem_new(const char* value, int key); void ListItem_append(ListItem* this, const char* text); diff --git a/MainPanel.c b/MainPanel.c index 25023367..51953d8f 100644 --- a/MainPanel.c +++ b/MainPanel.c @@ -72,15 +72,17 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { Htop_Reaction reaction = HTOP_OK; + Settings* settings = this->state->settings; + ScreenSettings* ss = settings->ss; + if (EVENT_IS_HEADER_CLICK(ch)) { int x = EVENT_HEADER_CLICK_GET_X(ch); ProcessList* pl = this->state->pl; - Settings* settings = this->state->settings; int hx = super->scrollH + x + 1; ProcessField field = ProcessList_keyAt(pl, hx); - if (field == settings->sortKey) { - Settings_invertSortOrder(settings); - settings->treeView = false; + if (field == ss->sortKey) { + ScreenSettings_invertSortOrder(ss); + ss->treeView = false; } else { reaction |= Action_setSortKey(settings, field); } @@ -113,8 +115,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); + MainPanel_updateTreeFunctions(this, settings->ss->treeView); + IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]); } if (reaction & HTOP_UPDATE_PANELHDR) { ProcessList_printHeader(this->state->pl, Panel_getHeader(super)); diff --git a/Process.c b/Process.c index 845ca54b..f36822c5 100644 --- a/Process.c +++ b/Process.c @@ -399,7 +399,8 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { attr = CRT_colors[PROCESS_THREAD]; baseattr = CRT_colors[PROCESS_THREAD_BASENAME]; } - if (!this->settings->treeView || this->indent == 0) { + ScreenSettings* ss = this->settings->ss; + if (!ss->treeView || this->indent == 0) { Process_writeCommand(this, attr, baseattr, str); return; } else { @@ -420,7 +421,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { buf += written; n -= written; } - const char* draw = CRT_treeStr[lastItem ? (this->settings->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE]; + const char* draw = CRT_treeStr[lastItem ? (ss->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE]; xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] ); RichString_append(str, CRT_colors[PROCESS_TREE], buffer); Process_writeCommand(this, attr, baseattr, str); @@ -491,7 +492,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { void Process_display(Object* cast, RichString* out) { Process* this = (Process*) cast; - ProcessField* fields = this->settings->fields; + ProcessField* fields = this->settings->ss->fields; RichString_prune(out); for (int i = 0; fields[i]; i++) As_Process(this)->writeField(this, out, fields[i]); @@ -561,14 +562,15 @@ long Process_pidCompare(const void* v1, const void* v2) { long Process_compare(const void* v1, const void* v2) { Process *p1, *p2; Settings *settings = ((Process*)v1)->settings; - if (settings->direction == 1) { + ScreenSettings* ss = settings->ss; + if (ss->direction == 1) { p1 = (Process*)v1; p2 = (Process*)v2; } else { p2 = (Process*)v1; p1 = (Process*)v2; } - switch (settings->sortKey) { + switch (ss->sortKey) { case PERCENT_CPU: return (p2->percent_cpu > p1->percent_cpu ? 1 : -1); case PERCENT_MEM: diff --git a/ProcessList.c b/ProcessList.c index 48b2d955..5b6a98f3 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -124,14 +124,15 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) { void ProcessList_printHeader(ProcessList* this, RichString* header) { RichString_prune(header); - ProcessField* fields = this->settings->fields; + ProcessField* fields = this->settings->ss->fields; for (int i = 0; fields[i]; i++) { - const char* field = Process_fields[fields[i]].title; + unsigned int key = fields[i]; + const char* field = Process_fields[key].title; if (!field) field = "- "; - if (!this->settings->treeView && this->settings->sortKey == fields[i]) - RichString_append(header, CRT_colors[PANEL_SELECTION_FOCUS], field); - else - RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field); + int color = (!this->settings->ss->treeView && this->settings->ss->sortKey == key) + ? CRT_colors[PANEL_SELECTION_FOCUS] + : CRT_colors[PANEL_HEADER_FOCUS]; + RichString_append(header, color, field); } } @@ -200,19 +201,19 @@ static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int i } void ProcessList_sort(ProcessList* this) { - if (!this->settings->treeView) { + if (!this->settings->ss->treeView) { Vector_insertionSort(this->processes); } else { // Save settings - int direction = this->settings->direction; - int sortKey = this->settings->sortKey; + int direction = this->settings->ss->direction; + int sortKey = this->settings->ss->sortKey; // Sort by PID - this->settings->sortKey = PID; - this->settings->direction = 1; + this->settings->ss->sortKey = PID; + this->settings->ss->direction = 1; Vector_quickSort(this->processes); // Restore settings - this->settings->sortKey = sortKey; - this->settings->direction = direction; + this->settings->ss->sortKey = sortKey; + this->settings->ss->direction = direction; int vsize = Vector_size(this->processes); // Find all processes whose parent is not visible int size; @@ -271,7 +272,7 @@ void ProcessList_sort(ProcessList* this) { ProcessField ProcessList_keyAt(ProcessList* this, int at) { int x = 0; - ProcessField* fields = this->settings->fields; + ProcessField* fields = this->settings->ss->fields; ProcessField field; for (int i = 0; (field = fields[i]); i++) { const char* title = Process_fields[field].title; diff --git a/ScreenManager.c b/ScreenManager.c index 1a93ae00..081d887a 100644 --- a/ScreenManager.c +++ b/ScreenManager.c @@ -71,30 +71,46 @@ inline int ScreenManager_size(ScreenManager* this) { } void ScreenManager_add(ScreenManager* this, Panel* item, int size) { + ScreenManager_insert(this, item, size, Vector_size(this->panels)); +} + +void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx) { if (this->orientation == HORIZONTAL) { int lastX = 0; - if (this->panelCount > 0) { - Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1); + if (idx > 0) { + Panel* last = (Panel*) Vector_get(this->panels, idx - 1); lastX = last->x + last->w + 1; } int height = LINES - this->y1 + this->y2; - if (size > 0) { - Panel_resize(item, size, height); - } else { - Panel_resize(item, COLS-this->x1+this->x2-lastX, height); + if (size <= 0) { + size = COLS-this->x1+this->x2-lastX; } + Panel_resize(item, size, height); Panel_move(item, lastX, this->y1); + if (idx < this->panelCount) { + for (int i = idx + 1; i <= this->panelCount; i++) { + Panel* p = (Panel*) Vector_get(this->panels, i); + Panel_move(p, p->x + size, p->y); + } + } } // TODO: VERTICAL - Vector_add(this->panels, item); + Vector_insert(this->panels, idx, item); item->needsRedraw = true; this->panelCount++; } Panel* ScreenManager_remove(ScreenManager* this, int idx) { assert(this->panelCount > idx); + int w = ((Panel*) Vector_get(this->panels, idx))->w; Panel* panel = (Panel*) Vector_remove(this->panels, idx); this->panelCount--; + if (idx < this->panelCount) { + for (int i = idx; i < this->panelCount; i++) { + Panel* p = (Panel*) Vector_get(this->panels, i); + Panel_move(p, p->x - w, p->y); + } + } return panel; } @@ -131,7 +147,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi if (*rescan) { *oldTime = newTime; ProcessList_scan(pl); - if (*sortTimeout == 0 || this->settings->treeView) { + if (*sortTimeout == 0 || this->settings->ss->treeView) { ProcessList_sort(pl); *sortTimeout = 1; } diff --git a/ScreenManager.h b/ScreenManager.h index 3d02a883..ebaf0bf6 100644 --- a/ScreenManager.h +++ b/ScreenManager.h @@ -43,6 +43,8 @@ extern int ScreenManager_size(ScreenManager* this); void ScreenManager_add(ScreenManager* this, Panel* item, int size); +void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx); + Panel* ScreenManager_remove(ScreenManager* this, int idx); void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2); diff --git a/ScreensPanel.c b/ScreensPanel.c index 6c88035a..19ac96bd 100644 --- a/ScreensPanel.c +++ b/ScreensPanel.c @@ -9,7 +9,6 @@ in the source distribution for its full text. #include "Platform.h" #include "StringUtils.h" -#include "ListItem.h" #include "CRT.h" #include @@ -19,7 +18,10 @@ in the source distribution for its full text. /*{ #include "Panel.h" +#include "ScreenManager.h" +#include "ColumnsPanel.h" #include "Settings.h" +#include "ListItem.h" #ifndef SCREEN_NAME_LEN #define SCREEN_NAME_LEN 20 @@ -27,8 +29,10 @@ in the source distribution for its full text. typedef struct ScreensPanel_ { Panel super; - + + ScreenManager* scr; Settings* settings; + ColumnsPanel* columns; char buffer[SCREEN_NAME_LEN + 1]; char* saved; int cursor; @@ -36,9 +40,27 @@ typedef struct ScreensPanel_ { bool renaming; } ScreensPanel; +typedef struct ScreenListItem_ { + ListItem super; + ScreenSettings* ss; +} ScreenListItem; + }*/ -static const char* const ScreensFunctions[] = {" ", "Rename", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL}; +ObjectClass ScreenListItem_class = { + .display = ListItem_display, + .delete = ListItem_delete, + .compare = ListItem_compare +}; + +ScreenListItem* ScreenListItem_new(const char* value, int key, ScreenSettings* ss) { + ScreenListItem* this = AllocThis(ScreenListItem); + ListItem_init((ListItem*)this, value, key); + this->ss = ss; + return this; +} + +static const char* const ScreensFunctions[] = {" ", "Rename", " ", " ", "New ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL}; static void ScreensPanel_delete(Object* object) { Panel* super = (Panel*) object; @@ -81,6 +103,7 @@ static HandlerResult ScreensPanel_eventHandlerRenaming(Panel* super, int ch) { this->renaming = false; super->cursorOn = false; Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]); + ScreensPanel_update(super); break; } case 27: // Esc @@ -94,11 +117,10 @@ static HandlerResult ScreensPanel_eventHandlerRenaming(Panel* super, int ch) { } } } - ScreensPanel_update(super); return HANDLED; } -void startRenaming(Panel* super) { +static void startRenaming(Panel* super) { ScreensPanel* const this = (ScreensPanel*) super; ListItem* item = (ListItem*) Panel_getSelected(super); @@ -115,10 +137,25 @@ void startRenaming(Panel* super) { Panel_setCursorToSelection(super); } +static void rebuildSettingsArray(Panel* super) { + ScreensPanel* const this = (ScreensPanel*) super; + + int n = Panel_size(super); + free(this->settings->screens); + this->settings->screens = xMalloc(sizeof(ScreenSettings*) * (n + 1)); + this->settings->screens[n] = NULL; + for (int i = 0; i < n; i++) { + ScreenListItem* item = (ScreenListItem*) Panel_get(super, i); + this->settings->screens[i] = item->ss; + } +} + static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { ScreensPanel* const this = (ScreensPanel*) super; int selected = Panel_getSelectedIndex(super); + ScreenListItem* oldFocus = (ScreenListItem*) Panel_getSelected(super); + bool shouldRebuildArray = false; HandlerResult result = IGNORED; switch(ch) { case 0x0a: @@ -133,27 +170,39 @@ static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { result = HANDLED; break; } + case EVENT_SET_SELECTED: + result = HANDLED; + break; + case KEY_NPAGE: + case KEY_PPAGE: + case KEY_HOME: + case KEY_END: { + Panel_onKey(super, ch); + break; + } case KEY_F(2): - case 0x12: /* Ctrl+R */ + case KEY_CTRL('R'): { startRenaming(super); result = HANDLED; break; } case KEY_F(5): - case 0x0e: /* Ctrl+N */ + case KEY_CTRL('N'): { ListItem* item = ListItem_new("", 0); int idx = Panel_getSelectedIndex(super); Panel_insert(super, idx + 1, (Object*) item); Panel_setSelected(super, idx + 1); startRenaming(super); + shouldRebuildArray = true; result = HANDLED; break; } case KEY_UP: { if (!this->moving) { + Panel_onKey(super, ch); break; } /* else fallthrough */ @@ -163,12 +212,14 @@ static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { case '-': { Panel_moveSelectedUp(super); + shouldRebuildArray = true; result = HANDLED; break; } case KEY_DOWN: { if (!this->moving) { + Panel_onKey(super, ch); break; } /* else fallthrough */ @@ -178,13 +229,17 @@ static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { case '+': { Panel_moveSelectedDown(super); + shouldRebuildArray = true; result = HANDLED; break; } case KEY_F(9): //case KEY_DC: { - Panel_remove(super, selected); + if (Panel_size(super) > 1) { + Panel_remove(super, selected); + } + shouldRebuildArray = true; result = HANDLED; break; } @@ -197,6 +252,14 @@ static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { break; } } + ScreenListItem* newFocus = (ScreenListItem*) Panel_getSelected(super); + if (oldFocus != newFocus) { + ColumnsPanel_fill(this->columns, newFocus->ss); + result = HANDLED; + } + if (shouldRebuildArray) { + rebuildSettingsArray(super); + } if (result == HANDLED) ScreensPanel_update(super); return result; @@ -227,16 +290,17 @@ ScreensPanel* ScreensPanel_new(Settings* settings) { Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); this->settings = settings; + this->columns = ColumnsPanel_new(settings->screens[0], &(settings->changed)); this->moving = false; this->renaming = false; super->cursorOn = false; this->cursor = 0; Panel_setHeader(super, "Screens"); - char** screens = this->settings->screens; - for (; *screens; screens++) { - char* name = *screens; - Panel_add(super, (Object*) ListItem_new(name, 0)); + for (unsigned int i = 0; i < settings->nScreens; i++) { + ScreenSettings* ss = settings->screens[i]; + char* name = ss->name; + Panel_add(super, (Object*) ScreenListItem_new(name, i, ss)); } return this; } @@ -248,7 +312,7 @@ void ScreensPanel_update(Panel* super) { this->settings->screens = xRealloc(this->settings->screens, sizeof(char*) * (size+1)); for (int i = 0; i < size; i++) { char* name = ((ListItem*) Panel_get(super, i))->value; - this->settings->screens[i] = xStrdup(name); + this->settings->screens[i]->name = xStrdup(name); } this->settings->screens[size] = NULL; } diff --git a/ScreensPanel.h b/ScreensPanel.h index 35842a95..f1c80647 100644 --- a/ScreensPanel.h +++ b/ScreensPanel.h @@ -10,7 +10,10 @@ in the source distribution for its full text. */ #include "Panel.h" +#include "ScreenManager.h" +#include "ColumnsPanel.h" #include "Settings.h" +#include "ListItem.h" #ifndef SCREEN_NAME_LEN #define SCREEN_NAME_LEN 20 @@ -18,8 +21,10 @@ in the source distribution for its full text. typedef struct ScreensPanel_ { Panel super; - + + ScreenManager* scr; Settings* settings; + ColumnsPanel* columns; char buffer[SCREEN_NAME_LEN + 1]; char* saved; int cursor; @@ -27,8 +32,15 @@ typedef struct ScreensPanel_ { bool renaming; } ScreensPanel; +typedef struct ScreenListItem_ { + ListItem super; + ScreenSettings* ss; +} ScreenListItem; -void startRenaming(Panel* super); + +extern ObjectClass ScreenListItem_class; + +ScreenListItem* ScreenListItem_new(const char* value, int key, ScreenSettings* ss); extern PanelClass ScreensPanel_class; diff --git a/Settings.c b/Settings.c index 663a24dc..84671a71 100644 --- a/Settings.c +++ b/Settings.c @@ -29,26 +29,33 @@ typedef struct { int* modes; } MeterColumnSettings; +typedef struct { + char* name; + ProcessField* fields; + int flags; + int direction; + ProcessField sortKey; + bool treeView; +} ScreenSettings; + typedef struct Settings_ { char* filename; - MeterColumnSettings columns[2]; + MeterColumnSettings meterColumns[2]; - char** screens; - int nScreens; + ScreenSettings** screens; + unsigned int nScreens; + unsigned int ssIndex; + ScreenSettings* ss; - ProcessField* fields; int flags; int colorScheme; int delay; int cpuCount; - int direction; - ProcessField sortKey; bool countCPUsFromZero; bool detailedCPUTime; - bool treeView; bool showProgramPath; bool hideThreads; bool shadowOtherUsers; @@ -80,8 +87,10 @@ static void writeList(FILE* fd, char** list, int len) { fprintf(fd, "\n"); } -static char** readQuotedList(char* line, int* size) { - *size = 0; +/* + +static char** readQuotedList(char* line) { + int n = 0; char** list = xCalloc(sizeof(char*), 1); int start = 0; for (;;) { @@ -100,50 +109,51 @@ static char** readQuotedList(char* line, int* size) { char* item = xMalloc(len + 1); strncpy(item, line + start, len); item[len] = '\0'; - list[*size] = item; - (*size)++; - list = xRealloc(list, sizeof(char*) * (*size + 1)); + list[n] = item; + n++; + list = xRealloc(list, sizeof(char*) * (n + 1)); start = close + 1; } - list[*size] = NULL; + list[n] = NULL; return list; } -static void writeQuotedList(FILE* fd, char** list, int len) { +static void writeQuotedList(FILE* fd, char** list) { const char* sep = ""; - for (int i = 0; i < len; i++) { + for (int i = 0; list[i]; i++) { fprintf(fd, "%s\"%s\"", sep, list[i]); sep = " "; } fprintf(fd, "\n"); } +*/ + void Settings_delete(Settings* this) { free(this->filename); - free(this->fields); - for (unsigned int i = 0; i < (sizeof(this->columns)/sizeof(MeterColumnSettings)); i++) { - String_freeArray(this->columns[i].names); - free(this->columns[i].modes); + for (unsigned int i = 0; i < (sizeof(this->meterColumns)/sizeof(MeterColumnSettings)); i++) { + String_freeArray(this->meterColumns[i].names); + free(this->meterColumns[i].modes); + } + if (this->screens) { + for (unsigned int i = 0; this->screens[i]; i++) { + free(this->screens[i]->name); + free(this->screens[i]->fields); + } + free(this->screens); } - String_freeArray(this->screens); free(this); } -static void Settings_readMeters(Settings* this, char* line, int column) { +static void Settings_readMeters(Settings* this, char* line, int side) { char* trim = String_trim(line); int nIds; char** ids = String_split(trim, ' ', &nIds); free(trim); - this->columns[column].names = ids; + this->meterColumns[side].names = ids; } -static void Settings_readScreens(Settings* this, char* line) { - char* trim = String_trim(line); - this->screens = readQuotedList(trim, &(this->nScreens)); - free(trim); -} - -static void Settings_readMeterModes(Settings* this, char* line, int column) { +static void Settings_readMeterModes(Settings* this, char* line, int side) { char* trim = String_trim(line); int nIds; char** ids = String_split(trim, ' ', &nIds); @@ -152,13 +162,13 @@ static void Settings_readMeterModes(Settings* this, char* line, int column) { for (int i = 0; ids[i]; i++) { len++; } - this->columns[column].len = len; + this->meterColumns[side].len = len; int* modes = xCalloc(len, sizeof(int)); for (int i = 0; i < len; i++) { modes[i] = atoi(ids[i]); } String_freeArray(ids); - this->columns[column].modes = modes; + this->meterColumns[side].modes = modes; } static void Settings_defaultMeters(Settings* this) { @@ -167,44 +177,54 @@ static void Settings_defaultMeters(Settings* this) { sizes[1]++; } for (int i = 0; i < 2; i++) { - this->columns[i].names = xCalloc(sizes[i] + 1, sizeof(char*)); - this->columns[i].modes = xCalloc(sizes[i], sizeof(int)); - this->columns[i].len = sizes[i]; + this->meterColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*)); + this->meterColumns[i].modes = xCalloc(sizes[i], sizeof(int)); + this->meterColumns[i].len = sizes[i]; } int r = 0; if (this->cpuCount > 8) { - this->columns[0].names[0] = xStrdup("LeftCPUs2"); - this->columns[0].modes[0] = BAR_METERMODE; - this->columns[1].names[r] = xStrdup("RightCPUs2"); - this->columns[1].modes[r++] = BAR_METERMODE; + this->meterColumns[0].names[0] = xStrdup("LeftCPUs2"); + this->meterColumns[0].modes[0] = BAR_METERMODE; + this->meterColumns[1].names[r] = xStrdup("RightCPUs2"); + this->meterColumns[1].modes[r++] = BAR_METERMODE; } else if (this->cpuCount > 4) { - this->columns[0].names[0] = xStrdup("LeftCPUs"); - this->columns[0].modes[0] = BAR_METERMODE; - this->columns[1].names[r] = xStrdup("RightCPUs"); - this->columns[1].modes[r++] = BAR_METERMODE; + this->meterColumns[0].names[0] = xStrdup("LeftCPUs"); + this->meterColumns[0].modes[0] = BAR_METERMODE; + this->meterColumns[1].names[r] = xStrdup("RightCPUs"); + this->meterColumns[1].modes[r++] = BAR_METERMODE; } else { - this->columns[0].names[0] = xStrdup("AllCPUs"); - this->columns[0].modes[0] = BAR_METERMODE; + this->meterColumns[0].names[0] = xStrdup("AllCPUs"); + this->meterColumns[0].modes[0] = BAR_METERMODE; } - this->columns[0].names[1] = xStrdup("Memory"); - this->columns[0].modes[1] = BAR_METERMODE; - this->columns[0].names[2] = xStrdup("Swap"); - this->columns[0].modes[2] = BAR_METERMODE; + this->meterColumns[0].names[1] = xStrdup("Memory"); + this->meterColumns[0].modes[1] = BAR_METERMODE; + this->meterColumns[0].names[2] = xStrdup("Swap"); + this->meterColumns[0].modes[2] = BAR_METERMODE; - this->columns[1].names[r] = xStrdup("Tasks"); - this->columns[1].modes[r++] = TEXT_METERMODE; - this->columns[1].names[r] = xStrdup("LoadAverage"); - this->columns[1].modes[r++] = TEXT_METERMODE; - this->columns[1].names[r] = xStrdup("Uptime"); - this->columns[1].modes[r++] = TEXT_METERMODE; + this->meterColumns[1].names[r] = xStrdup("Tasks"); + this->meterColumns[1].modes[r++] = TEXT_METERMODE; + this->meterColumns[1].names[r] = xStrdup("LoadAverage"); + this->meterColumns[1].modes[r++] = TEXT_METERMODE; + this->meterColumns[1].names[r] = xStrdup("Uptime"); + this->meterColumns[1].modes[r++] = TEXT_METERMODE; } -static void Settings_defaultScreens(Settings* this) { - this->screens = xMalloc(sizeof(char*) * 3); - this->screens[0] = xStrdup("Overview"); - this->screens[1] = xStrdup("I/O"); - this->screens[2] = NULL; +static int toFieldIndex(const char* str) { + if (isdigit(str[0])) { + // This "+1" is for compatibility with the older enum format. + int id = atoi(str) + 1; + if (Process_fields[id].name && id < Platform_numberOfFields) { + return id; + } + } else { + for (int p = 1; p < LAST_PROCESSFIELD; p++) { + if (Process_fields[p].name && strcmp(Process_fields[p].name, str) == 0) { + return p; + } + } + } + return -1; } static void readFields(ProcessField* fields, int* flags, const char* line) { @@ -215,11 +235,10 @@ static void readFields(ProcessField* fields, int* flags, const char* line) { int i, j; *flags = 0; for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) { - // This "+1" is for compatibility with the older enum format. - int id = atoi(ids[i]) + 1; - if (id > 0 && Process_fields[id].name && id < Platform_numberOfFields) { - fields[j] = id; - *flags |= Process_fields[id].flags; + int idx = toFieldIndex(ids[i]); + if (idx != -1) { + fields[j] = idx; + *flags |= Process_fields[idx].flags; j++; } } @@ -227,6 +246,25 @@ static void readFields(ProcessField* fields, int* flags, const char* line) { String_freeArray(ids); } +static void Settings_readScreen(Settings* this, const char* name, const char* line) { + ScreenSettings* ss = xCalloc(sizeof(ScreenSettings), 1); + ss->name = xStrdup(name); + ss->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField)); + ss->flags = 0; + ss->direction = 1; + ss->treeView = 0; + readFields(ss->fields, &(ss->flags), line); + this->screens[this->nScreens] = ss; + this->nScreens++; + this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1)); + this->screens[this->nScreens] = NULL; +} + +static void Settings_defaultScreens(Settings* this) { + Settings_readScreen(this, "Default", "PID USER PRIORITY NICE M_SIZE M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command"); + Settings_readScreen(this, "I/O", "PID IO_PRIORITY USER IO_READ_RATE IO_WRITE_RATE Command"); +} + static bool Settings_read(Settings* this, const char* fileName) { FILE* fd; @@ -238,6 +276,9 @@ static bool Settings_read(Settings* this, const char* fileName) { bool didReadMeters = false; bool didReadFields = false; + ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField)); + int legacyFlags; + bool legacyFieldsRead = false; for (;;) { char* line = String_readLine(fd); if (!line) { @@ -251,15 +292,8 @@ static bool Settings_read(Settings* this, const char* fileName) { continue; } if (String_eq(option[0], "fields")) { - readFields(this->fields, &(this->flags), option[1]); - didReadFields = true; - } else if (String_eq(option[0], "sort_key")) { - // This "+1" is for compatibility with the older enum format. - this->sortKey = atoi(option[1]) + 1; - } else if (String_eq(option[0], "sort_direction")) { - this->direction = atoi(option[1]); - } else if (String_eq(option[0], "tree_view")) { - this->treeView = atoi(option[1]); + readFields(legacyFields, &legacyFlags, option[1]); + legacyFieldsRead = true; } else if (String_eq(option[0], "hide_threads")) { this->hideThreads = atoi(option[1]); } else if (String_eq(option[0], "hide_kernel_threads")) { @@ -308,14 +342,31 @@ static bool Settings_read(Settings* this, const char* fileName) { } else if (String_eq(option[0], "right_meter_modes")) { Settings_readMeterModes(this, option[1], 1); didReadMeters = true; - } else if (String_eq(option[0], "screens")) { - Settings_readScreens(this, option[1]); + } else if (strncmp(option[0], "screen:", 7) == 0) { + Settings_readScreen(this, option[0] + 7, option[1]); + } else if (String_eq(option[0], ".tree_view")) { + if (this->nScreens > 0) { + this->screens[this->nScreens - 1]->treeView = atoi(option[1]); + } + } else if (String_eq(option[0], ".sort_direction")) { + if (this->nScreens > 0) { + this->screens[this->nScreens - 1]->direction = atoi(option[1]); + } + } else if (String_eq(option[0], ".sort_key")) { + if (this->nScreens > 0) { + this->screens[this->nScreens - 1]->sortKey = toFieldIndex(option[1]); + } } String_freeArray(option); } fclose(fd); - if (!this->screens) { + if (this->nScreens == 0) { Settings_defaultScreens(this); + if (legacyFieldsRead) { + free(this->screens[0]->fields); + this->screens[0]->fields = legacyFields; + this->screens[0]->flags = legacyFlags; + } } if (!didReadMeters) { Settings_defaultMeters(this); @@ -323,25 +374,28 @@ static bool Settings_read(Settings* this, const char* fileName) { return didReadFields; } -static void writeFields(FILE* fd, ProcessField* fields, const char* name) { - fprintf(fd, "%s=", name); +static void writeFields(FILE* fd, ProcessField* fields, bool byName) { const char* sep = ""; for (int i = 0; fields[i]; i++) { - // This "-1" is for compatibility with the older enum format. - fprintf(fd, "%s%d", sep, (int) fields[i]-1); + if (byName) { + fprintf(fd, "%s%s", sep, Process_fields[fields[i]].name); + } else { + // This " - 1" is for compatibility with the older enum format. + fprintf(fd, "%s%d", sep, (int) fields[i] - 1); + } sep = " "; } fprintf(fd, "\n"); } -static void writeMeters(Settings* this, FILE* fd, int column) { - writeList(fd, this->columns[column].names, this->columns[column].len); +static void writeMeters(Settings* this, FILE* fd, int side) { + writeList(fd, this->meterColumns[side].names, this->meterColumns[side].len); } -static void writeMeterModes(Settings* this, FILE* fd, int column) { +static void writeMeterModes(Settings* this, FILE* fd, int side) { const char* sep = ""; - for (int i = 0; i < this->columns[column].len; i++) { - fprintf(fd, "%s%d", sep, this->columns[column].modes[i]); + for (int i = 0; i < this->meterColumns[side].len; i++) { + fprintf(fd, "%s%d", sep, this->meterColumns[side].modes[i]); sep = " "; } fprintf(fd, "\n"); @@ -359,10 +413,7 @@ bool Settings_write(Settings* this) { } fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n"); fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n"); - writeFields(fd, this->fields, "fields"); - // This "-1" is for compatibility with the older enum format. - fprintf(fd, "sort_key=%d\n", (int) this->sortKey-1); - fprintf(fd, "sort_direction=%d\n", (int) this->direction); + fprintf(fd, "fields="); writeFields(fd, this->screens[0]->fields, false); fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads); fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads); fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads); @@ -372,7 +423,6 @@ bool Settings_write(Settings* this) { fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName); fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes); fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads); - fprintf(fd, "tree_view=%d\n", (int) this->treeView); fprintf(fd, "header_margin=%d\n", (int) this->headerMargin); fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime); fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero); @@ -384,8 +434,16 @@ bool Settings_write(Settings* this) { fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0); fprintf(fd, "right_meters="); writeMeters(this, fd, 1); fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1); - if (this->nScreens > 0) { - fprintf(fd, "screens="); writeQuotedList(fd, this->screens, this->nScreens); + if (this->screens && this->screens[0]) { + for (unsigned int i = 0; i < this->nScreens; i++) { + ScreenSettings* ss = this->screens[i]; + fprintf(fd, "screen:%s=", ss->name); + writeFields(fd, ss->fields, true); + fprintf(fd, ".tree_view=%d\n", (int) ss->treeView); + // This "-1" is for compatibility with the older enum format. + fprintf(fd, ".sort_key=%d\n", (int) ss->sortKey-1); + fprintf(fd, ".sort_direction=%d\n", (int) ss->direction); + } } fclose(fd); return true; @@ -395,14 +453,11 @@ Settings* Settings_new(int cpuCount) { Settings* this = xCalloc(1, sizeof(Settings)); - this->sortKey = PERCENT_CPU; - this->direction = 1; this->hideThreads = false; this->shadowOtherUsers = false; this->showThreadNames = false; this->hideKernelThreads = false; this->hideUserlandThreads = false; - this->treeView = false; this->highlightBaseName = false; this->highlightMegabytes = false; this->detailedCPUTime = false; @@ -412,15 +467,8 @@ Settings* Settings_new(int cpuCount) { this->showProgramPath = true; this->highlightThreads = true; - this->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField)); - // TODO: turn 'fields' into a Vector, - // (and ProcessFields into proper objects). - this->flags = 0; - ProcessField* defaults = Platform_defaultFields; - for (int i = 0; defaults[i]; i++) { - this->fields[i] = defaults[i]; - this->flags |= Process_fields[defaults[i]].flags; - } + this->screens = xCalloc(sizeof(ScreenSettings*), 1); + this->nScreens = 0; char* legacyDotfile = NULL; char* rcfile = getenv("HTOPRC"); @@ -487,10 +535,14 @@ Settings* Settings_new(int cpuCount) { this->highlightThreads = true; this->headerMargin = true; } + + this->ssIndex = 0; + this->ss = this->screens[this->ssIndex]; + return this; } -void Settings_invertSortOrder(Settings* this) { +void ScreenSettings_invertSortOrder(ScreenSettings* this) { if (this->direction == 1) this->direction = -1; else diff --git a/Settings.h b/Settings.h index aed438eb..eccdae55 100644 --- a/Settings.h +++ b/Settings.h @@ -20,26 +20,33 @@ typedef struct { int* modes; } MeterColumnSettings; +typedef struct { + char* name; + ProcessField* fields; + int flags; + int direction; + ProcessField sortKey; + bool treeView; +} ScreenSettings; + typedef struct Settings_ { char* filename; - MeterColumnSettings columns[2]; + MeterColumnSettings meterColumns[2]; - char** screens; - int nScreens; + ScreenSettings** screens; + unsigned int nScreens; + unsigned int ssIndex; + ScreenSettings* ss; - ProcessField* fields; int flags; int colorScheme; int delay; int cpuCount; - int direction; - ProcessField sortKey; bool countCPUsFromZero; bool detailedCPUTime; - bool treeView; bool showProgramPath; bool hideThreads; bool shadowOtherUsers; @@ -61,12 +68,16 @@ typedef struct Settings_ { #endif +/* + +*/ + void Settings_delete(Settings* this); bool Settings_write(Settings* this); Settings* Settings_new(int cpuCount); -void Settings_invertSortOrder(Settings* this); +void ScreenSettings_invertSortOrder(ScreenSettings* this); #endif diff --git a/htop.c b/htop.c index 239b5d6e..a01456fd 100644 --- a/htop.c +++ b/htop.c @@ -203,12 +203,12 @@ int main(int argc, char** argv) { MainPanel* panel = MainPanel_new(); ProcessList_setPanel(pl, (Panel*) panel); - MainPanel_updateTreeFunctions(panel, settings->treeView); + MainPanel_updateTreeFunctions(panel, settings->screens[0]->treeView); if (flags.sortKey > 0) { - settings->sortKey = flags.sortKey; - settings->treeView = false; - settings->direction = 1; + settings->screens[0]->sortKey = flags.sortKey; + settings->screens[0]->treeView = false; + settings->screens[0]->direction = 1; } ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel)); diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c index 39b5647e..3bfc697d 100644 --- a/linux/LinuxProcess.c +++ b/linux/LinuxProcess.c @@ -404,7 +404,7 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) long LinuxProcess_compare(const void* v1, const void* v2) { LinuxProcess *p1, *p2; Settings *settings = ((Process*)v1)->settings; - if (settings->direction == 1) { + if (settings->ss->direction == 1) { p1 = (LinuxProcess*)v1; p2 = (LinuxProcess*)v2; } else { @@ -412,7 +412,7 @@ long LinuxProcess_compare(const void* v1, const void* v2) { p1 = (LinuxProcess*)v2; } long long diff; - switch ((int)settings->sortKey) { + switch ((int)settings->ss->sortKey) { case M_DRS: return (p2->m_drs - p1->m_drs); case M_DT: