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};

Reply via email to