Separate tree and list sort orders

Implements the suggestion from https://github.com/htop-dev/htop/issues/399#issuecomment-747861013

Thanks to the refactors from 0bd5c8fb5da and 6393baa74e5, this was really easy
and clean to do.

It maintains the "Tree view always by PID" option in the Settings, which
results in some specific behaviors such as "clicking on the column header to
exit tree view" and "picking a new sort order to exit tree view", for the sake
of the muscle memory of long time htop users. :)
This commit is contained in:
Hisham Muhammad 2020-12-18 11:03:31 -03:00 committed by BenBE
parent e8c6994f40
commit 2327260ee8
7 changed files with 54 additions and 24 deletions

View File

@ -158,11 +158,7 @@ static bool collapseIntoParent(Panel* panel) {
} }
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) { Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
settings->sortKey = sortKey; Settings_setSortKey(settings, sortKey);
settings->direction = 1;
if (settings->treeViewAlwaysByPID) {
settings->treeView = false;
}
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING; return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
} }
@ -174,7 +170,7 @@ static Htop_Reaction sortBy(State* st) {
for (int i = 0; fields[i]; i++) { for (int i = 0; fields[i]; i++) {
char* name = String_trim(Process_fields[fields[i]].name); char* name = String_trim(Process_fields[fields[i]].name);
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i])); Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
if (fields[i] == st->settings->sortKey) if (fields[i] == Settings_getActiveSortKey(st->settings))
Panel_setSelected(sortPanel, i); Panel_setSelected(sortPanel, i);
free(name); free(name);
@ -234,7 +230,7 @@ static Htop_Reaction actionToggleMergedCommand(State* st) {
static Htop_Reaction actionToggleTreeView(State* st) { static Htop_Reaction actionToggleTreeView(State* st) {
st->settings->treeView = !st->settings->treeView; st->settings->treeView = !st->settings->treeView;
if (st->settings->treeView) { if (st->settings->treeView) {
st->settings->direction = 1; st->settings->treeDirection = 1;
} }
ProcessList_expandTree(st->pl); ProcessList_expandTree(st->pl);

View File

@ -60,14 +60,15 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
Settings* settings = this->state->settings; Settings* settings = this->state->settings;
int hx = super->scrollH + x + 1; int hx = super->scrollH + x + 1;
ProcessField field = ProcessList_keyAt(pl, hx); ProcessField field = ProcessList_keyAt(pl, hx);
if (field == settings->sortKey) { if (settings->treeView && settings->treeViewAlwaysByPID) {
settings->treeView = false;
settings->direction = 1;
reaction |= Action_setSortKey(settings, field);
} else if (field == Settings_getActiveSortKey(settings)) {
Settings_invertSortOrder(settings); Settings_invertSortOrder(settings);
} else { } else {
reaction |= Action_setSortKey(settings, field); reaction |= Action_setSortKey(settings, field);
} }
if (settings->treeViewAlwaysByPID) {
settings->treeView = false;
}
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS; reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
result = HANDLED; result = HANDLED;
} else if (ch != ERR && this->inc->active) { } else if (ch != ERR && this->inc->active) {

View File

@ -497,7 +497,7 @@ long Process_compare(const void* v1, const void* v2) {
const Settings *settings = ((const Process*)v1)->settings; const Settings *settings = ((const Process*)v1)->settings;
int r; int r;
if (settings->direction == 1) { if (Settings_getActiveDirection(settings) == 1) {
p1 = (const Process*)v1; p1 = (const Process*)v1;
p2 = (const Process*)v2; p2 = (const Process*)v2;
} else { } else {
@ -505,10 +505,7 @@ long Process_compare(const void* v1, const void* v2) {
p1 = (const Process*)v2; p1 = (const Process*)v2;
} }
ProcessField key = settings->sortKey; ProcessField key = Settings_getActiveSortKey(settings);
if (settings->treeView && settings->treeViewAlwaysByPID) {
key = PID;
}
switch (key) { switch (key) {
case PERCENT_CPU: case PERCENT_CPU:

View File

@ -85,6 +85,8 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
const Settings* settings = this->settings; const Settings* settings = this->settings;
const ProcessField* fields = settings->fields; const ProcessField* fields = settings->fields;
ProcessField key = Settings_getActiveSortKey(settings);
for (int i = 0; fields[i]; i++) { for (int i = 0; fields[i]; i++) {
const char* field = Process_fields[fields[i]].title; const char* field = Process_fields[fields[i]].title;
if (!field) { if (!field) {
@ -94,7 +96,7 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
int color; int color;
if (settings->treeView && settings->treeViewAlwaysByPID) { if (settings->treeView && settings->treeViewAlwaysByPID) {
color = CRT_colors[PANEL_HEADER_FOCUS]; color = CRT_colors[PANEL_HEADER_FOCUS];
} else if (settings->sortKey == fields[i]) { } else if (key == fields[i]) {
color = CRT_colors[PANEL_SELECTION_FOCUS]; color = CRT_colors[PANEL_SELECTION_FOCUS];
} else { } else {
color = CRT_colors[PANEL_HEADER_FOCUS]; color = CRT_colors[PANEL_HEADER_FOCUS];
@ -355,7 +357,7 @@ static long ProcessList_treeProcessCompareByPID(const void* v1, const void* v2)
static void ProcessList_buildTree(ProcessList* this) { static void ProcessList_buildTree(ProcessList* this) {
int node_counter = 1; int node_counter = 1;
int node_index = 0; int node_index = 0;
int direction = this->settings->direction; int direction = Settings_getActiveDirection(this->settings);
// Sort by PID // Sort by PID
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID); Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID);

View File

@ -137,8 +137,13 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
} else if (String_eq(option[0], "sort_key")) { } else if (String_eq(option[0], "sort_key")) {
// This "+1" is for compatibility with the older enum format. // This "+1" is for compatibility with the older enum format.
this->sortKey = atoi(option[1]) + 1; this->sortKey = atoi(option[1]) + 1;
} else if (String_eq(option[0], "tree_sort_key")) {
// This "+1" is for compatibility with the older enum format.
this->treeSortKey = atoi(option[1]) + 1;
} else if (String_eq(option[0], "sort_direction")) { } else if (String_eq(option[0], "sort_direction")) {
this->direction = atoi(option[1]); this->direction = atoi(option[1]);
} else if (String_eq(option[0], "tree_sort_direction")) {
this->treeDirection = atoi(option[1]);
} else if (String_eq(option[0], "tree_view")) { } else if (String_eq(option[0], "tree_view")) {
this->treeView = atoi(option[1]); this->treeView = atoi(option[1]);
} else if (String_eq(option[0], "tree_view_always_by_pid")) { } else if (String_eq(option[0], "tree_view_always_by_pid")) {
@ -275,6 +280,8 @@ bool Settings_write(Settings* this) {
// This "-1" is for compatibility with the older enum format. // This "-1" is for compatibility with the older enum format.
fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1); fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1);
fprintf(fd, "sort_direction=%d\n", (int) this->direction); fprintf(fd, "sort_direction=%d\n", (int) this->direction);
fprintf(fd, "tree_sort_key=%d\n", (int) this->treeSortKey - 1);
fprintf(fd, "tree_sort_direction=%d\n", (int) this->treeDirection);
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads); fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads); fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers); fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
@ -319,7 +326,9 @@ Settings* Settings_new(int initialCpuCount) {
Settings* this = xCalloc(1, sizeof(Settings)); Settings* this = xCalloc(1, sizeof(Settings));
this->sortKey = PERCENT_CPU; this->sortKey = PERCENT_CPU;
this->treeSortKey = PID;
this->direction = 1; this->direction = 1;
this->treeDirection = 1;
this->shadowOtherUsers = false; this->shadowOtherUsers = false;
this->showThreadNames = false; this->showThreadNames = false;
this->hideKernelThreads = false; this->hideKernelThreads = false;
@ -430,9 +439,17 @@ Settings* Settings_new(int initialCpuCount) {
} }
void Settings_invertSortOrder(Settings* this) { void Settings_invertSortOrder(Settings* this) {
if (this->direction == 1) { int* attr = (this->treeView) ? &(this->treeDirection) : &(this->direction);
this->direction = -1; *attr = (*attr == 1) ? -1 : 1;
} else { }
void Settings_setSortKey(Settings* this, ProcessField sortKey) {
if (this->treeViewAlwaysByPID || !this->treeView) {
this->sortKey = sortKey;
this->direction = 1; this->direction = 1;
this->treeView = false;
} else {
this->treeSortKey = sortKey;
this->treeDirection = 1;
} }
} }

View File

@ -33,7 +33,9 @@ typedef struct Settings_ {
int delay; int delay;
int direction; int direction;
int treeDirection;
ProcessField sortKey; ProcessField sortKey;
ProcessField treeSortKey;
bool countCPUsFromOne; bool countCPUsFromOne;
bool detailedCPUTime; bool detailedCPUTime;
@ -71,6 +73,16 @@ typedef struct Settings_ {
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu)) #define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu))
static inline ProcessField Settings_getActiveSortKey(const Settings* this) {
return (this->treeView)
? (this->treeViewAlwaysByPID ? PID : this->treeSortKey)
: this->sortKey;
}
static inline int Settings_getActiveDirection(const Settings* this) {
return this->treeView ? this->treeDirection : this->direction;
}
void Settings_delete(Settings* this); void Settings_delete(Settings* this);
bool Settings_write(Settings* this); bool Settings_write(Settings* this);
@ -79,4 +91,6 @@ Settings* Settings_new(int initialCpuCount);
void Settings_invertSortOrder(Settings* this); void Settings_invertSortOrder(Settings* this);
void Settings_setSortKey(Settings* this, ProcessField sortKey);
#endif #endif

7
htop.c
View File

@ -298,9 +298,12 @@ int main(int argc, char** argv) {
if (flags.highlightDelaySecs != -1) if (flags.highlightDelaySecs != -1)
settings->highlightDelaySecs = flags.highlightDelaySecs; settings->highlightDelaySecs = flags.highlightDelaySecs;
if (flags.sortKey > 0) { if (flags.sortKey > 0) {
settings->sortKey = flags.sortKey; // -t -s <key> means "tree sorted by key"
// -s <key> means "list sorted by key" (previous existing behavior)
if (!flags.treeView) {
settings->treeView = false; settings->treeView = false;
settings->direction = 1; }
Settings_setSortKey(settings, flags.sortKey);
} }
CRT_init(&(settings->delay), settings->colorScheme, flags.allowUnicode); CRT_init(&(settings->delay), settings->colorScheme, flags.allowUnicode);