diff --git a/.suckless/slstatus/components/battery.c b/.suckless/slstatus/components/battery.c new file mode 100644 index 0000000..1c753f9 --- /dev/null +++ b/.suckless/slstatus/components/battery.c @@ -0,0 +1,247 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) +/* + * https://www.kernel.org/doc/html/latest/power/power_supply_class.html + */ + #include + #include + #include + + #define POWER_SUPPLY_CAPACITY "/sys/class/power_supply/%s/capacity" + #define POWER_SUPPLY_STATUS "/sys/class/power_supply/%s/status" + #define POWER_SUPPLY_CHARGE "/sys/class/power_supply/%s/charge_now" + #define POWER_SUPPLY_ENERGY "/sys/class/power_supply/%s/energy_now" + #define POWER_SUPPLY_CURRENT "/sys/class/power_supply/%s/current_now" + #define POWER_SUPPLY_POWER "/sys/class/power_supply/%s/power_now" + + static const char * + pick(const char *bat, const char *f1, const char *f2, char *path, + size_t length) + { + if (esnprintf(path, length, f1, bat) > 0 && + access(path, R_OK) == 0) + return f1; + + if (esnprintf(path, length, f2, bat) > 0 && + access(path, R_OK) == 0) + return f2; + + return NULL; + } + + const char * + battery_perc(const char *bat) + { + int cap_perc; + char path[PATH_MAX]; + + if (esnprintf(path, sizeof(path), POWER_SUPPLY_CAPACITY, bat) < 0) + return NULL; + if (pscanf(path, "%d", &cap_perc) != 1) + return NULL; + + return bprintf("%d", cap_perc); + } + + const char * + battery_state(const char *bat) + { + static struct { + char *state; + char *symbol; + } map[] = { + { "Charging", "+" }, + { "Discharging", "-" }, + { "Full", "o" }, + { "Not charging", "o" }, + }; + size_t i; + char path[PATH_MAX], state[12]; + + if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0) + return NULL; + if (pscanf(path, "%12[a-zA-Z ]", state) != 1) + return NULL; + + for (i = 0; i < LEN(map); i++) + if (!strcmp(map[i].state, state)) + break; + + return (i == LEN(map)) ? "?" : map[i].symbol; + } + + const char * + battery_remaining(const char *bat) + { + uintmax_t charge_now, current_now, m, h; + double timeleft; + char path[PATH_MAX], state[12]; + + if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0) + return NULL; + if (pscanf(path, "%12[a-zA-Z ]", state) != 1) + return NULL; + + if (!pick(bat, POWER_SUPPLY_CHARGE, POWER_SUPPLY_ENERGY, path, + sizeof(path)) || + pscanf(path, "%ju", &charge_now) < 0) + return NULL; + + if (!strcmp(state, "Discharging")) { + if (!pick(bat, POWER_SUPPLY_CURRENT, POWER_SUPPLY_POWER, path, + sizeof(path)) || + pscanf(path, "%ju", ¤t_now) < 0) + return NULL; + + if (current_now == 0) + return NULL; + + timeleft = (double)charge_now / (double)current_now; + h = timeleft; + m = (timeleft - (double)h) * 60; + + return bprintf("%juh %jum", h, m); + } + + return ""; + } +#elif defined(__OpenBSD__) + #include + #include + #include + #include + + static int + load_apm_power_info(struct apm_power_info *apm_info) + { + int fd; + + fd = open("/dev/apm", O_RDONLY); + if (fd < 0) { + warn("open '/dev/apm':"); + return 0; + } + + memset(apm_info, 0, sizeof(struct apm_power_info)); + if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) { + warn("ioctl 'APM_IOC_GETPOWER':"); + close(fd); + return 0; + } + return close(fd), 1; + } + + const char * + battery_perc(const char *unused) + { + struct apm_power_info apm_info; + + if (load_apm_power_info(&apm_info)) + return bprintf("%d", apm_info.battery_life); + + return NULL; + } + + const char * + battery_state(const char *unused) + { + struct { + unsigned int state; + char *symbol; + } map[] = { + { APM_AC_ON, "+" }, + { APM_AC_OFF, "-" }, + }; + struct apm_power_info apm_info; + size_t i; + + if (load_apm_power_info(&apm_info)) { + for (i = 0; i < LEN(map); i++) + if (map[i].state == apm_info.ac_state) + break; + + return (i == LEN(map)) ? "?" : map[i].symbol; + } + + return NULL; + } + + const char * + battery_remaining(const char *unused) + { + struct apm_power_info apm_info; + unsigned int h, m; + + if (load_apm_power_info(&apm_info)) { + if (apm_info.ac_state != APM_AC_ON) { + h = apm_info.minutes_left / 60; + m = apm_info.minutes_left % 60; + return bprintf("%uh %02um", h, m); + } else { + return ""; + } + } + + return NULL; + } +#elif defined(__FreeBSD__) + #include + + #define BATTERY_LIFE "hw.acpi.battery.life" + #define BATTERY_STATE "hw.acpi.battery.state" + #define BATTERY_TIME "hw.acpi.battery.time" + + const char * + battery_perc(const char *unused) + { + int cap_perc; + size_t len; + + len = sizeof(cap_perc); + if (sysctlbyname(BATTERY_LIFE, &cap_perc, &len, NULL, 0) < 0 || !len) + return NULL; + + return bprintf("%d", cap_perc); + } + + const char * + battery_state(const char *unused) + { + int state; + size_t len; + + len = sizeof(state); + if (sysctlbyname(BATTERY_STATE, &state, &len, NULL, 0) < 0 || !len) + return NULL; + + switch (state) { + case 0: /* FALLTHROUGH */ + case 2: + return "+"; + case 1: + return "-"; + default: + return "?"; + } + } + + const char * + battery_remaining(const char *unused) + { + int rem; + size_t len; + + len = sizeof(rem); + if (sysctlbyname(BATTERY_TIME, &rem, &len, NULL, 0) < 0 || !len + || rem < 0) + return NULL; + + return bprintf("%uh %02um", rem / 60, rem % 60); + } +#endif diff --git a/.suckless/slstatus/components/battery.o b/.suckless/slstatus/components/battery.o new file mode 100644 index 0000000..3deff79 Binary files /dev/null and b/.suckless/slstatus/components/battery.o differ diff --git a/.suckless/slstatus/components/cat.c b/.suckless/slstatus/components/cat.c new file mode 100644 index 0000000..07944cc --- /dev/null +++ b/.suckless/slstatus/components/cat.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +cat(const char *path) +{ + char *f; + FILE *fp; + + if (!(fp = fopen(path, "r"))) { + warn("fopen '%s':", path); + return NULL; + } + + f = fgets(buf, sizeof(buf) - 1, fp); + if (fclose(fp) < 0) { + warn("fclose '%s':", path); + return NULL; + } + if (!f) + return NULL; + + if ((f = strrchr(buf, '\n'))) + f[0] = '\0'; + + return buf[0] ? buf : NULL; +} + diff --git a/.suckless/slstatus/components/cat.o b/.suckless/slstatus/components/cat.o new file mode 100644 index 0000000..6c3820d Binary files /dev/null and b/.suckless/slstatus/components/cat.o differ diff --git a/.suckless/slstatus/components/cpu.c b/.suckless/slstatus/components/cpu.c new file mode 100644 index 0000000..d0d03c7 --- /dev/null +++ b/.suckless/slstatus/components/cpu.c @@ -0,0 +1,157 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) + #define CPU_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + + const char * + cpu_freq(const char *unused) + { + uintmax_t freq; + + /* in kHz */ + if (pscanf(CPU_FREQ, "%ju", &freq) != 1) + return NULL; + + return fmt_human(freq * 1000, 1000); + } + + const char * + cpu_perc(const char *unused) + { + static long double a[7]; + long double b[7], sum; + + memcpy(b, a, sizeof(b)); + /* cpu user nice system idle iowait irq softirq */ + if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]) + != 7) + return NULL; + + if (b[0] == 0) + return NULL; + + sum = (b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6]) - + (a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6]); + + if (sum == 0) + return NULL; + + return bprintf("%d", (int)(100 * + ((b[0] + b[1] + b[2] + b[5] + b[6]) - + (a[0] + a[1] + a[2] + a[5] + a[6])) / sum)); + } +#elif defined(__OpenBSD__) + #include + #include + #include + + const char * + cpu_freq(const char *unused) + { + int freq, mib[2]; + size_t size; + + mib[0] = CTL_HW; + mib[1] = HW_CPUSPEED; + + size = sizeof(freq); + + /* in MHz */ + if (sysctl(mib, 2, &freq, &size, NULL, 0) < 0) { + warn("sysctl 'HW_CPUSPEED':"); + return NULL; + } + + return fmt_human(freq * 1E6, 1000); + } + + const char * + cpu_perc(const char *unused) + { + int mib[2]; + static uintmax_t a[CPUSTATES]; + uintmax_t b[CPUSTATES], sum; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME; + + size = sizeof(a); + + memcpy(b, a, sizeof(b)); + if (sysctl(mib, 2, &a, &size, NULL, 0) < 0) { + warn("sysctl 'KERN_CPTIME':"); + return NULL; + } + if (b[0] == 0) + return NULL; + + sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]); + + if (sum == 0) + return NULL; + + return bprintf("%d", 100 * + ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] + + a[CP_INTR]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + + b[CP_INTR])) / sum); + } +#elif defined(__FreeBSD__) + #include + #include + #include + + const char * + cpu_freq(const char *unused) + { + int freq; + size_t size; + + size = sizeof(freq); + /* in MHz */ + if (sysctlbyname("hw.clockrate", &freq, &size, NULL, 0) < 0 || !size) { + warn("sysctlbyname 'hw.clockrate':"); + return NULL; + } + + return fmt_human(freq * 1E6, 1000); + } + + const char * + cpu_perc(const char *unused) + { + size_t size; + static long a[CPUSTATES]; + long b[CPUSTATES], sum; + + size = sizeof(a); + memcpy(b, a, sizeof(b)); + if (sysctlbyname("kern.cp_time", &a, &size, NULL, 0) < 0 || !size) { + warn("sysctlbyname 'kern.cp_time':"); + return NULL; + } + if (b[0] == 0) + return NULL; + + sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]); + + if (sum == 0) + return NULL; + + return bprintf("%d", 100 * + ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] + + a[CP_INTR]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + + b[CP_INTR])) / sum); + } +#endif