From 3679115ebc6e919c7347e44f741af37d87b48ebe Mon Sep 17 00:00:00 2001 From: TolaMironcenko Date: Tue, 5 Nov 2024 03:05:54 +0700 Subject: [PATCH] dwmstatus added --- .gitignore | 3 + dwmstatus/.gitignore | 9 ++ dwmstatus/LICENSE | 25 ++++ dwmstatus/README.md | 55 ++++++++ dwmstatus/meson.build | 10 ++ dwmstatus/src/Makefile | 38 ++++++ dwmstatus/src/config.def.h | 33 +++++ dwmstatus/src/config.mk | 15 +++ dwmstatus/src/dwmstatus.c | 242 ++++++++++++++++++++++++++++++++++ dwmstatus/src/dwmstatus.h | 64 +++++++++ dwmstatus/src/dwmstatus_std.c | 76 +++++++++++ dwmstatus/src/dwmstatus_xcb.c | 106 +++++++++++++++ dwmstatus/src/meson.build | 32 +++++ 13 files changed, 708 insertions(+) create mode 100644 dwmstatus/.gitignore create mode 100644 dwmstatus/LICENSE create mode 100644 dwmstatus/README.md create mode 100644 dwmstatus/meson.build create mode 100644 dwmstatus/src/Makefile create mode 100644 dwmstatus/src/config.def.h create mode 100644 dwmstatus/src/config.mk create mode 100644 dwmstatus/src/dwmstatus.c create mode 100644 dwmstatus/src/dwmstatus.h create mode 100644 dwmstatus/src/dwmstatus_std.c create mode 100644 dwmstatus/src/dwmstatus_xcb.c create mode 100644 dwmstatus/src/meson.build diff --git a/.gitignore b/.gitignore index 786352b..aa0f56d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ dwm/drw.o dwm/dwm.o dwm/util.o dwm/dwm-6.5.tar.gz +*.0 +dwmstatus/src/dwmstatus_std +dwmstatus/src/dwmstatus_xcb diff --git a/dwmstatus/.gitignore b/dwmstatus/.gitignore new file mode 100644 index 0000000..eec6794 --- /dev/null +++ b/dwmstatus/.gitignore @@ -0,0 +1,9 @@ +*.o +*~ +*.sh +build +debug +src/config.h +src/dwmstatus_std +src/dwmstatus_xcb + diff --git a/dwmstatus/LICENSE b/dwmstatus/LICENSE new file mode 100644 index 0000000..b95a928 --- /dev/null +++ b/dwmstatus/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2018, Jiayi Zhao +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dwmstatus/README.md b/dwmstatus/README.md new file mode 100644 index 0000000..57e7803 --- /dev/null +++ b/dwmstatus/README.md @@ -0,0 +1,55 @@ +# dwmstatus +## Description +A simple, customizable status bar for Dynamic Window Manager(dwm) + +Exports status bar to X11 root window via xcb instead of xlib + +Output: +``` +/* charging */ +<---> │ 0.94GHz │ 39°C │ [100%+] │ Vol: 50% │ 1:09 │ Thu 10/29 4:20 +/* discharging */ +<---> │ 0.94GHz │ 39°C │ [99%] │ Vol: 50% │ 1:69 │ Thu 10/29 4:20 +/* AC power */ +<---> │ 0.94GHz │ 39°C │ [0%] │ Vol: 50% │ 1:48 │ Thu 10/29 4:20 +``` + +## Requirements + - c compiler + - [xcb-util](https://xcb.freedesktop.org/) [For exporting status bar to root X11 window] + - Kernel options: + - `CONFIG_SYSFS`: sysfs file system support [Where most information will be parsed from] + - `CONFIG_THERMAL_HWMON`: Expose thermal sensors as hwmon device [For getting cpu temps] + +## Installation +Installation using **make**: +``` +$ cd dwmstatus/src +$ make +# make install +``` +Alternatively, you can install using **meson**: +``` +$ cd dwmstatus +$ meson build +$ ninja -C build +# ninja -C build install +``` + +## Running +``` +$ dwmstatus_std # for outputting to stdout +$ dwmstatus_xcb # for outputting to X11 root window +``` + +## Configuration +All configurations are done through `config.def.h`/`config.h` +to keep the program simple and fast(?). +Note: some functions may be commented from my usages. +Uncomment to use them. + +## Features + - Displays date, uptime, battery percentage + - Displays a single cpu's frequency and temperature + - Displays network connections + - only if connected to access point, not internet access diff --git a/dwmstatus/meson.build b/dwmstatus/meson.build new file mode 100644 index 0000000..8173e22 --- /dev/null +++ b/dwmstatus/meson.build @@ -0,0 +1,10 @@ +project( + 'dwmstatus', + 'c', + meson_version: '>=0.41.2', + version: '0.1', + default_options: ['warning_level=2'], +) + +add_global_arguments('-Wvla', language : 'c') +subdir('src') diff --git a/dwmstatus/src/Makefile b/dwmstatus/src/Makefile new file mode 100644 index 0000000..abce948 --- /dev/null +++ b/dwmstatus/src/Makefile @@ -0,0 +1,38 @@ +# Makefile + +include config.mk + +all: options dwmstatus_xcb dwmstatus_std + +options: + + @echo " CC = ${CC}" + @echo "CFLAGS = ${CFLAGS}" + @echo " LIBS = ${LIBS}" + +config.h: config.def.h + + @echo "cp config.def.h -> config.h" + cp config.def.h config.h + +dwmstatus.o: dwmstatus.c dwmstatus.h config.h + ${CC} ${CFLAGS} -c dwmstatus.c + +dwmstatus_xcb.o: dwmstatus.o dwmstatus_xcb.c + ${CC} ${CFLAGS} -c dwmstatus_xcb.c + +dwmstatus_xcb: dwmstatus.o dwmstatus_xcb.o + ${CC} ${CFLAGS} $@.o dwmstatus.o -o $@ ${LIBS} + +dwmstatus_std.o: dwmstatus.o dwmstatus_std.c + ${CC} ${CFLAGS} -c dwmstatus_std.c + +dwmstatus_std: dwmstatus.o dwmstatus_std.o + ${CC} ${CFLAGS} $@.o dwmstatus.o -o $@ ${LIBS} + +install: + cp -f dwmstatus_std ${PREFIX}/bin/dwmstatus_std + cp -f dwmstatus_xcb ${PREFIX}/bin/dwmstatus_xcb + +clean: + rm -f *.o dwmstatus_std dwmstatus_xcb diff --git a/dwmstatus/src/config.def.h b/dwmstatus/src/config.def.h new file mode 100644 index 0000000..e9ba665 --- /dev/null +++ b/dwmstatus/src/config.def.h @@ -0,0 +1,33 @@ + +/* Refresh rates of status bar */ +#define STATUS_REFRESH_RATE_REG 3 +#define STATUS_REFRESH_RATE_LOW 30 + +/* File indicating AC is present */ +#define AC_FILE "/sys/class/power_supply/AC/online" + +/* Directory for battery presence */ +#define BAT_DIR "/sys/class/power_supply/BAT0" + +/* File with battery value */ +#define BAT_CAPFILE BAT_DIR "/capacity" + +/* File with battery drain information in milliwatts */ +#define BAT_DRAIN_FILE BAT_DIR "/power_now" + +/* File with current frequency of first core */ +#define CPU_FREQFILE "/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq" + +/* File with current temperature of first core */ +#define CPU_TEMPFILE "/sys/devices/platform/coretemp.0/hwmon/hwmon0/temp1_input" + +/* File with current connectivity status of (wired) network interface */ +#define ETH_CARFILE "/sys/class/net/enp3s0/carrier" + +/* File with current connectivity status of (wireless) network interface */ +#define WLAN_CARFILE "/sys/class/net/wlp5s0/carrier" + +/* Which sound card volume to display */ +#define SOUNDCARD "default" + +#define SOUNDCONTROL "Master" diff --git a/dwmstatus/src/config.mk b/dwmstatus/src/config.mk new file mode 100644 index 0000000..2cfa8bc --- /dev/null +++ b/dwmstatus/src/config.mk @@ -0,0 +1,15 @@ +# compiler and linker +CC = cc + +# flags +CFLAGS = -ggdb3 -Os -Wall -Wno-unused-variable -march=native -fno-stack-protector -D_GNU_SOURCE + +# X11 export support +DEP_XCB = `pkg-config --cflags --libs xcb xcb-atom` + +# output volume support +DEP_ALSA = `pkg-config --cflags --libs alsa` + +LIBS = ${DEP_XCB} ${DEP_ALSA} + +PREFIX=/usr/local diff --git a/dwmstatus/src/dwmstatus.c b/dwmstatus/src/dwmstatus.c new file mode 100644 index 0000000..ac9145d --- /dev/null +++ b/dwmstatus/src/dwmstatus.c @@ -0,0 +1,242 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "dwmstatus.h" + +// #define alloca(x) __builtin_alloca(x) + +/** + * grabs sysinfo + */ +void initialize_sysinfo(struct sysinfo *s_info) +{ + int error = sysinfo(s_info); + if (error) + fprintf(stderr, "Error: error code: %d\n", error); +} + +/** + * get the connectivity of network interfaces and return string + * indicating the status of them: + * <---> - wireless connection to network + * [---] - wired connection to network + * --/-- - no connection to network + */ +char *network_status() +{ + FILE *carrier_fd; + /* If the file exists, get and return its state */ + if ((carrier_fd = fopen(WLAN_CARFILE, "r"))) { + if (fgetc(carrier_fd) == '1') { + fclose(carrier_fd); + return "<--->"; + } + fclose(carrier_fd); + } + /* Else, check if the wired interface carrier file exists */ + if ((carrier_fd = fopen(ETH_CARFILE, "r"))) { + if (fgetc(carrier_fd) == '1') { + fclose(carrier_fd); + return "[---]"; + } + fclose(carrier_fd); + } + return "--/--"; +} + +/** + * get and return the current amount of free ram in KBs + */ +long memfree(struct sysinfo *s_info) +{ + unsigned long free_ram = s_info->freeram; + return free_ram; +} + +/** + * get and return the total amount of ram in KBs + */ +unsigned long memtotal(struct sysinfo *s_info) +{ + unsigned long total_mem = s_info->totalram; + return total_mem; +} + +/** + * get and return the current amount of ram used in KBs + */ +unsigned long memused(struct sysinfo *s_info) +{ + unsigned long total_mem = memtotal(s_info); + unsigned long free_mem = memfree(s_info); + unsigned long used_mem = total_mem - free_mem; + return used_mem; +} + +long alsa_get_max_vol(snd_mixer_t *handle) +{ + snd_mixer_selem_id_t *sid; + + snd_mixer_selem_id_alloca(&sid); + snd_mixer_selem_id_set_index(sid, 0); + snd_mixer_selem_id_set_name(sid, "Master"); + + long min, max; + + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + snd_mixer_selem_get_playback_volume_range(elem, &min, &max); + + return max; +} + +snd_mixer_t *create_alsa_handle() +{ + snd_mixer_t *handle; + + snd_mixer_open(&handle, 0); + snd_mixer_attach(handle, SOUNDCARD); + snd_mixer_selem_register(handle, NULL, NULL); + snd_mixer_load(handle); + + return handle; +} + +unsigned int alsa_volume(snd_mixer_t *handle) +{ + long volume; + snd_mixer_selem_id_t *sid; + snd_mixer_elem_t *elem; + + snd_mixer_selem_id_alloca(&sid); + snd_mixer_selem_id_set_index(sid, 0); + snd_mixer_selem_id_set_name(sid, SOUNDCONTROL); + + elem = snd_mixer_find_selem(handle, sid); + + snd_mixer_selem_get_playback_volume(elem, + SND_MIXER_SCHN_FRONT_LEFT, &volume); + + return volume; +} + +unsigned int alsa_volume_percent(snd_mixer_t *handle, long unit) +{ + long volume = alsa_volume(handle); + return (double)volume / (double)unit; +} + +/** + * get and return the current frequency of the core + */ +float cpufreq() +{ + /* Open up core0 frequency sysfs file for parsing current + * frequency + */ + unsigned int raw_freq; + float core_freq = 0; + + FILE *freq_fd; + if ((freq_fd = fopen(CPU_FREQFILE, "r"))) { + if (fscanf(freq_fd, "%ud", &raw_freq) == 1) { + /* Format the frequency to GHz */ + core_freq = raw_freq * 0.000001; + } + fclose(freq_fd); + } + return core_freq; +} + +/** + * get and return the temperature of the core in celsius + */ +short cputemp() +{ + FILE *temp_fd; + unsigned int raw_temp; + short core_temp = 0; + + if ((temp_fd = fopen(CPU_TEMPFILE, "r"))) { + if (fscanf(temp_fd, "%ud", &raw_temp) == 1) { + core_temp = raw_temp * 0.001; + } + fclose(temp_fd); + } + return core_temp; +} + +float battery_watt_drain() +{ + FILE *fp; + + if ((fp = fopen(BAT_DRAIN_FILE, "r")) == NULL) + return -1; + + unsigned int milliwatts; + if (fscanf(fp, "%u", &milliwatts) != 1) + return -1; + + return milliwatts / 10000000; +} + +/* Power */ +char *power_status() +{ + static char power_buf[7]; + static unsigned short old_charge = 0; + static unsigned short battery_charge; + static int ac_on; + + FILE *fp; + if ((fp = fopen(BAT_CAPFILE, "r")) == NULL) { + return "AC"; + } + + if (fscanf(fp, "%hu", &battery_charge) != 1) { + fclose(fp); + return "Batt Err"; + } + fclose(fp); + if (battery_charge == old_charge) { + return power_buf; + } + + old_charge = battery_charge; + + snprintf(power_buf, sizeof(power_buf), + "%hu%%", battery_charge); + + if ((fp = fopen(AC_FILE, "r"))) { + ac_on = fgetc(fp); + if (ac_on == '1') + strcat(power_buf, "+"); + fclose(fp); + } + return power_buf; +} + +/** + * get and return an array of chars representing the time of the system: + * day_of_week month/day hour:minutes + */ +char *unixtime() +{ + static char time_buf[22]; + static const char *format = "%a %m/%d %I:%M"; + static time_t date; + + time(&date); + + struct tm *tm_info = localtime(&date); + strftime(time_buf, sizeof(time_buf), format, tm_info); + + return time_buf; +} diff --git a/dwmstatus/src/dwmstatus.h b/dwmstatus/src/dwmstatus.h new file mode 100644 index 0000000..88c26c7 --- /dev/null +++ b/dwmstatus/src/dwmstatus.h @@ -0,0 +1,64 @@ +#include + +#include +#include + +#include "config.h" + +/** + * grabs sysinfo + */ +void initialize_sysinfo(struct sysinfo *s_info); + +/** + * get the connectivity of network interfaces and return string + * indicating the status of them: + * <---> - wireless connection to network + * [---] - wired connection to network + * --/-- - no connection to network + */ +char *network_status(); + +/** + * get and return the current amount of free ram in KBs + */ +long memfree(struct sysinfo *s_info); + +/** + * get and return the total amount of ram in KBs + */ +unsigned long memtotal(struct sysinfo *s_info); + +/** + * get and return the current amount of ram used in KBs + */ +unsigned long memused(struct sysinfo *s_info); + +long alsa_get_max_vol(snd_mixer_t *handle); +snd_mixer_t *create_alsa_handle(); +unsigned int alsa_volume(snd_mixer_t *handle); +unsigned int alsa_volume_percent(snd_mixer_t *handle, long unit); + +/** + * get and return the current frequency of the core + */ +float cpufreq(); + +/** + * get and return the temperature of the core in celsius + */ +short cputemp(); + +/* Volume (Hexadecimal) */ + +/* get battery drain in watts */ +float battery_watt_drain(); + +/* Power */ +char *power_status(); + +/** + * get and return an array of chars representing the time of the system: + * day_of_week month/day hour:minutes + */ +char *unixtime(void); diff --git a/dwmstatus/src/dwmstatus_std.c b/dwmstatus/src/dwmstatus_std.c new file mode 100644 index 0000000..4f6d9aa --- /dev/null +++ b/dwmstatus/src/dwmstatus_std.c @@ -0,0 +1,76 @@ +#include +#include +#include + +#include +#include + +#include "dwmstatus.h" + +static unsigned char keep_running = 1; + +/** + * handles all memory cleanups when program is told to stop + */ +void sigint_handler() +{ + keep_running = 0; +} + +int main() +{ + /* format the uptime into minutes */ + unsigned int up_minutes, up_hours, volume; + long uptime, alsa_vol_unit; + char *system_time, *battery_status; + + struct sysinfo s_info; + + /* use a counter to update less important info less often */ + unsigned int counter = STATUS_REFRESH_RATE_LOW; + + signal(SIGINT, sigint_handler); + + snd_mixer_t *alsa_handle = create_alsa_handle(); + alsa_vol_unit = alsa_get_max_vol(alsa_handle) / 100; + volume = alsa_volume_percent(alsa_handle, alsa_vol_unit); + + while (keep_running) { + if (snd_mixer_wait(alsa_handle, STATUS_REFRESH_RATE_REG * 1000) == 0) { + snd_mixer_handle_events(alsa_handle); + volume = alsa_volume_percent(alsa_handle, alsa_vol_unit); + } + + if (counter >= STATUS_REFRESH_RATE_LOW) { + counter = 0; + + /* setup sysinfo with values */ + sysinfo(&s_info); + + /* get the uptime of machine in minutes */ + uptime = s_info.uptime / 60; + /* format the uptime into minutes */ + up_hours = uptime / 60; + up_minutes = uptime % 60; + + /* get the battery life */ + battery_status = power_status(); + + /* get the system time */ + system_time = unixtime(); + + } + + /* output and flush status to stdout */ + printf("%s \u2502 %0.02fGHz \u2502 %u\u00B0C \u2502 [%s] \u2502 Vol: %d%% \u2502 %d:%02d \u2502 %s \n", + network_status(), cpufreq(), cputemp(), battery_status, volume, up_hours, up_minutes, system_time); + fflush(stdout); + + /* refresh rate of status bar */ + counter += STATUS_REFRESH_RATE_REG; + } + + snd_mixer_close(alsa_handle); + + return 0; +} diff --git a/dwmstatus/src/dwmstatus_xcb.c b/dwmstatus/src/dwmstatus_xcb.c new file mode 100644 index 0000000..3bf3e18 --- /dev/null +++ b/dwmstatus/src/dwmstatus_xcb.c @@ -0,0 +1,106 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "dwmstatus.h" + +static unsigned char keep_running = 1; + +/** + * handles all memory cleanups when program is told to stop + */ +void sigint_handler() +{ + keep_running = 0; +} + + +int main() +{ + /* format the uptime into minutes */ + unsigned int up_minutes, up_hours, volume; + char *battery_status, *system_time; + long uptime, alsa_vol_unit; + static char status[100]; + struct sysinfo s_info; + + /* display number */ + int screen_default_nbr; + /* connect to display */ + xcb_connection_t *connection = xcb_connect(NULL, &screen_default_nbr); + + /* get the screen and the root window */ + xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; + xcb_window_t root_window = 0; + + signal(SIGINT, sigint_handler); + + if (screen) + root_window = screen->root; + + snd_mixer_t *alsa_handle = create_alsa_handle(); + alsa_vol_unit = alsa_get_max_vol(alsa_handle) / 100; + volume = alsa_volume_percent(alsa_handle, alsa_vol_unit); + + /* use a counter to update less important info less often */ + unsigned int counter = STATUS_REFRESH_RATE_LOW; + while (keep_running) { + if (snd_mixer_wait(alsa_handle, STATUS_REFRESH_RATE_REG * 1000) == 0) { + snd_mixer_handle_events(alsa_handle); + volume = alsa_get_max_vol(alsa_handle) / 100; + } + + if (counter >= STATUS_REFRESH_RATE_LOW) { + counter = 0; + + /* setup sysinfo with values */ + sysinfo(&s_info); + + /* get the uptime of machine in minutes */ + uptime = s_info.uptime / 60; + /* format the uptime into minutes */ + up_hours = uptime / 60; + up_minutes = uptime % 60; + + /* get the battery life */ + battery_status = power_status(); + + /* get the system time */ + system_time = unixtime(); + } + + snprintf(status, sizeof(status), + "%s \u2502 %0.02fGHz \u2502 %u\u00B0C \u2502 [%s] \u2502 vol: %d \u2502 %d:%02d \u2502 %s ", + network_status(), cpufreq(), cputemp(), battery_status, volume, up_hours, up_minutes, system_time); + + /* changed root window name */ + xcb_change_property(connection, + XCB_PROP_MODE_REPLACE, + root_window, + XCB_ATOM_WM_NAME, + XCB_ATOM_STRING, + 8, + sizeof(status), + status); + + /* update display */ + xcb_flush(connection); + + /* refresh rate */ + counter += STATUS_REFRESH_RATE_REG; + } + + snd_mixer_close(alsa_handle); + /* disconnect from X server */ + xcb_disconnect(connection); + + return 0; +} + +// printf("%s \u2502 %uMB \u2502 %u°C \u2502 [%u%%] \u2502 %s \n", +// get_net_carrier(), get_meminfo(), get_temp(), battery_life, unixtime()); diff --git a/dwmstatus/src/meson.build b/dwmstatus/src/meson.build new file mode 100644 index 0000000..7f31b61 --- /dev/null +++ b/dwmstatus/src/meson.build @@ -0,0 +1,32 @@ +# update config.h +run_command('cp', + ['-u', 'config.def.h', 'config.h'] + ) + +config_h = custom_target('config.h', + input : ['config.def.h'], + output : ['config.h'], + command : ['cp', '@INPUT0@', + '@OUTPUT0@']) + +dep_alsa = dependency('alsa') +dep_xcb = dependency('xcb') +dep_xcb_util = dependency('xcb-util') + +dwmstatus = declare_dependency( + sources: 'dwmstatus.c', + dependencies: dep_alsa + ) + +executable('dwmstatus_std', + 'dwmstatus_std.c', + dependencies: dwmstatus, + install: true + ) + +executable('dwmstatus_xcb', + 'dwmstatus_xcb.c', + dependencies : [dwmstatus, dep_xcb, dep_xcb_util], + install: true + ) +