diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index 3b9e6cc43..4eb56177a 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -113,6 +113,8 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_newByRef("- Tree view is collapsed by default", &(settings->ss->allBranchesCollapsed))); Panel_add(super, (Object*) TextItem_new("Global options:")); Panel_add(super, (Object*) CheckItem_newByRef("Show tabs for screens", &(settings->screenTabs))); + Panel_add(super, (Object*) CheckItem_newByRef("Show parent processes during filter", &(settings->showParentsInFilter))); + Panel_add(super, (Object*) CheckItem_newByRef("Show children processes during filter", &(settings->showChildrenInFilter))); Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers))); Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads))); Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads))); diff --git a/ProcessList.c b/ProcessList.c index d11567893..90cbf2b1f 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -370,6 +370,16 @@ void ProcessList_collapseAllBranches(ProcessList* this) { } } +static void ProcessList_filterChildren(ProcessList *this, pid_t pid, Hashtable *processFilter) { + for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { + Process *p = (Process*) (Vector_get(this->processes, i)); + if (p->pid != pid && Process_isChildOf(p, pid)) { + Hashtable_put(processFilter, p->pid, (void*) 1); + ProcessList_filterChildren(this, p->pid, processFilter); + } + } +} + void ProcessList_rebuildPanel(ProcessList* this) { ProcessList_updateDisplayList(this); @@ -392,6 +402,26 @@ void ProcessList_rebuildPanel(ProcessList* this) { const int processCount = Vector_size(this->displayList); int idx = 0; + + // Mark Children and Parent for F4-Filter + Hashtable* filteredProcesses = Hashtable_new(processCount, false); + for (int i = 0; i < processCount; i++) { + Process* p = (Process*)Vector_get(this->processes, i); + pid_t ppid = Process_getParentPid(p); + + if (incFilter && !(String_contains_i(Process_getCommand(p), incFilter, true))) + continue; + + if (this->settings->showChildrenInFilter) + ProcessList_filterChildren(this, p->pid, filteredProcesses); + + do { + Hashtable_put(filteredProcesses, p->pid, (void*) 1); + ppid = Process_getParentPid(p); + p = Hashtable_get(this->processTable, ppid); + } while (this->settings->showParentsInFilter && p && p->pid != p->ppid); + } + bool foundFollowed = false; for (int i = 0; i < processCount; i++) { @@ -399,7 +429,7 @@ void ProcessList_rebuildPanel(ProcessList* this) { if ( (!p->show) || (this->userId != (uid_t) -1 && (p->st_uid != this->userId)) - || (incFilter && !(String_contains_i(Process_getCommand(p), incFilter, true))) + || (incFilter && !Hashtable_get(filteredProcesses, p->pid)) || (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) ) continue; @@ -428,6 +458,7 @@ void ProcessList_rebuildPanel(ProcessList* this) { this->panel->scrollV = currScrollV; } + Hashtable_delete(filteredProcesses); } Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor) { diff --git a/Settings.c b/Settings.c index f1664d37a..00e5d7ee7 100644 --- a/Settings.c +++ b/Settings.c @@ -378,6 +378,10 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini // old (no screen) naming also supported for backwards compatibility screen = Settings_defaultScreens(this); screen->allBranchesCollapsed = atoi(option[1]); + } else if (String_eq(option[0], "show_parents_in_filter")) { + this->showParentsInFilter = atoi(option[1]); + } else if (String_eq(option[0], "show_children_in_filter")) { + this->showChildrenInFilter = atoi(option[1]); } else if (String_eq(option[0], "hide_kernel_threads")) { this->hideKernelThreads = atoi(option[1]); } else if (String_eq(option[0], "hide_userland_threads")) { @@ -624,6 +628,8 @@ int Settings_write(const Settings* this, bool onCrash) { // Legacy compatibility with older versions of htop printSettingInteger("tree_view", this->screens[0]->treeView); // This "-1" is for compatibility with the older enum format. + printSettingInteger("show_parents_in_filter", this->showParentsInFilter); + printSettingInteger("show_children_in_filter", this->showChildrenInFilter); printSettingInteger("sort_key", this->screens[0]->sortKey - 1); printSettingInteger("tree_sort_key", this->screens[0]->treeSortKey - 1); printSettingInteger("sort_direction", this->screens[0]->direction); @@ -673,6 +679,8 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) this->hideKernelThreads = true; this->hideUserlandThreads = false; this->hideRunningInContainer = false; + this->showParentsInFilter = false; + this->showChildrenInFilter = false; this->highlightBaseName = false; this->highlightDeletedExe = true; this->highlightMegabytes = true; diff --git a/Settings.h b/Settings.h index f6a6ea653..8707a76cf 100644 --- a/Settings.h +++ b/Settings.h @@ -69,6 +69,8 @@ typedef struct Settings_ { bool showCPUTemperature; bool degreeFahrenheit; #endif + bool showParentsInFilter; + bool showChildrenInFilter; bool showProgramPath; bool shadowOtherUsers; bool showThreadNames;