summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2014-04-09 18:02:50 -0300
committerHisham Muhammad <hisham@gobolinux.org>2014-04-09 18:02:50 -0300
commit19b438de1009047ee425d1f36207c20b9c80d43a (patch)
tree003a45252e211016edb8ec71518efb321fd5aced
parentaf4c412ebf4ba96973fb6ea3e9ee8f59fe751769 (diff)
Improve discoverability of the expand/collapse feature.
It is now accessible via F6 when on tree view (as a bonus, it is now also reachable via the mouse). The function bar now dynamically changes to reflect the toggle nature of the tree-view mode (F5) and the F6 key serves as expand/collapse when on tree mode, and its previous behavior of bringing up the "Sort By" menu (which only made sense on non-tree mode). Users wishing to go to the "Sort By" menu straight from Tree View can still do so with the "<" and ">" keys (the top-compatible keys for sort selection).
-rw-r--r--FunctionBar.c18
-rw-r--r--htop.1.in8
-rw-r--r--htop.c133
-rw-r--r--htop.h2
4 files changed, 112 insertions, 49 deletions
diff --git a/FunctionBar.c b/FunctionBar.c
index 66b9843f..1c6066ae 100644
--- a/FunctionBar.c
+++ b/FunctionBar.c
@@ -40,15 +40,19 @@ ObjectClass FunctionBar_class = {
FunctionBar* FunctionBar_new(const char** functions, const char** keys, int* events) {
FunctionBar* this = AllocThis(FunctionBar);
- this->functions = (char**) functions;
+ this->functions = calloc(16, sizeof(char*));
+ if (!functions) {
+ functions = FunctionBar_FLabels;
+ }
+ for (int i = 0; i < 15 && functions[i]; i++) {
+ this->functions[i] = strdup(functions[i]);
+ }
if (keys && events) {
this->staticData = false;
- this->functions = malloc(sizeof(char*) * 15);
this->keys = malloc(sizeof(char*) * 15);
this->events = malloc(sizeof(int) * 15);
int i = 0;
while (i < 15 && functions[i]) {
- this->functions[i] = strdup(functions[i]);
this->keys[i] = strdup(keys[i]);
this->events[i] = events[i];
i++;
@@ -56,7 +60,6 @@ FunctionBar* FunctionBar_new(const char** functions, const char** keys, int* eve
this->size = i;
} else {
this->staticData = true;
- this->functions = (char**)( functions ? functions : FunctionBar_FLabels );
this->keys = (char**) FunctionBar_FKeys;
this->events = FunctionBar_FEvents;
this->size = 10;
@@ -66,12 +69,14 @@ FunctionBar* FunctionBar_new(const char** functions, const char** keys, int* eve
void FunctionBar_delete(Object* cast) {
FunctionBar* this = (FunctionBar*) cast;
+ for (int i = 0; i < 15 && this->functions[i]; i++) {
+ free(this->functions[i]);
+ }
+ free(this->functions);
if (!this->staticData) {
for (int i = 0; i < this->size; i++) {
- free(this->functions[i]);
free(this->keys[i]);
}
- free(this->functions);
free(this->keys);
free(this->events);
}
@@ -79,7 +84,6 @@ void FunctionBar_delete(Object* cast) {
}
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
- assert(!this->staticData);
for (int i = 0; i < this->size; i++) {
if (this->events[i] == event) {
free(this->functions[i]);
diff --git a/htop.1.in b/htop.1.in
index 5b2d754e..a0e2a261 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -91,9 +91,11 @@ between them as a tree. Toggling the key will switch between tree and
your previously selected sort view. Selecting a sort view will exit
tree view.
.TP
-.B F6, <, >
-Select a field for sorting. The current sort field is indicated by a
-highlight in the header.
+.B F6
+On sorted view, select a field for sorting, also accessible through < and >.
+The current sort field is indicated by a highlight in the header.
+On tree view, expand or collapse the current subtree. A "+" indicator in the
+tree node indicates that it is collapsed.
.TP
.B F7, ]
Increase the selected process's priority (subtract from 'nice' value).
diff --git a/htop.c b/htop.c
index 48fc6fc7..94ff3a7c 100644
--- a/htop.c
+++ b/htop.c
@@ -48,6 +48,8 @@ static void printVersionFlag() {
exit(0);
}
+static const char* defaultFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
+
static void printHelpFlag() {
fputs("htop " VERSION " - " COPYRIGHT "\n"
"Released under the GNU GPL.\n\n"
@@ -76,7 +78,7 @@ static struct { const char* key; const char* info; } helpLeft[] = {
{ .key = " H: ", .info = "hide/show user threads" },
{ .key = " K: ", .info = "hide/show kernel threads" },
{ .key = " F: ", .info = "cursor follows process" },
- { .key = " + -: ", .info = "expand/collapse tree" },
+ { .key = " F6 + -: ", .info = "expand/collapse tree" },
{ .key = " P M T: ", .info = "sort by CPU%, MEM% or TIME" },
{ .key = " I: ", .info = "invert sort order" },
{ .key = " F6 >: ", .info = "select sort column" },
@@ -268,10 +270,24 @@ static bool setUserOnly(const char* userName, bool* userOnly, uid_t* userId) {
return false;
}
-static inline void setSortKey(ProcessList* pl, ProcessField sortKey, Panel* panel, Settings* settings) {
+static void setTreeView(ProcessList* pl, FunctionBar* fuBar, bool mode) {
+ if (mode) {
+ FunctionBar_setLabel(fuBar, KEY_F(5), "Sorted");
+ FunctionBar_setLabel(fuBar, KEY_F(6), "Collap");
+ } else {
+ FunctionBar_setLabel(fuBar, KEY_F(5), "Tree ");
+ FunctionBar_setLabel(fuBar, KEY_F(6), "SortBy");
+ }
+ if (mode != pl->treeView) {
+ FunctionBar_draw(fuBar, NULL);
+ }
+ pl->treeView = mode;
+}
+
+static inline void setSortKey(ProcessList* pl, FunctionBar* fuBar, ProcessField sortKey, Panel* panel, Settings* settings) {
pl->sortKey = sortKey;
pl->direction = 1;
- pl->treeView = false;
+ setTreeView(pl, fuBar, false);
settings->changed = true;
ProcessList_printHeader(pl, Panel_getHeader(panel));
}
@@ -294,6 +310,35 @@ static void tagAllChildren(Panel* panel, Process* parent) {
}
}
+static bool expandCollapse(Panel* panel) {
+ Process* p = (Process*) Panel_getSelected(panel);
+ if (!p) return false;
+ p->showChildren = !p->showChildren;
+ return true;
+}
+
+void sortBy(Panel* panel, ProcessList* pl, Settings* settings, int headerHeight, FunctionBar* defaultBar, Header* header) {
+ Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem));
+ Panel_setHeader(sortPanel, "Sort by");
+ const char* fuFunctions[] = {"Sort ", "Cancel ", NULL};
+ ProcessField* fields = pl->fields;
+ for (int i = 0; fields[i]; i++) {
+ char* name = String_trim(Process_fieldNames[fields[i]]);
+ Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
+ if (fields[i] == pl->sortKey)
+ Panel_setSelected(sortPanel, i);
+ free(name);
+ }
+ ListItem* field = (ListItem*) pickFromVector(panel, sortPanel, 15, headerHeight, fuFunctions, defaultBar, header);
+ if (field) {
+ settings->changed = true;
+ setSortKey(pl, defaultBar, field->key, panel, settings);
+ } else {
+ ProcessList_printHeader(pl, Panel_getHeader(panel));
+ }
+ Object_delete(sortPanel);
+}
+
int main(int argc, char** argv) {
int delay = -1;
@@ -437,16 +482,15 @@ int main(int argc, char** argv) {
Panel* panel = Panel_new(0, headerHeight, COLS, LINES - headerHeight - 2, false, &Process_class);
ProcessList_setPanel(pl, panel);
+ FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
+ setTreeView(pl, defaultBar, pl->treeView);
+
if (sortKey > 0) {
pl->sortKey = sortKey;
- pl->treeView = false;
+ setTreeView(pl, defaultBar, false);
pl->direction = 1;
}
ProcessList_printHeader(pl, Panel_getHeader(panel));
-
- const char* defaultFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ",
- "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
- FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
IncSet* inc = IncSet_new(defaultBar);
@@ -468,6 +512,8 @@ int main(int argc, char** argv) {
bool idle = false;
+ bool collapsed = false;
+
while (!quit) {
gettimeofday(&tv, NULL);
newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
@@ -490,9 +536,24 @@ int main(int argc, char** argv) {
idle = false;
}
doRefresh = true;
+
+ if (pl->treeView) {
+ Process* p = (Process*) Panel_getSelected(panel);
+ if (p) {
+ if (!p->showChildren && !collapsed) {
+ FunctionBar_setLabel(defaultBar, KEY_F(6), "Expand");
+ FunctionBar_draw(defaultBar, NULL);
+ } else if (p->showChildren && collapsed) {
+ FunctionBar_setLabel(defaultBar, KEY_F(6), "Collap");
+ FunctionBar_draw(defaultBar, NULL);
+ }
+ collapsed = !p->showChildren;
+ }
+ }
- if (!idle)
+ if (!idle) {
Panel_draw(panel, true);
+ }
int prev = ch;
if (inc->active)
@@ -524,9 +585,9 @@ int main(int argc, char** argv) {
ProcessField field = ProcessList_keyAt(pl, x);
if (field == pl->sortKey) {
ProcessList_invertSortOrder(pl);
- pl->treeView = false;
+ setTreeView(pl, defaultBar, false);
} else {
- setSortKey(pl, field, panel, settings);
+ setSortKey(pl, defaultBar, field, panel, settings);
}
refreshTimeout = 0;
continue;
@@ -580,13 +641,13 @@ int main(int argc, char** argv) {
case 'M':
{
refreshTimeout = 0;
- setSortKey(pl, PERCENT_MEM, panel, settings);
+ setSortKey(pl, defaultBar, PERCENT_MEM, panel, settings);
break;
}
case 'T':
{
refreshTimeout = 0;
- setSortKey(pl, TIME, panel, settings);
+ setSortKey(pl, defaultBar, TIME, panel, settings);
break;
}
case 'c':
@@ -608,7 +669,7 @@ int main(int argc, char** argv) {
case 'P':
{
refreshTimeout = 0;
- setSortKey(pl, PERCENT_CPU, panel, settings);
+ setSortKey(pl, defaultBar, PERCENT_CPU, panel, settings);
break;
}
case KEY_F(1):
@@ -704,11 +765,10 @@ int main(int argc, char** argv) {
case '=':
case '-':
{
- Process* p = (Process*) Panel_getSelected(panel);
- if (!p) break;
- p->showChildren = !p->showChildren;
- refreshTimeout = 0;
- doRecalculate = true;
+ if (expandCollapse(panel)) {
+ doRecalculate = true;
+ refreshTimeout = 0;
+ }
break;
}
case KEY_F(9):
@@ -764,31 +824,25 @@ int main(int argc, char** argv) {
break;
case '<':
case ',':
- case KEY_F(18):
case '>':
case '.':
+ {
+ sortBy(panel, pl, settings, headerHeight, defaultBar, header);
+ refreshTimeout = 0;
+ break;
+ }
+ case KEY_F(18):
case KEY_F(6):
{
- Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem));
- Panel_setHeader(sortPanel, "Sort by");
- const char* fuFunctions[] = {"Sort ", "Cancel ", NULL};
- ProcessField* fields = pl->fields;
- for (int i = 0; fields[i]; i++) {
- char* name = String_trim(Process_fieldNames[fields[i]]);
- Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
- if (fields[i] == pl->sortKey)
- Panel_setSelected(sortPanel, i);
- free(name);
- }
- ListItem* field = (ListItem*) pickFromVector(panel, sortPanel, 15, headerHeight, fuFunctions, defaultBar, header);
- if (field) {
- settings->changed = true;
- setSortKey(pl, field->key, panel, settings);
+ if (pl->treeView) {
+ if (expandCollapse(panel)) {
+ doRecalculate = true;
+ refreshTimeout = 0;
+ }
} else {
- ProcessList_printHeader(pl, Panel_getHeader(panel));
+ sortBy(panel, pl, settings, headerHeight, defaultBar, header);
+ refreshTimeout = 0;
}
- Object_delete(sortPanel);
- refreshTimeout = 0;
break;
}
case 'i':
@@ -842,7 +896,8 @@ int main(int argc, char** argv) {
case 't':
case KEY_F(5):
refreshTimeout = 0;
- pl->treeView = !pl->treeView;
+ collapsed = false;
+ setTreeView(pl, defaultBar, !pl->treeView);
if (pl->treeView) pl->direction = 1;
ProcessList_printHeader(pl, Panel_getHeader(panel));
ProcessList_expandTree(pl);
diff --git a/htop.h b/htop.h
index 7338010e..354a2f99 100644
--- a/htop.h
+++ b/htop.h
@@ -15,6 +15,8 @@ in the source distribution for its full text.
typedef bool(*ForeachProcessFn)(Process*, size_t);
+void sortBy(Panel* panel, ProcessList* pl, Settings* settings, int headerHeight, FunctionBar* defaultBar, Header* header);
+
int main(int argc, char** argv);
#endif

© 2014-2024 Faster IT GmbH | imprint | privacy policy