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 <[email protected]>
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};