initial import

This commit is contained in:
2025-06-22 20:39:04 -05:00
commit f8a70886f0
3428 changed files with 302546 additions and 0 deletions

46
i3status/PKGBUILD Normal file
View File

@@ -0,0 +1,46 @@
# Maintainer: Jesus E. <heckyel@riseup.net>
pkgname=i3status
pkgver=2.13
pkgrel=2
pkgdesc="Generates status bar to use for example with i3bar or dzen2"
arch=('i686' 'x86_64')
url='https://i3wm.org/i3status/'
license=('Modified-BSD')
groups=('i3')
depends=('sndio' 'confuse' 'libnl' 'yajl')
makedepends=('asciidoc' 'xmlto')
backup=('etc/i3status.conf')
options=('docs')
source=("https://i3wm.org/i3status/$pkgname-$pkgver.tar.bz2"
"build-without-pulse.patch"
"add-sndio-backend.patch")
sha512sums=('6dadff19e53499d169ba4f491e1f821014b4f92fc3c93d7947c85cbbbdeaba538d02bd8ab98fe266a8f80756a287fd5803ec77a8cd874d50082b5cad309875c2'
'3efd2ca3ef71a37689d5e6bbf0acb37571fa5dcf20608bad78f03a23386c4ece09519f7defe8d5ffe6d566b7864f82492316de558e5fdf5c9c2e0c3267ca263f'
'd44093627fabc712b6464c1d045b5592995ab8b64b8227e9ee14bef384dc2226557239cbd7c3c67d39ff3fdfa065f507e75832ec2bc470e8a4aedd5d50b2830c')
prepare() {
cd $pkgname-$pkgver
patch -Np1 -i $srcdir/build-without-pulse.patch
patch -Np1 -i $srcdir/add-sndio-backend.patch
autoreconf -vi
}
build() {
cd $pkgname-$pkgver
mkdir build && cd build
../configure \
--prefix=/usr \
--sysconfdir=/etc \
--disable-sanitizers \
--disable-pulseaudio
make CPPFLAGS+="-U_FORTIFY_SOURCE"
}
package() {
cd $pkgname-$pkgver/build
make DESTDIR="$pkgdir" install
install -Dm644 -t "$pkgdir"/usr/share/licenses/$pkgname ../LICENSE
}

View File

@@ -0,0 +1,229 @@
--- /dev/null
+++ src/sndio.c
@@ -0,0 +1,201 @@
+#include <poll.h>
+#include <sndio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "i3status.h"
+
+struct control {
+ struct control *next;
+ char name[32];
+ unsigned int addr;
+ unsigned int max;
+ unsigned int value;
+ unsigned int muted;
+ unsigned int muteaddr;
+};
+
+static int initialized;
+static struct sioctl_hdl *hdl;
+static struct control *controls;
+static struct pollfd *pfds;
+
+/*
+ * new control registered or control changed
+ */
+static void ondesc(void *unused, struct sioctl_desc *d, int val)
+{
+ struct control *i, **pi;
+
+ if (d == NULL)
+ return;
+
+ /*
+ * delete existing control with the same address
+ */
+ for (pi = &controls; (i = *pi) != NULL; pi = &i->next) {
+ if (d->addr == i->addr) {
+ *pi = i->next;
+ free(i);
+ break;
+ }
+ }
+
+ /*
+ * if we find an output.mute, associate it with its output.level
+ */
+ if (d->type == SIOCTL_SW &&
+ d->group[0] == 0 &&
+ strcmp(d->node0.name, "output") == 0 &&
+ strcmp(d->func, "mute") == 0) {
+ char name[32];
+ snprintf(name, sizeof(name), "%s%d", d->node0.name, d->node0.unit);
+ for (pi = &controls; (i = *pi) != NULL; pi = &i->next) {
+ if (strcmp(name, i->name) == 0) {
+ i->muted = val;
+ i->muteaddr = d->addr;
+ break;
+ }
+ }
+ return;
+ }
+
+ /*
+ * we're interested in top-level output.level controls only
+ */
+ if (d->type != SIOCTL_NUM ||
+ d->group[0] != 0 ||
+ strcmp(d->node0.name, "output") != 0 ||
+ strcmp(d->func, "level") != 0)
+ return;
+
+ i = malloc(sizeof(struct control));
+ if (i == NULL) {
+ fprintf(stderr, "sndio: failed to allocate control\n");
+ return;
+ }
+
+ snprintf(i->name, sizeof(i->name), "%s%d", d->node0.name, d->node0.unit);
+ i->addr = d->addr;
+ i->max = d->maxval;
+ i->value = val;
+ i->next = controls;
+ i->muted = 0;
+ i->muteaddr = -1;
+ controls = i;
+}
+
+/*
+ * control value changed
+ */
+static void onval(void *unused, unsigned int addr, unsigned int value)
+{
+ struct control *c;
+
+ for (c = controls; ; c = c->next) {
+ if (c == NULL)
+ return;
+ if (c->addr == addr) {
+ c->value = value;
+ return;
+ }
+ if (c->muteaddr == addr) {
+ c->muted = value;
+ return;
+ }
+ }
+}
+
+static void cleanup(void)
+{
+ struct control *c;
+
+ if (hdl) {
+ sioctl_close(hdl);
+ hdl = NULL;
+ }
+ if (pfds) {
+ free(pfds);
+ pfds = NULL;
+ }
+ while ((c = controls) != NULL) {
+ controls = c->next;
+ free(c);
+ }
+}
+
+static int init(void)
+{
+ /* open device */
+ hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0);
+ if (hdl == NULL) {
+ fprintf(stderr, "sndio: cannot open device\n");
+ goto failed;
+ }
+
+ /* register call-back for control description changes */
+ if (!sioctl_ondesc(hdl, ondesc, NULL)) {
+ fprintf(stderr, "sndio: cannot get description\n");
+ goto failed;
+ }
+
+ /* register call-back for volume changes */
+ if (!sioctl_onval(hdl, onval, NULL)) {
+ fprintf(stderr, "sndio: cannot get values\n");
+ goto failed;
+ }
+
+ /* allocate structures for poll() syscall */
+ pfds = calloc(sioctl_nfds(hdl), sizeof(struct pollfd));
+ if (pfds == NULL) {
+ fprintf(stderr, "sndio: cannot allocate pollfd structures\n");
+ goto failed;
+ }
+ return 1;
+failed:
+ cleanup();
+ return 0;
+}
+
+int volume_sndio(int *vol, int *muted)
+{
+ struct control *c;
+ int n, v;
+
+ if (!initialized) {
+ initialized = 1;
+ init();
+ }
+ if (hdl == NULL)
+ return -1;
+
+ /* check if controls changed */
+ n = sioctl_pollfd(hdl, pfds, POLLIN);
+ if (n > 0) {
+ n = poll(pfds, n, 0);
+ if (n > 0) {
+ if (sioctl_revents(hdl, pfds) & POLLHUP) {
+ fprintf(stderr, "sndio: disconnected\n");
+ cleanup();
+ return -1;
+ }
+ }
+ }
+
+ /*
+ * get control value: as there may be multiple
+ * channels, return the minimum
+ */
+ *vol = 100;
+ *muted = 0;
+ for (c = controls; c != NULL; c = c->next) {
+ v = (c->value * 100 + c->max / 2) / c->max;
+ if (v < *vol) {
+ *vol = v;
+ *muted = c->muted;
+
+ }
+ }
+
+ return 0;
+}
--- a/configure.ac
+++ b/configure.ac
@@ -91,6 +91,13 @@ case $host_os in
;;
esac
+# if sndio is available, define USE_SNDIO
+AC_CHECK_HEADER(sndio.h,
+ [AC_CHECK_LIB([sndio], [sio_open], [
+ AC_SUBST(SNDIO_LIBS, "-lsndio")
+ AC_DEFINE([USE_SNDIO], [], [Use sndio])
+ ], [])], [])
+
dnl TODO: check for libbsd for GNU/kFreeBSD
# Checks for programs.
--- a/include/i3status.h
+++ b/include/i3status.h
@@ -425,6 +425,7 @@ void print_volume(volume_ctx_t *ctx);
bool process_runs(const char *path);
int volume_pulseaudio(uint32_t sink_idx, const char *sink_name);
+int volume_sndio(int *vol, int *muted);
bool description_pulseaudio(uint32_t sink_idx, const char *sink_name, char buffer[MAX_SINK_DESCRIPTION_LEN]);
bool pulse_initialize(void);

View File

@@ -0,0 +1,408 @@
--- a/configure.ac 2019-06-30 19:53:24.000000000 +0200
+++ b/configure.ac 2021-07-19 13:39:39.769190529 +0200
@@ -80,11 +80,24 @@
PKG_CHECK_MODULES([CONFUSE], [libconfuse])
PKG_CHECK_MODULES([YAJL], [yajl])
+AC_ARG_ENABLE(pulseaudio,
+ AS_HELP_STRING(
+ [--disable-pulseaudio],
+ [build without pulseaudio support]),
+ [ax_pulse=$enableval],
+ [ax_pulse=yes])
+AM_CONDITIONAL([PULSE], [test x$ax_pulse = xyes])
+AS_IF([test x"$ax_pulse" = x"yes"],
+ [PKG_CHECK_MODULES([PULSE], [libpulse])])
+pulse_def=0
+AS_IF([test x"$ax_pulse" = x"yes"],
+ [pulse_def=1])
+AC_DEFINE_UNQUOTED([HAS_PULSEAUDIO], [$pulse_def], [Build with pulseaudio])
+
case $host_os in
linux*)
PKG_CHECK_MODULES([NLGENL], [libnl-genl-3.0])
PKG_CHECK_MODULES([ALSA], [alsa])
- PKG_CHECK_MODULES([PULSE], [libpulse])
;;
netbsd*)
AC_SEARCH_LIBS([prop_string_create], [prop])
@@ -101,12 +114,20 @@
AC_PROG_RANLIB
AC_PROG_LN_S
-AC_PATH_PROG([PATH_ASCIIDOC], [asciidoc], [no])
-AS_IF([test x"$PATH_ASCIIDOC" = x"no"],
- [AC_MSG_ERROR([asciidoc is required for generating man pages])])
-AC_PATH_PROG([PATH_XMLTO], [xmlto], [no])
-AS_IF([test x"$PATH_XMLTO" = x"no"],
- [AC_MSG_ERROR([xmlto is required for generating man pages])])
+AC_ARG_ENABLE(mans,
+ AS_HELP_STRING(
+ [--disable-mans],
+ [disable building manual pages]),
+ [ax_mans=$enableval],
+ [ax_mans=yes])
+AS_IF([test x$ax_mans = xyes], [
+ AC_PATH_PROG([PATH_ASCIIDOC], [asciidoc])
+])
+AS_IF([test x$ax_mans = xyes], [
+ AC_PATH_PROG([PATH_XMLTO], [xmlto])
+ AC_PATH_PROG([PATH_POD2MAN], [pod2man])
+])
+AM_CONDITIONAL([BUILD_MANS], [test x$ax_mans = xyes && test x$PATH_ASCIIDOC != x && test x$PATH_XMLTO != x && test x$PATH_POD2MAN != x])
AM_PROG_AR
@@ -131,15 +152,12 @@
AC_OUTPUT
-in_git_worktree=`git rev-parse --is-inside-work-tree 2>/dev/null`
-if [ "$in_git_worktree" = "true" ]; then
- git_dir=`git rev-parse --git-dir 2>/dev/null`
- srcdir=`dirname "$git_dir"`
- exclude_dir=`pwd | sed "s,^$srcdir,,g"`
- if ! grep -q "^$exclude_dir" "$git_dir/info/exclude"; then
- echo "$exclude_dir" >> "$git_dir/info/exclude"
- fi
-fi
+AS_IF([test -d ${srcdir}/.git], [
+ srcdir_abs=`readlink -f "$srcdir"`
+ exclude_dir=`pwd | sed "s,^$srcdir_abs/*,,g"`
+ AS_IF([! grep -q "^$exclude_dir" "${srcdir}/.git/info/exclude"],
+ [echo "$exclude_dir" >> "${srcdir}/.git/info/exclude"])])
+
echo \
"--------------------------------------------------------------------------------
@@ -151,6 +169,7 @@
AS_HELP_STRING([enable debug flags:], [${ax_enable_debug}])
AS_HELP_STRING([code coverage:], [${CODE_COVERAGE_ENABLED}])
AS_HELP_STRING([enabled sanitizers:], [${ax_enabled_sanitizers}])
+AS_HELP_STRING([pulseaudio support:], [${ax_pulse}])
To compile, run:
--- a/Makefile.am 2019-02-21 15:35:12.000000000 +0100
+++ b/Makefile.am 2021-07-19 13:47:05.320995008 +0200
@@ -5,6 +5,7 @@
bin_PROGRAMS = i3status
+if BUILD_MANS
dist_man1_MANS = \
$(asciidoc_MANS)
@@ -17,6 +18,9 @@
man/%.xml: man/%.man man/asciidoc.conf man/$(dirstamp)
$(AM_V_GEN) @PATH_ASCIIDOC@ -d manpage -b docbook -f $(top_builddir)/man/asciidoc.conf -o $@ $<
+else
+asciidoc_MANS =
+endif
AM_CPPFLAGS = \
-DSYSCONFDIR="\"$(sysconfdir)\"" \
@@ -50,6 +54,7 @@
i3status.c \
src/auto_detect_format.c \
src/first_network_device.c \
+ src/format_placeholders.c \
src/general.c \
src/output.c \
src/print_battery_info.c \
@@ -68,8 +73,11 @@
src/print_volume.c \
src/print_wireless_info.c \
src/print_file_contents.c \
- src/process_runs.c \
- src/pulse.c
+ src/process_runs.c
+
+if PULSE
+i3status_SOURCES += src/pulse.c
+endif
dist_sysconf_DATA = \
i3status.conf
--- a/src/print_volume.c 2019-01-23 09:03:56.000000000 +0100
+++ b/src/print_volume.c 2021-07-19 13:53:19.409302195 +0200
@@ -21,7 +21,7 @@
#include <sys/soundcard.h>
#endif
-#ifdef __OpenBSD__
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <fcntl.h>
#include <unistd.h>
#include <sys/audioio.h>
@@ -31,6 +31,8 @@
#include "i3status.h"
#include "queue.h"
+#define STRING_SIZE 10
+
#define ALSA_VOLUME(channel) \
err = snd_mixer_selem_get_##channel##_dB_range(elem, &min, &max) || \
snd_mixer_selem_get_##channel##_dB(elem, 0, &val); \
@@ -48,30 +50,20 @@
fmt = fmt_muted; \
}
-static char *apply_volume_format(const char *fmt, char *outwalk, int ivolume, const char *devicename) {
- const char *walk = fmt;
+static char *apply_volume_format(const char *fmt, char *buffer, int ivolume, const char *devicename) {
+ char string_volume[STRING_SIZE];
- for (; *walk != '\0'; walk++) {
- if (*walk != '%') {
- *(outwalk++) = *walk;
-
- } else if (BEGINS_WITH(walk + 1, "%")) {
- outwalk += sprintf(outwalk, "%s", pct_mark);
- walk += strlen("%");
-
- } else if (BEGINS_WITH(walk + 1, "volume")) {
- outwalk += sprintf(outwalk, "%d%s", ivolume, pct_mark);
- walk += strlen("volume");
-
- } else if (BEGINS_WITH(walk + 1, "devicename")) {
- outwalk += sprintf(outwalk, "%s", devicename);
- walk += strlen("devicename");
+ snprintf(string_volume, STRING_SIZE, "%d%s", ivolume, pct_mark);
- } else {
- *(outwalk++) = '%';
- }
- }
- return outwalk;
+ placeholder_t placeholders[] = {
+ {.name = "%%", .value = pct_mark},
+ {.name = "%volume", .value = string_volume},
+ {.name = "%devicename", .value = devicename}};
+
+ const size_t num = sizeof(placeholders) / sizeof(placeholder_t);
+ buffer = format_placeholders(fmt, &placeholders[0], num);
+
+ return buffer;
}
void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_muted, const char *device, const char *mixer, int mixer_idx) {
@@ -86,7 +78,7 @@
free(instance);
}
-#if !defined(__DragonFly__) && !defined(__OpenBSD__)
+#if HAS_PULSEAUDIO
/* Try PulseAudio first */
/* If the device name has the format "pulse[:N]" where N is the
@@ -119,11 +111,11 @@
/* negative result means error, stick to 0 */
if (ivolume < 0)
ivolume = 0;
- outwalk = apply_volume_format(muted ? fmt_muted : fmt,
- outwalk,
- ivolume,
- description);
- goto out;
+ buffer = apply_volume_format(muted ? fmt_muted : fmt,
+ buffer,
+ ivolume,
+ description);
+ goto out_with_format;
} else if (!strcasecmp(device, "default") && pulse_initialize()) {
/* no device specified or "default" set */
char description[MAX_SINK_DESCRIPTION_LEN];
@@ -136,11 +128,11 @@
START_COLOR("color_degraded");
pbval = 0;
}
- outwalk = apply_volume_format(muted ? fmt_muted : fmt,
- outwalk,
- ivolume,
- description);
- goto out;
+ buffer = apply_volume_format(muted ? fmt_muted : fmt,
+ buffer,
+ ivolume,
+ description);
+ goto out_with_format;
}
/* negative result or NULL description means error, fail PulseAudio attempt */
}
@@ -242,13 +234,14 @@
ALSA_MUTE_SWITCH(capture)
}
- outwalk = apply_volume_format(fmt, outwalk, avg, mixer_name);
+ buffer = apply_volume_format(fmt, buffer, avg, mixer_name);
snd_mixer_close(m);
snd_mixer_selem_id_free(sid);
+ goto out_with_format;
#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
char *mixerpath;
char defaultmixer[] = "/dev/mixer";
int mixfd, vol, devmask = 0;
@@ -261,7 +254,7 @@
mixerpath = defaultmixer;
if ((mixfd = open(mixerpath, O_RDWR)) < 0) {
-#if defined(__OpenBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
warn("audioio: Cannot open mixer");
#else
warn("OSS: Cannot open mixer");
@@ -272,7 +265,7 @@
if (mixer_idx > 0)
free(mixerpath);
-#if defined(__OpenBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int oclass_idx = -1, master_idx = -1, master_mute_idx = -1;
int master_next = AUDIO_MIXER_LAST;
mixer_devinfo_t devinfo, devinfo2;
@@ -327,15 +320,17 @@
vol = (int)vinfo.un.value.level[AUDIO_MIXER_LEVEL_MONO];
}
- vinfo.dev = master_mute_idx;
- vinfo.type = AUDIO_MIXER_ENUM;
- if (ioctl(mixfd, AUDIO_MIXER_READ, &vinfo) == -1)
- goto out;
+ if (master_mute_idx != -1) {
+ vinfo.dev = master_mute_idx;
+ vinfo.type = AUDIO_MIXER_ENUM;
+ if (ioctl(mixfd, AUDIO_MIXER_READ, &vinfo) == -1)
+ goto out;
- if (master_mute_idx != -1 && vinfo.un.ord) {
- START_COLOR("color_degraded");
- fmt = fmt_muted;
- pbval = 0;
+ if (vinfo.un.ord) {
+ START_COLOR("color_degraded");
+ fmt = fmt_muted;
+ pbval = 0;
+ }
}
#else
@@ -354,13 +349,20 @@
}
#endif
- outwalk = apply_volume_format(fmt, outwalk, vol & 0x7f, devicename);
+ buffer = apply_volume_format(fmt, buffer, vol & 0x7f, devicename);
close(mixfd);
+ goto out_with_format;
#endif
out:
- *outwalk = '\0';
if (!pbval)
END_COLOR;
OUTPUT_FULL_TEXT(buffer);
+ return;
+
+out_with_format:
+ if (!pbval)
+ END_COLOR;
+ OUTPUT_FULL_TEXT(buffer);
+ free(buffer);
}
--- /dev/null 2021-07-19 09:18:28.360000528 +0200
+++ b/src/format_placeholders.c 2021-07-19 13:57:16.830921169 +0200
@@ -0,0 +1,70 @@
+/*
+ * vim:ts=4:sw=4:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
+ *
+ */
+// copied from i3:libi3/format_placeholders.c
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "i3status.h"
+
+#ifndef CS_STARTS_WITH
+#define CS_STARTS_WITH(string, needle) (strncmp((string), (needle), strlen((needle))) == 0)
+#endif
+
+/*
+ * Replaces occurrences of the defined placeholders in the format string.
+ *
+ */
+char *format_placeholders(const char *format, placeholder_t *placeholders, int num) {
+ if (format == NULL)
+ return NULL;
+
+ /* We have to first iterate over the string to see how much buffer space
+ * we need to allocate. */
+ int buffer_len = strlen(format) + 1;
+ for (const char *walk = format; *walk != '\0'; walk++) {
+ for (int i = 0; i < num; i++) {
+ if (!CS_STARTS_WITH(walk, placeholders[i].name))
+ continue;
+
+ buffer_len = buffer_len - strlen(placeholders[i].name) + strlen(placeholders[i].value);
+ walk += strlen(placeholders[i].name) - 1;
+ break;
+ }
+ }
+
+ /* Now we can parse the format string. */
+ char buffer[buffer_len];
+ char *outwalk = buffer;
+ for (const char *walk = format; *walk != '\0'; walk++) {
+ if (*walk != '%') {
+ *(outwalk++) = *walk;
+ continue;
+ }
+
+ bool matched = false;
+ for (int i = 0; i < num; i++) {
+ if (!CS_STARTS_WITH(walk, placeholders[i].name)) {
+ continue;
+ }
+
+ matched = true;
+ outwalk += sprintf(outwalk, "%s", placeholders[i].value);
+ walk += strlen(placeholders[i].name) - 1;
+ break;
+ }
+
+ if (!matched)
+ *(outwalk++) = *walk;
+ }
+
+ *outwalk = '\0';
+ return sstrdup(buffer);
+}
--- a/include/i3status.h 2019-02-21 15:35:12.000000000 +0100
+++ b/include/i3status.h 2021-07-19 14:06:39.618462946 +0200
@@ -198,6 +199,16 @@
void reset_cursor(void);
void maybe_escape_markup(char *text, char **buffer);
+// copied from i3:libi3/format_placeholders.c
+/* src/format_placeholders.c */
+typedef struct {
+ /* The placeholder to be replaced, e.g., "%title". */
+ const char *name;
+ /* The value this placeholder should be replaced with. */
+ const char *value;
+} placeholder_t;
+char *format_placeholders(const char *format, placeholder_t *placeholders, int num);
+
/* src/auto_detect_format.c */
char *auto_detect_format();