Compare commits

...

10 Commits

Author SHA1 Message Date
f457346d54 modifications 2023-01-29 13:30:16 +01:00
Aaron Marcher
84a2f117a3 Update README 2020-11-30 21:32:14 +01:00
Aaron Marcher
ae8a658d0c Update LICENSE 2020-11-30 21:26:40 +01:00
Aaron Marcher
dd5bfc3e51 Add comment for FreeBSD to config.mk
Apparently `-lkvm` is needed for swap on FreeBSD

Thanks to Micheal Buch and Jason Smith
(See thread https://lists.suckless.org/dev/1907/33594.html)
2020-11-30 21:24:34 +01:00
Ingo Feinerer
9ac721c23f Use the sioctl_open(3) OpenBSD API to access vol
Starting with OpenBSD 6.7 regular users cannot access raw audio devices
anymore, for improved security.

Instead use the sioctl_open(3) API to access and manipulate audio
controls exposed by sndiod(8). On the first call a permanent connection
is established with the running sndiod daemon, and call-back functions
are registered which are triggered when audio controls are changed
(e.g., a USB headset is attached) or when the volume is modified. On
subsequent calls we poll for changes; if there are no volume changes
this costs virtually nothing.

Joint work with Alexandre Ratchov
2020-11-30 21:24:33 +01:00
Daniel Moch
aaf279f6dd Add a -1 option flag
Allow slstatus to be used by programs that can grab status by calling
an external program on a periodic basis (e.g. tmux)
2020-11-30 21:23:56 +01:00
Mart Lubbers
d1b23e5509 Handle SIGUSR1 for forced refreshes
At some point one might want to force a refresh for example after
checking email or changing the volume. Sending a SIGUSR1 achieves this
now
2020-11-30 21:23:49 +01:00
dsp
3fc2872d1b Fix temperature reporting on OpenBSD
On OpenBSD although the formula is correct due to integer division a
temperature of for example 54 celsius appears as 5. this patch first
treats it as a floating point op before retaining the non decimal digits
2020-11-30 21:23:48 +01:00
Cem Keylan
3ac985eb03 Full battery indicator
When you reach full charge the symbol would change
to a question mark "?" as "Full" was not defined,
now it changes to an "o" instead.
2020-11-30 21:23:26 +01:00
Ryan Kes
2b0f50d1aa Add separator module 2020-11-30 21:15:13 +01:00
15 changed files with 295 additions and 66 deletions

10
LICENSE
View File

@ -1,6 +1,6 @@
ISC License ISC License
Copyright 2016-2019 Aaron Marcher <me@drkhsh.at> Copyright 2016-2020 Aaron Marcher <me@drkhsh.at>
Copyright 2016 Roy Freytag <rfreytag@hs-mittweida.de> Copyright 2016 Roy Freytag <rfreytag@hs-mittweida.de>
Copyright 2016 Vincent Loupmon <vincentloupmon@gmail.com> Copyright 2016 Vincent Loupmon <vincentloupmon@gmail.com>
@ -19,7 +19,13 @@ Copyright 2018 David Demelier <markand@malikania.fr>
Copyright 2018-2019 Michael Buch <michaelbuch12@gmail.com> Copyright 2018-2019 Michael Buch <michaelbuch12@gmail.com>
Copyright 2018 Ian Remmler <ian@remmler.org> Copyright 2018 Ian Remmler <ian@remmler.org>
Copyright 2016-2019 Joerg Jung <jung@openbsd.org> Copyright 2016-2019 Joerg Jung <jung@openbsd.org>
Copyright 2019 Ingo Feinerer <feinerer@logic.at> Copyright 2019 Ryan Kes <alrayyes@gmail.com>
Copyright 2019 Cem Keylan <cem@ckyln.com>
Copyright 2019 dsp <dsp@2f30.org>
Copyright 2019-2020 Ingo Feinerer <feinerer@logic.at>
Copyright 2020 Alexandre Ratchov <alex@caoua.org>
Copyright 2020 Mart Lubbers <mart@martlubbers.net>
Copyright 2020 Daniel Moch <daniel@danielmoch.com>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View File

@ -21,6 +21,7 @@ COM =\
components/num_files\ components/num_files\
components/ram\ components/ram\
components/run_command\ components/run_command\
components/separator\
components/swap\ components/swap\
components/temperature\ components/temperature\
components/uptime\ components/uptime\

10
README
View File

@ -26,7 +26,7 @@ Features
- Swap status (free swap, percentage, total swap and used swap) - Swap status (free swap, percentage, total swap and used swap)
- Temperature - Temperature
- Uptime - Uptime
- Volume percentage (OSS/ALSA) - Volume percentage
- WiFi signal percentage and ESSID - WiFi signal percentage and ESSID
@ -58,6 +58,8 @@ slstatus can be customized by creating a custom config.h and (re)compiling the
source code. This keeps it fast, secure and simple. source code. This keeps it fast, secure and simple.
Todo Upcoming
---- --------
Cleaning up the whole codebase it the goal before thinking about a release.
A release (v1.0) will come soon... ;)
After a long phase of inactivity, development has been continued!

View File

@ -52,6 +52,7 @@
} map[] = { } map[] = {
{ "Charging", "+" }, { "Charging", "+" },
{ "Discharging", "-" }, { "Discharging", "-" },
{ "Full", "o" },
}; };
size_t i; size_t i;
char path[PATH_MAX], state[12]; char path[PATH_MAX], state[12];

10
components/separator.c Normal file
View File

@ -0,0 +1,10 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include "../util.h"
const char *
separator(const char *separator)
{
return separator;
}

View File

@ -45,7 +45,7 @@
} }
/* kelvin to celsius */ /* kelvin to celsius */
return bprintf("%d", (temp.value - 273150000) / 1E6); return bprintf("%d", (int)((float)(temp.value-273150000) / 1E6));
} }
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
#include <stdio.h> #include <stdio.h>

View File

@ -8,69 +8,177 @@
#include "../util.h" #include "../util.h"
#if defined(__OpenBSD__) #if defined(__OpenBSD__)
#include <sys/audioio.h> #include <sys/queue.h>
#include <poll.h>
#include <sndio.h>
#include <stdlib.h>
struct control {
LIST_ENTRY(control) next;
unsigned int addr;
#define CTRL_NONE 0
#define CTRL_LEVEL 1
#define CTRL_MUTE 2
unsigned int type;
unsigned int maxval;
unsigned int val;
};
static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls);
static struct pollfd *pfds;
static struct sioctl_hdl *hdl;
static int initialized;
/*
* Call-back to obtain the description of all audio controls.
*/
static void
ondesc(void *unused, struct sioctl_desc *desc, int val)
{
struct control *c, *ctmp;
unsigned int type = CTRL_NONE;
if (desc == NULL)
return;
/* Delete existing audio control with the same address. */
LIST_FOREACH_SAFE(c, &controls, next, ctmp) {
if (desc->addr == c->addr) {
LIST_REMOVE(c, next);
free(c);
break;
}
}
/* Only match output.level and output.mute audio controls. */
if (desc->group[0] != 0 ||
strcmp(desc->node0.name, "output") != 0)
return;
if (desc->type == SIOCTL_NUM &&
strcmp(desc->func, "level") == 0)
type = CTRL_LEVEL;
else if (desc->type == SIOCTL_SW &&
strcmp(desc->func, "mute") == 0)
type = CTRL_MUTE;
else
return;
c = malloc(sizeof(struct control));
if (c == NULL) {
warn("sndio: failed to allocate audio control\n");
return;
}
c->addr = desc->addr;
c->type = type;
c->maxval = desc->maxval;
c->val = val;
LIST_INSERT_HEAD(&controls, c, next);
}
/*
* Call-back invoked whenever an audio control changes.
*/
static void
onval(void *unused, unsigned int addr, unsigned int val)
{
struct control *c;
LIST_FOREACH(c, &controls, next) {
if (c->addr == addr)
break;
}
c->val = val;
}
static void
cleanup(void)
{
struct control *c;
if (hdl) {
sioctl_close(hdl);
hdl = NULL;
}
free(pfds);
pfds = NULL;
while (!LIST_EMPTY(&controls)) {
c = LIST_FIRST(&controls);
LIST_REMOVE(c, next);
free(c);
}
}
static int
init(void)
{
hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0);
if (hdl == NULL) {
warn("sndio: cannot open device");
goto failed;
}
if (!sioctl_ondesc(hdl, ondesc, NULL)) {
warn("sndio: cannot set control description call-back");
goto failed;
}
if (!sioctl_onval(hdl, onval, NULL)) {
warn("sndio: cannot set control values call-back");
goto failed;
}
pfds = calloc(sioctl_nfds(hdl), sizeof(struct pollfd));
if (pfds == NULL) {
warn("sndio: cannot allocate pollfd structures");
goto failed;
}
return 1;
failed:
cleanup();
return 0;
}
const char * const char *
vol_perc(const char *card) vol_perc(const char *unused)
{ {
static int cls = -1; struct control *c;
mixer_devinfo_t mdi; int n, v, value;
mixer_ctrl_t mc;
int afd = -1, m = -1, v = -1;
if ((afd = open(card, O_RDONLY)) < 0) { if (!initialized)
warn("open '%s':", card); initialized = init();
return NULL;
}
for (mdi.index = 0; cls == -1; mdi.index++) { if (hdl == NULL)
if (ioctl(afd, AUDIO_MIXER_DEVINFO, &mdi) < 0) { return NULL;
warn("ioctl 'AUDIO_MIXER_DEVINFO':");
close(afd); n = sioctl_pollfd(hdl, pfds, POLLIN);
if (n > 0) {
n = poll(pfds, n, 0);
if (n > 0) {
if (sioctl_revents(hdl, pfds) & POLLHUP) {
warn("sndio: disconnected");
cleanup();
return NULL; return NULL;
} }
if (mdi.type == AUDIO_MIXER_CLASS &&
!strncmp(mdi.label.name,
AudioCoutputs,
MAX_AUDIO_DEV_LEN))
cls = mdi.index;
}
for (mdi.index = 0; v == -1 || m == -1; mdi.index++) {
if (ioctl(afd, AUDIO_MIXER_DEVINFO, &mdi) < 0) {
warn("ioctl 'AUDIO_MIXER_DEVINFO':");
close(afd);
return NULL;
}
if (mdi.mixer_class == cls &&
((mdi.type == AUDIO_MIXER_VALUE &&
!strncmp(mdi.label.name,
AudioNmaster,
MAX_AUDIO_DEV_LEN)) ||
(mdi.type == AUDIO_MIXER_ENUM &&
!strncmp(mdi.label.name,
AudioNmute,
MAX_AUDIO_DEV_LEN)))) {
mc.dev = mdi.index, mc.type = mdi.type;
if (ioctl(afd, AUDIO_MIXER_READ, &mc) < 0) {
warn("ioctl 'AUDIO_MIXER_READ':");
close(afd);
return NULL;
}
if (mc.type == AUDIO_MIXER_VALUE)
v = mc.un.value.num_channels == 1 ?
mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] :
(mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] >
mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] ?
mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] :
mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
else if (mc.type == AUDIO_MIXER_ENUM)
m = mc.un.ord;
} }
} }
close(afd); value = 100;
LIST_FOREACH(c, &controls, next) {
if (c->type == CTRL_MUTE && c->val == 1)
value = 0;
else if (c->type == CTRL_LEVEL) {
v = (c->val * 100 + c->maxval / 2) / c->maxval;
/* For multiple channels return the minimum. */
if (v < value)
value = v;
}
}
return bprintf("%d", m ? 0 : v * 100 / 255); return bprintf("%d", value);
} }
#else #else
#include <sys/soundcard.h> #include <sys/soundcard.h>

View File

@ -45,6 +45,7 @@ static const char unknown_str[] = "n/a";
* ram_total total memory size in GB NULL * ram_total total memory size in GB NULL
* ram_used used memory in GB NULL * ram_used used memory in GB NULL
* run_command custom shell command command (echo foo) * run_command custom shell command command (echo foo)
* separator string to echo NULL
* swap_free free swap in GB NULL * swap_free free swap in GB NULL
* swap_perc swap usage in percent NULL * swap_perc swap usage in percent NULL
* swap_total total swap size in GB NULL * swap_total total swap size in GB NULL
@ -58,6 +59,7 @@ static const char unknown_str[] = "n/a";
* uptime system uptime NULL * uptime system uptime NULL
* username username of current user NULL * username username of current user NULL
* vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer) * vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer)
* NULL on OpenBSD
* wifi_perc WiFi signal in percent interface name (wlan0) * wifi_perc WiFi signal in percent interface name (wlan0)
* wifi_essid WiFi ESSID interface name (wlan0) * wifi_essid WiFi ESSID interface name (wlan0)
*/ */

84
config.h Normal file
View File

@ -0,0 +1,84 @@
/* See LICENSE file for copyright and license details. */
/* interval between updates (in ms) */
const unsigned int interval = 1000;
/* text to show if no value can be retrieved */
static const char unknown_str[] = "n/a";
/* maximum output string length */
#define MAXLEN 2048
/*
* function description argument (example)
*
* battery_perc battery percentage battery name (BAT0)
* NULL on OpenBSD/FreeBSD
* battery_state battery charging state battery name (BAT0)
* NULL on OpenBSD/FreeBSD
* battery_remaining battery remaining HH:MM battery name (BAT0)
* NULL on OpenBSD/FreeBSD
* cpu_perc cpu usage in percent NULL
* cpu_freq cpu frequency in MHz NULL
* datetime date and time format string (%F %T)
* disk_free free disk space in GB mountpoint path (/)
* disk_perc disk usage in percent mountpoint path (/)
* disk_total total disk space in GB mountpoint path (/")
* disk_used used disk space in GB mountpoint path (/)
* entropy available entropy NULL
* gid GID of current user NULL
* hostname hostname NULL
* ipv4 IPv4 address interface name (eth0)
* ipv6 IPv6 address interface name (eth0)
* kernel_release `uname -r` NULL
* keyboard_indicators caps/num lock indicators format string (c?n?)
* see keyboard_indicators.c
* keymap layout (variant) of current NULL
* keymap
* load_avg load average NULL
* netspeed_rx receive network speed interface name (wlan0)
* netspeed_tx transfer network speed interface name (wlan0)
* num_files number of files in a directory path
* (/home/foo/Inbox/cur)
* ram_free free memory in GB NULL
* ram_perc memory usage in percent NULL
* ram_total total memory size in GB NULL
* ram_used used memory in GB NULL
* run_command custom shell command command (echo foo)
* separator string to echo NULL
* swap_free free swap in GB NULL
* swap_perc swap usage in percent NULL
* swap_total total swap size in GB NULL
* swap_used used swap in GB NULL
* temp temperature in degree celsius sensor file
* (/sys/class/thermal/...)
* NULL on OpenBSD
* thermal zone on FreeBSD
* (tz0, tz1, etc.)
* uid UID of current user NULL
* uptime system uptime NULL
* username username of current user NULL
* vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer)
* NULL on OpenBSD
* wifi_perc WiFi signal in percent interface name (wlan0)
* wifi_essid WiFi ESSID interface name (wlan0)
*/
static const struct arg args[] = {
/* function format argument */
// { cpu_perc, "pc: %s%%", NULL },
// { ram_used, " %s", NULL },
// { ram_perc, "/%s%%", NULL },
{ battery_state, "%s", "BAT0" },
{ battery_perc, "%s%% ", "BAT0" },
{ battery_remaining, "%s", "BAT0" },
{ disk_free, " %s ", "/"},
// { vol_perc, " [ %s ] ", NULL },
{ ipv4, "%s ", "wlp2s0" },
{ wifi_essid, "%s ", "wlp2s0" },
{ wifi_perc, "(%s) ", "wlp2s0" },
// { netspeed_rx, "[%s:", "wlp2s0" },
// { netspeed_tx, "%s]", "wlp2s0" },
{ run_command, "b:%s%% ", "light | cut -d'.' -f1" },
{ run_command, "v:%s%% ", "pamixer --get-volume" },
{ datetime, " %s ", "%a %F %T" },
};

View File

@ -14,6 +14,8 @@ X11LIB = /usr/X11R6/lib
CPPFLAGS = -I$(X11INC) -D_DEFAULT_SOURCE CPPFLAGS = -I$(X11INC) -D_DEFAULT_SOURCE
CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os
LDFLAGS = -L$(X11LIB) -s LDFLAGS = -L$(X11LIB) -s
# OpenBSD: add -lsndio
# FreeBSD: add -lkvm
LDLIBS = -lX11 LDLIBS = -lX11
# compiler and linker # compiler and linker

3
read Normal file
View File

@ -0,0 +1,3 @@
100.00
100.00
100.00

BIN
slstatus Executable file

Binary file not shown.

View File

@ -1,4 +1,4 @@
.Dd 2017-08-10 .Dd 2020-06-23
.Dt SLSTATUS 1 .Dt SLSTATUS 1
.Os .Os
.Sh NAME .Sh NAME
@ -7,6 +7,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl s .Op Fl s
.Op Fl 1
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a suckless status monitor for window managers that use WM_NAME (e.g. dwm) or is a suckless status monitor for window managers that use WM_NAME (e.g. dwm) or
@ -18,6 +19,8 @@ outputs to WM_NAME.
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl s .It Fl s
Write to stdout instead of WM_NAME. Write to stdout instead of WM_NAME.
.It Fl 1
Write once to stdout and quit.
.El .El
.Sh CUSTOMIZATION .Sh CUSTOMIZATION
.Nm .Nm

View File

@ -18,7 +18,7 @@ struct arg {
}; };
char buf[1024]; char buf[1024];
static int done; static volatile sig_atomic_t done;
static Display *dpy; static Display *dpy;
#include "config.h" #include "config.h"
@ -26,8 +26,7 @@ static Display *dpy;
static void static void
terminate(const int signo) terminate(const int signo)
{ {
(void)signo; if (signo != SIGUSR1)
done = 1; done = 1;
} }
@ -42,7 +41,7 @@ difftimespec(struct timespec *res, struct timespec *a, struct timespec *b)
static void static void
usage(void) usage(void)
{ {
die("usage: %s [-s]", argv0); die("usage: %s [-s] [-1]", argv0);
} }
int int
@ -57,6 +56,9 @@ main(int argc, char *argv[])
sflag = 0; sflag = 0;
ARGBEGIN { ARGBEGIN {
case '1':
done = 1;
/* fallthrough */
case 's': case 's':
sflag = 1; sflag = 1;
break; break;
@ -72,12 +74,14 @@ main(int argc, char *argv[])
act.sa_handler = terminate; act.sa_handler = terminate;
sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL); sigaction(SIGTERM, &act, NULL);
act.sa_flags |= SA_RESTART;
sigaction(SIGUSR1, &act, NULL);
if (!sflag && !(dpy = XOpenDisplay(NULL))) { if (!sflag && !(dpy = XOpenDisplay(NULL))) {
die("XOpenDisplay: Failed to open display"); die("XOpenDisplay: Failed to open display");
} }
while (!done) { do {
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) { if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) {
die("clock_gettime:"); die("clock_gettime:");
} }
@ -124,7 +128,7 @@ main(int argc, char *argv[])
} }
} }
} }
} } while (!done);
if (!sflag) { if (!sflag) {
XStoreName(dpy, DefaultRootWindow(dpy), NULL); XStoreName(dpy, DefaultRootWindow(dpy), NULL);

View File

@ -56,6 +56,9 @@ const char *ram_used(void);
/* run_command */ /* run_command */
const char *run_command(const char *cmd); const char *run_command(const char *cmd);
/* separator */
const char *separator(const char *separator);
/* swap */ /* swap */
const char *swap_free(void); const char *swap_free(void);
const char *swap_perc(void); const char *swap_perc(void);