I'd like to propose a new package btop, which is a feature-rich resource monitor. btop is ready for many Linux distributions including Fedora.
Thanks in advance. -- Takashi Yano <takashi.y...@nifty.ne.jp>
NAME="btop" VERSION=1.3.0 RELEASE=1 LICENSE="Apache-2.0" CATEGORY="System" SUMMARY="Resource monitor with rich features." DESCRIPTION="Resource monitor that shows usage and stats for processor, memory, disks, network and processes." HOMEPAGE="https://github.com/aristocratos/btop" SRC_URI="https://github.com/aristocratos/btop/archive/refs/tags/v${VERSION}.tar.gz" PATCH_URI="fix-gcc13-warnings.patch" inherit cmake
--- origsrc/btop-1.3.0/CMakeLists.txt 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/CMakeLists.txt 2024-01-24 21:19:32.514670900 +0900 @@ -66,6 +66,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeB target_sources(btop PRIVATE src/freebsd/btop_collect.cpp) elseif(LINUX) target_sources(btop PRIVATE src/linux/btop_collect.cpp) +elseif(CYGWIN) + target_sources(btop PRIVATE src/linux/btop_collect.cpp) else() message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supported") endif() @@ -184,6 +186,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeB find_package(kvm REQUIRED) target_link_libraries(btop elf::elf kvm::kvm) endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "CYGWIN") + target_link_libraries(btop pdh iphlpapi) endif() install(TARGETS btop RUNTIME) --- origsrc/btop-1.3.0/Makefile 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/Makefile 2024-01-24 21:19:32.514670900 +0900 @@ -34,7 +34,7 @@ else ARCH ?= $(shell $(CXX) -dumpmachine | cut -d "-" -f 1) endif -override PLATFORM_LC := $(shell echo $(PLATFORM) | tr '[:upper:]' '[:lower:]') +override PLATFORM_LC := $(shell echo $(PLATFORM) | tr '[:upper:]' '[:lower:]' | sed 's/-.*$$//' ) #? GPU Support ifeq ($(PLATFORM_LC)$(ARCH),linuxx86_64) @@ -141,6 +141,11 @@ else ifeq ($(PLATFORM_LC),openbsd) override ADDFLAGS += -lkvm export MAKE = gmake SU_GROUP := wheel +else ifeq ($(PLATFORM_LC),cygwin_nt) + PLATFORM_DIR := linux + THREADS := $(shell getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1) + override ADDFLAGS += -lpdh -liphlpapi + SU_GROUP := Administrators else $(error $(shell printf "\033[1;91mERROR: \033[97mUnsupported platform ($(PLATFORM))\033[0m")) endif --- origsrc/btop-1.3.0/src/btop.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop.cpp 2024-01-24 21:19:32.524679000 +0900 @@ -16,6 +16,10 @@ indent = tab tab-size = 4 */ +#ifdef __CYGWIN__ +#define _GNU_SOURCE 1 +#endif + #include <algorithm> #include <csignal> #include <clocale> --- origsrc/btop-1.3.0/src/btop_config.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop_config.cpp 2024-01-24 21:19:32.524679000 +0900 @@ -16,6 +16,10 @@ indent = tab tab-size = 4 */ +#ifdef __CYGWIN__ +#define _GNU_SOURCE +#endif + #include <array> #include <atomic> #include <fstream> @@ -284,7 +288,11 @@ namespace Config { {"swap_disk", true}, {"show_disks", true}, {"only_physical", true}, +#ifdef __CYGWIN__ + {"use_fstab", false}, +#else {"use_fstab", true}, +#endif {"zfs_hide_datasets", false}, {"show_io_stat", true}, {"io_mode", false}, --- origsrc/btop-1.3.0/src/btop_input.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop_input.cpp 2024-01-24 21:19:32.524679000 +0900 @@ -16,6 +16,10 @@ indent = tab tab-size = 4 */ +#ifdef __CYGWIN__ +#define _GNU_SOURCE 1 +#endif + #include <limits> #include <ranges> #include <vector> --- origsrc/btop-1.3.0/src/btop_menu.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop_menu.cpp 2024-01-24 21:19:32.524679000 +0900 @@ -16,6 +16,10 @@ indent = tab tab-size = 4 */ +#ifdef __CYGWIN__ +#define _GNU_SOURCE +#endif + #include <deque> #include <unordered_map> #include <array> --- origsrc/btop-1.3.0/src/btop_tools.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop_tools.cpp 2024-01-24 21:19:32.524679000 +0900 @@ -16,6 +16,10 @@ indent = tab tab-size = 4 */ +#ifdef __CYGWIN__ +#define _GNU_SOURCE 1 +#endif + #include <cmath> #include <codecvt> #include <iostream> --- origsrc/btop-1.3.0/src/linux/btop_collect.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/linux/btop_collect.cpp 2024-01-24 21:19:32.534678900 +0900 @@ -16,6 +16,10 @@ indent = tab tab-size = 4 */ +#ifdef __CYGWIN__ +#define _GNU_SOURCE +#endif + #include <cstdlib> #include <unordered_map> #include <unordered_set> @@ -43,6 +47,102 @@ tab-size = 4 #include <pwd.h> #endif +#ifdef __CYGWIN__ +typedef uint32_t DWORD; +typedef long long LONGLONG; +typedef unsigned long ULONG; +typedef unsigned long ULONG_PTR; +typedef long LONG; +typedef unsigned int UINT; +typedef uint8_t BYTE; +typedef char CHAR; +typedef int BOOL; +typedef void *HANDLE; +typedef void *HQUERY; +typedef void *HCOUNTER; +typedef struct { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME; +typedef struct { + DWORD CStatus; + FILETIME TimeStamp; + LONGLONG FirstValue; + LONGLONG SecondValue; + DWORD MultiCount; +} PDH_RAW_COUNTER; +#define PDH_FMT_DOUBLE ((DWORD) 0x00000200) +typedef struct { + DWORD CStatus; + union { + long longValue; + double doubleValue; + LONGLONG largeValue; + char *AnsiStringValue; + wchar_t *WideStringValue; + }; +} PDH_FMT_COUNTERVALUE; +typedef struct { + char *String[4*4]; +} IP_ADDRESS_STRING, IP_MASK_STRING; +typedef struct _IP_ADDR_STRING { + struct _IP_ADDR_STRING *Next; + IP_ADDRESS_STRING IpAddress; + IP_MASK_STRING IpMask; + DWORD Context; +} IP_ADDR_STRING, *PIP_ADDR_STRING; +#define MAX_ADAPTER_ADDRESS_LENGTH 8 +#define MAX_ADAPTER_NAME_LENGTH 256 +#define MAX_ADAPTER_DESCRIPTION_LENGTH 128 +typedef struct _IP_ADAPTER_INFO { + struct _IP_ADAPTER_INFO *Next; + DWORD ComboIndex; + char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; + char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; + UINT AddressLength; + BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; + DWORD Index; + UINT Type; + UINT DhcpEnabled; + PIP_ADDR_STRING CurrentIpAddress; + IP_ADDR_STRING IpAddressList; + IP_ADDR_STRING GatewayList; + IP_ADDR_STRING DhcpServer; + BOOL HaveWins; + IP_ADDR_STRING PrimaryWinsServer; + IP_ADDR_STRING SecondaryWinsServer; + time_t LeaseObtained; + time_t LeaseExpires; +} IP_ADAPTER_INFO; +#define MAX_PATH 260 +typedef struct { + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + LONG pcPriClassBase; + DWORD dwFlags; + CHAR szExeFile[MAX_PATH]; +} PROCESSENTRY32; +#define TH32CS_SNAPPROCESS 0x00000002 +extern "C" { + ULONG GetAdaptersInfo(IP_ADAPTER_INFO *, ULONG *); + DWORD PdhOpenQuery(char *, DWORD *, HQUERY *); + DWORD PdhAddCounterA(HQUERY, char *, DWORD *, HCOUNTER *); + DWORD PdhCollectQueryData(HQUERY); + DWORD PdhGetRawCounterValue(HCOUNTER, DWORD *, PDH_RAW_COUNTER *); + DWORD PdhGetFormattedCounterValue(HCOUNTER, DWORD, DWORD *, PDH_FMT_COUNTERVALUE *); + DWORD PdhCalculateCounterFromRawValue(HCOUNTER, DWORD, PDH_RAW_COUNTER *, PDH_RAW_COUNTER *, PDH_FMT_COUNTERVALUE *); + DWORD PdhCloseQuery(HQUERY); + HANDLE CreateToolhelp32Snapshot(DWORD, DWORD); + BOOL Process32First(HANDLE, PROCESSENTRY32 *); + BOOL Process32Next(HANDLE, PROCESSENTRY32 *); +} +#endif + #include "../btop_shared.hpp" #include "../btop_config.hpp" #include "../btop_tools.hpp" @@ -232,11 +332,15 @@ namespace Shared { } } +#ifdef __CYGWIN__ + pageSize = 4096; +#else pageSize = sysconf(_SC_PAGE_SIZE); if (pageSize <= 0) { pageSize = 4096; Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect."); } +#endif clkTck = sysconf(_SC_CLK_TCK); if (clkTck <= 0) { @@ -1632,6 +1736,9 @@ namespace Mem { static vector<string> ignore_list; double uptime = system_uptime(); auto free_priv = Config::getB("disk_free_priv"); +#ifdef __CYGWIN__ + string root_dev; +#endif try { auto& disks_filter = Config::getS("disks_filter"); bool filter_exclude = false; @@ -1639,7 +1746,9 @@ namespace Mem { auto only_physical = Config::getB("only_physical"); auto zfs_hide_datasets = Config::getB("zfs_hide_datasets"); auto& disks = mem.disks; +#ifndef __CYGWIN__ static std::unordered_map<string, future<pair<disk_info, int>>> disks_stats_promises; +#endif ifstream diskread; vector<string> filter; @@ -1693,6 +1802,18 @@ namespace Mem { } //? Get mounts from /etc/mtab or /proc/self/mounts +#ifdef __CYGWIN__ + diskread.open((fs::exists("/etc/mtab") ? fs::path("/etc/mtab") : Shared::procPath / "self/mounts")); + if (diskread.good()) { + string dev, mountpoint, fstype; + while (not diskread.eof()) { + diskread >> dev >> mountpoint >> fstype; + diskread.ignore(SSmax, '\n'); + if (mountpoint == "/") root_dev = dev; + } + diskread.close(); + } +#endif diskread.open((fs::exists("/etc/mtab") ? fs::path("/etc/mtab") : Shared::procPath / "self/mounts")); if (diskread.good()) { vector<string> found; @@ -1715,6 +1836,9 @@ namespace Mem { //? Skip ZFS datasets if zfs_hide_datasets option is enabled size_t zfs_dataset_name_start = 0; if (fstype == "zfs" && (zfs_dataset_name_start = dev.find('/')) != std::string::npos && zfs_hide_datasets) continue; +#ifdef __CYGWIN__ + if (not (mountpoint == "/") and dev.starts_with(root_dev)) continue; +#endif if ((not use_fstab and not only_physical) or (use_fstab and v_contains(fstab, mountpoint)) @@ -1779,6 +1903,23 @@ namespace Mem { diskread.close(); //? Get disk/partition stats +#ifdef __CYGWIN__ + /* Cygwin has a bug that handle leak occurs if std::async is used. */ + for (auto& [mountpoint, disk] : disks) { + if (std::error_code ec; not fs::exists(mountpoint, ec) or v_contains(ignore_list, mountpoint)) continue; + struct statvfs vfs; + if (statvfs(mountpoint.c_str(), &vfs) < 0) { + Logger::warning("Failed to get disk/partition stats for mount \""+ mountpoint + "\" with statvfs error code: " + to_string(errno) + ". Ignoring..."); + ignore_list.push_back(mountpoint); + continue; + } + disk.total = vfs.f_blocks * vfs.f_frsize; + disk.free = (free_priv ? vfs.f_bfree : vfs.f_bavail) * vfs.f_frsize; + disk.used = disk.total - disk.free; + disk.used_percent = round((double)disk.used * 100 / disk.total); + disk.free_percent = 100 - disk.used_percent; + } +#else for (auto it = disks.begin(); it != disks.end(); ) { auto &[mountpoint, disk] = *it; if (v_contains(ignore_list, mountpoint) or disk.name == "swap") { @@ -1821,6 +1962,7 @@ namespace Mem { }); ++it; } +#endif //? Setup disks order in UI and add swap if enabled mem.disks_order.clear(); @@ -1846,6 +1988,72 @@ namespace Mem { #endif //? Get disks IO +#ifdef __CYGWIN__ + /* Cygwin does not have means to provide statistics of disk I/O. + Because there is no other choice, use WIN32API instead. */ + int64_t bytes_read, bytes_write; + disk_ios = 0; + static std::unordered_map<string, PDH_RAW_COUNTER> RawCounterReadTimeOld, RawCounterWriteTimeOld; + for (auto& [mountpoint, disk] : disks) { + char perf_counter_read[1024], perf_counter_write[1024]; + char perf_counter_read_time[1024], perf_counter_write_time[1024]; + HQUERY hQuery; + HCOUNTER hCounterRead, hCounterWrite; + HCOUNTER hCounterReadTime, hCounterWriteTime; + PDH_RAW_COUNTER RawCounterRead, RawCounterWrite; + PDH_RAW_COUNTER RawCounterReadTime, RawCounterWriteTime; + PDH_FMT_COUNTERVALUE FmtCounterReadTime, FmtCounterWriteTime; + string dev = disk.dev; + + if (dev.empty() or dev.find(':') == std::string::npos) continue; + + sprintf(perf_counter_read, "\\LogicalDisk(%s)\\Disk Read Bytes/sec", dev.substr(0, 2).c_str()); + sprintf(perf_counter_write, "\\LogicalDisk(%s)\\Disk Write Bytes/sec", dev.substr(0, 2).c_str()); + sprintf(perf_counter_read_time, "\\LogicalDisk(%s)\\%% Disk Read Time", dev.substr(0, 2).c_str()); + sprintf(perf_counter_write_time, "\\LogicalDisk(%s)\\%% Disk Write Time", dev.substr(0, 2).c_str()); + + PdhOpenQuery(NULL, 0, &hQuery); + PdhAddCounterA(hQuery, perf_counter_read, 0, &hCounterRead); + PdhAddCounterA(hQuery, perf_counter_write, 0, &hCounterWrite); + PdhAddCounterA(hQuery, perf_counter_read_time, 0, &hCounterReadTime); + PdhAddCounterA(hQuery, perf_counter_write_time, 0, &hCounterWriteTime); + PdhCollectQueryData(hQuery); + PdhGetRawCounterValue(hCounterRead, NULL, &RawCounterRead); + PdhGetRawCounterValue(hCounterWrite, NULL, &RawCounterWrite); + PdhGetRawCounterValue(hCounterReadTime, NULL, &RawCounterReadTime); + PdhGetRawCounterValue(hCounterWriteTime, NULL, &RawCounterWriteTime); + + if (RawCounterReadTimeOld.find(mountpoint) == RawCounterReadTimeOld.end()) { + FmtCounterReadTime.doubleValue = 0; + } else { + PdhCalculateCounterFromRawValue(hCounterReadTime, PDH_FMT_DOUBLE, + &RawCounterReadTime, &RawCounterReadTimeOld[mountpoint], &FmtCounterReadTime); + } + if (RawCounterWriteTimeOld.find(mountpoint) == RawCounterWriteTimeOld.end()) { + FmtCounterWriteTime.doubleValue = 0; + } else { + PdhCalculateCounterFromRawValue(hCounterWriteTime, PDH_FMT_DOUBLE, + &RawCounterWriteTime, &RawCounterWriteTimeOld[mountpoint], &FmtCounterWriteTime); + } + PdhCloseQuery(hQuery); + + RawCounterReadTimeOld[mountpoint] = RawCounterReadTime; + RawCounterWriteTimeOld[mountpoint] = RawCounterWriteTime; + + bytes_read = RawCounterRead.FirstValue; + disk.io_read.push_back(max((int64_t)0, bytes_read - disk.old_io.at(0))); + disk.old_io.at(0) = bytes_read; + while (cmp_greater(disk.io_read.size(), width * 2)) disk.io_read.pop_front(); + + bytes_write = RawCounterWrite.FirstValue; + disk.io_write.push_back(max((int64_t)0, bytes_write - disk.old_io.at(1))); + disk.old_io.at(1) = bytes_write; + while (cmp_greater(disk.io_write.size(), width * 2)) disk.io_write.pop_front(); + + disk.io_activity.push_back(clamp((long)round(FmtCounterReadTime.doubleValue + FmtCounterWriteTime.doubleValue), 0l, 100l)); + while (cmp_greater(disk.io_activity.size(), width * 2)) disk.io_activity.pop_front(); + } +#else int64_t sectors_read, sectors_write, io_ticks, io_ticks_temp; disk_ios = 0; for (auto& [ignored, disk] : disks) { @@ -1929,6 +2137,7 @@ namespace Mem { } diskread.close(); } +#endif old_uptime = uptime; } catch (const std::exception& e) { @@ -2121,6 +2330,9 @@ namespace Net { //? Iteration over all items in getifaddrs() list for (auto* ifa = if_wrap(); ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr == nullptr) continue; +#ifdef __CYGWIN__ + if ((ifa->ifa_flags & IFF_RUNNING) == 0) continue; +#endif family = ifa->ifa_addr->sa_family; const auto& iface = ifa->ifa_name; @@ -2162,6 +2374,80 @@ namespace Net { } //? Get total recieved and transmitted bytes + device address if no ip was found +#ifdef __CYGWIN__ + /* Cygwin does not have means to provide statistics of network interfaces. + Because there is no other choice, use WIN32API instead. */ + do { + char buf[65536]; + ULONG adapters_size = sizeof(buf); + IP_ADAPTER_INFO *adapters = (IP_ADAPTER_INFO *) buf; + GetAdaptersInfo(adapters, &adapters_size); + + for (const auto& iface : interfaces) { + char perf_counter_download[1024], perf_counter_upload[1024]; + HQUERY hQuery; + HCOUNTER hCounterDown, hCounterUp; + PDH_RAW_COUNTER RawCounterDown, RawCounterUp; + for (IP_ADAPTER_INFO *p = adapters; p; p = p->Next) { + if (p->AdapterName == iface) { + char *q = p->Description; + while ((q = strchr(q, '('))) *q = '['; + q = p->Description; + while ((q = strchr(q, ')'))) *q = ']'; + sprintf(perf_counter_download, "\\Network Interface(%s)\\Bytes Received/sec", p->Description); + sprintf(perf_counter_upload, "\\Network Interface(%s)\\Bytes Sent/sec", p->Description); + break; + } + } + PdhOpenQuery(NULL, 0, &hQuery); + PdhAddCounterA(hQuery, perf_counter_download, 0, &hCounterDown); + PdhAddCounterA(hQuery, perf_counter_upload, 0, &hCounterUp); + PdhCollectQueryData(hQuery); + PdhGetRawCounterValue(hCounterDown, NULL, &RawCounterDown); + PdhGetRawCounterValue(hCounterUp, NULL, &RawCounterUp); + PdhCloseQuery(hQuery); + for (const string dir : {"download", "upload"}) { + auto& saved_stat = net.at(iface).stat.at(dir); + auto& bandwidth = net.at(iface).bandwidth.at(dir); + uint64_t val{}; + + val = (dir == "download") ? RawCounterDown.FirstValue : RawCounterUp.FirstValue; + + //? Update speed, total and top values + if (val < saved_stat.last) { + saved_stat.rollover += saved_stat.last; + saved_stat.last = 0; + } + if (cmp_greater((unsigned long long)saved_stat.rollover + (unsigned long long)val, numeric_limits<uint64_t>::max())) { + saved_stat.rollover = 0; + saved_stat.last = 0; + } + saved_stat.speed = round((double)(val - saved_stat.last) / ((double)(new_timestamp - timestamp) / 1000)); + if (saved_stat.speed > saved_stat.top) saved_stat.top = saved_stat.speed; + if (saved_stat.offset > val + saved_stat.rollover) saved_stat.offset = 0; + saved_stat.total = (val + saved_stat.rollover) - saved_stat.offset; + saved_stat.last = val; + + //? Add values to graph + bandwidth.push_back(saved_stat.speed); + while (cmp_greater(bandwidth.size(), width * 2)) bandwidth.pop_front(); + + //? Set counters for auto scaling + if (net_auto and selected_iface == iface) { + if (net_sync and saved_stat.speed < net.at(iface).stat.at(dir == "download" ? "upload" : "download").speed) continue; + if (saved_stat.speed > graph_max[dir]) { + ++max_count[dir][0]; + if (max_count[dir][1] > 0) --max_count[dir][1]; + } + else if (graph_max[dir] > 10 << 10 and saved_stat.speed < graph_max[dir] / 10) { + ++max_count[dir][1]; + if (max_count[dir][0] > 0) --max_count[dir][0]; + } + } + } + } + } while (false); +#else for (const auto& iface : interfaces) { if (net.at(iface).ipv4.empty() and net.at(iface).ipv6.empty()) net.at(iface).ipv4 = readfile("/sys/class/net/" + iface + "/address"); @@ -2210,6 +2496,7 @@ namespace Net { } } } +#endif //? Clean up net map if needed if (net.size() > interfaces.size()) { @@ -2376,6 +2663,28 @@ namespace Proc { while (cmp_greater(detailed.mem_bytes.size(), width)) detailed.mem_bytes.pop_front(); +#ifdef __CYGWIN__ + /* Cygwin does not have means to provide statistics of I/O. + Because there is no other choice, use WIN32API instead. */ + char perf_counter_read[1024], perf_counter_write[1024]; + HQUERY hQuery; + HCOUNTER hCounterRead, hCounterWrite; + PDH_RAW_COUNTER RawCounterRead, RawCounterWrite; + + sprintf(perf_counter_read, "\\Process(%s)\\IO Read Bytes/sec", p_info->name.c_str()); + sprintf(perf_counter_write, "\\Process(%s)\\IO Write Bytes/sec", p_info->name.c_str()); + + PdhOpenQuery(NULL, 0, &hQuery); + PdhAddCounterA(hQuery, perf_counter_read, 0, &hCounterRead); + PdhAddCounterA(hQuery, perf_counter_write, 0, &hCounterWrite); + PdhCollectQueryData(hQuery); + PdhGetRawCounterValue(hCounterRead, NULL, &RawCounterRead); + PdhGetRawCounterValue(hCounterWrite, NULL, &RawCounterWrite); + PdhCloseQuery(hQuery); + + detailed.io_read = floating_humanizer(RawCounterRead.FirstValue); + detailed.io_write = floating_humanizer(RawCounterWrite.FirstValue); +#else //? Get bytes read and written from proc/[pid]/io if (fs::exists(pid_path / "io")) { d_read.open(pid_path / "io"); @@ -2400,6 +2709,7 @@ namespace Proc { catch (const std::out_of_range&) {} d_read.close(); } +#endif } //* Collects and sorts process information from /proc @@ -2486,6 +2796,11 @@ namespace Proc { else throw std::runtime_error("Failure to read /proc/stat"); pread.close(); +#ifdef __CYGWIN__ + /* Cygwin does not have means to provide number of thread in the process. + Because there is no other choice, use WIN32API instead. */ + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); +#endif //? Iterate over all pids in /proc for (const auto& d: fs::directory_iterator(Shared::procPath)) { if (Runner::stopping) @@ -2517,10 +2832,12 @@ namespace Proc { //? Get program name, command and username if (no_cache) { +#ifndef __CYGWIN__ pread.open(d.path() / "comm"); if (not pread.good()) continue; getline(pread, new_proc.name); pread.close(); +#endif //? Check for whitespace characters in name and set offset to get correct fields from stat file new_proc.name_offset = rng::count(new_proc.name, ' '); @@ -2547,6 +2864,10 @@ namespace Proc { pread.ignore(); getline(pread, uid, '\t'); break; +#ifdef __CYGWIN__ + } else if (line == "Name") { + pread >> std::skipws >> new_proc.name; +#endif } else { pread.ignore(SSmax, '\n'); } @@ -2635,6 +2956,27 @@ namespace Proc { pread.close(); +#ifdef __CYGWIN__ + /* Cygwin does not have means to provide number of thread in the process. + Because there is no other choice, use WIN32API instead. */ + pread.open(d.path() / "winpid"); + if (pread.good()) { + DWORD winpid; + PROCESSENTRY32 pe; + pread >> winpid; + pread.close(); + pe.dwSize = sizeof(PROCESSENTRY32); + if (Process32First(snap, &pe)) { + do { + if (pe.th32ProcessID == winpid) { + new_proc.threads = pe.cntThreads; + break; + } + } while (Process32Next(snap, &pe)); + } + } +#endif + if (should_filter_kernel and new_proc.ppid == KTHREADD) { kernels_procs.emplace(new_proc.pid); found.pop_back();
diff -ru origsrc/btop-1.3.0/src/btop_draw.cpp src/btop-1.3.0/src/btop_draw.cpp --- origsrc/btop-1.3.0/src/btop_draw.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop_draw.cpp 2024-01-24 23:21:05.802983100 +0900 @@ -797,7 +797,7 @@ + Theme::g("cpu").at(clamp(safeVal(cpu.cpu_percent, "total"s).back(), 0ll, 100ll)) + rjust(to_string(safeVal(cpu.cpu_percent, "total"s).back()), 4) + Theme::c("main_fg") + '%'; if (show_temps) { const auto [temp, unit] = celsius_to(safeVal(cpu.temp, 0).back(), temp_scale); - const auto& temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, 0).back() * 100 / cpu.temp_max, 0ll, 100ll)); + const auto temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, 0).back() * 100 / cpu.temp_max, 0ll, 100ll)); if ((b_column_size > 1 or b_columns > 1) and temp_graphs.size() >= 1ll) out += ' ' + Theme::c("inactive_fg") + graph_bg * 5 + Mv::l(5) + temp_color + temp_graphs.at(0)(safeVal(cpu.temp, 0), data_same or redraw); @@ -823,7 +823,7 @@ if (show_temps and not hide_cores and std::cmp_greater_equal(temp_graphs.size(), n)) { const auto [temp, unit] = celsius_to(safeVal(cpu.temp, n+1).back(), temp_scale); - const auto& temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, n+1).back() * 100 / cpu.temp_max, 0ll, 100ll)); + const auto temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, n+1).back() * 100 / cpu.temp_max, 0ll, 100ll)); if (b_column_size > 1) out += ' ' + Theme::c("inactive_fg") + graph_bg * 5 + Mv::l(5) + temp_graphs.at(n+1)(safeVal(cpu.temp, n+1), data_same or redraw); @@ -1273,7 +1273,7 @@ for (const auto& mount : mem.disks_order) { if (not disks.contains(mount)) continue; if (cy > height - 3) break; - const auto& disk = safeVal(disks, mount); + const auto disk = safeVal(disks, mount); if (disk.io_read.empty()) continue; const string total = floating_humanizer(disk.total, not big_disk); out += Mv::to(y+1+cy, x+1+cx) + divider + Theme::c("title") + Fx::b + uresize(disk.name, disks_width - 8) + Mv::to(y+1+cy, x+cx + disks_width - total.size()) @@ -1312,7 +1312,7 @@ for (const auto& mount : mem.disks_order) { if (not disks.contains(mount)) continue; if (cy > height - 3) break; - const auto& disk = safeVal(disks, mount); + const auto disk = safeVal(disks, mount); if (disk.name.empty() or not disk_meters_used.contains(mount)) continue; auto comb_val = (not disk.io_read.empty() ? disk.io_read.back() + disk.io_write.back() : 0ll); const string human_io = (comb_val > 0 ? (disk.io_write.back() > 0 and big_disk ? "â¼"s : ""s) + (disk.io_read.back() > 0 and big_disk ? "â²"s : ""s) @@ -1604,8 +1604,8 @@ out += Mv::to(d_y, d_x - 1) + Theme::c("proc_box") + Symbols::div_up + Mv::to(y, d_x - 1) + Symbols::div_down + Theme::c("div_line"); for (const int& i : iota(1, 8)) out += Mv::to(d_y + i, d_x - 1) + Symbols::v_line; - const string& t_color = (not alive or selected > 0 ? Theme::c("inactive_fg") : Theme::c("title")); - const string& hi_color = (not alive or selected > 0 ? t_color : Theme::c("hi_fg")); + const string t_color = (not alive or selected > 0 ? Theme::c("inactive_fg") : Theme::c("title")); + const string hi_color = (not alive or selected > 0 ? t_color : Theme::c("hi_fg")); const string hide = (selected > 0 ? t_color + "hide " : Theme::c("title") + "hide " + Theme::c("hi_fg")); int mouse_x = d_x + 2; out += Mv::to(d_y, d_x + 1); diff -ru origsrc/btop-1.3.0/src/btop_menu.cpp src/btop-1.3.0/src/btop_menu.cpp --- origsrc/btop-1.3.0/src/btop_menu.cpp 2024-01-07 23:23:01.000000000 +0900 +++ src/btop-1.3.0/src/btop_menu.cpp 2024-01-24 23:19:42.301762700 +0900 @@ -801,12 +805,12 @@ string msgBox::operator()() { string out; int pos = width / 2 - (boxtype == 0 ? 6 : 14); - auto& first_color = (selected == 0 ? Theme::c("hi_fg") : Theme::c("div_line")); + auto first_color = (selected == 0 ? Theme::c("hi_fg") : Theme::c("div_line")); out = Mv::d(1) + Mv::r(pos) + Fx::b + first_color + button_left + (selected == 0 ? Theme::c("title") : Theme::c("main_fg") + Fx::ub) + (boxtype == 0 ? " Ok " : " Yes ") + first_color + button_right; mouse_mappings["button1"] = Input::Mouse_loc{y + height - 4, x + pos + 1, 3, 12 + (boxtype > 0 ? 1 : 0)}; if (boxtype > 0) { - auto& second_color = (selected == 1 ? Theme::c("hi_fg") : Theme::c("div_line")); + auto second_color = (selected == 1 ? Theme::c("hi_fg") : Theme::c("div_line")); out += Mv::r(2) + second_color + button_left + (selected == 1 ? Theme::c("title") : Theme::c("main_fg") + Fx::ub) + " No " + second_color + button_right; mouse_mappings["button2"] = Input::Mouse_loc{y + height - 4, x + pos + 15 + (boxtype > 0 ? 1 : 0), 3, 12};