summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Light <sam@lightscale.co.uk>2025-09-10 19:37:28 +0100
committerSam Light <sam@lightscale.co.uk>2025-09-10 19:37:28 +0100
commitd9b456d738e5013d48f41f5e6315ef7c22d6acf0 (patch)
tree2e3722f5697cbf883c4b16edc87726b9e510bce1
Initial commit
-rw-r--r--.gitignore23
-rw-r--r--Makefile.am15
-rw-r--r--config.h.in74
-rw-r--r--configure.ac56
-rw-r--r--src/dwminfo.c61
-rw-r--r--src/modules/.dirstamp0
-rw-r--r--src/modules/battery.c73
-rw-r--r--src/modules/battery.h22
-rw-r--r--src/modules/pulse.c136
-rw-r--r--src/modules/pulse.h26
-rw-r--r--src/modules/time.c29
-rw-r--r--src/modules/time.h15
-rw-r--r--src/signal.c34
-rw-r--r--src/signal.h10
-rw-r--r--src/somebarinfo.c86
-rw-r--r--src/text.c49
-rw-r--r--src/text.h21
17 files changed, 730 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d6d8760
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+somebarinfo
+dwminfo
+*.o
+
+
+configure
+Makefile
+Makefile.in
+config.log
+config.status
+autom4te.cache
+aclocal.m4
+install-sh
+compile
+depcomp
+missing
+.deps
+ar-lib
+config.h
+config.guess
+config.sub
+stamp-h1
+.dirstamp
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..6889b3e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,15 @@
+bin_PROGRAMS=somebarinfo dwminfo
+
+CFLAGS=$(LIBPULSE_CFLAGS)
+LDADD=$(LIBPULSE_LIBS) -lm
+
+COMMON_SOURCES=src/text.c \
+ src/signal.c \
+ src/modules/pulse.c \
+ src/modules/time.c \
+ src/modules/battery.c
+
+somebarinfo_SOURCES=src/somebarinfo.c $(COMMON_SOURCES)
+
+dwminfo_LDADD=$(LDADD) -lX11
+dwminfo_SOURCES=src/dwminfo.c $(COMMON_SOURCES)
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..8929c27
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,74 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if C supports variable-length arrays. */
+#undef HAVE_C_VARARRAYS
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if C does not support variable-length arrays, and if the
+ compiler does not already define this. */
+#undef __STDC_NO_VLA__
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..c0eb433
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,56 @@
+AC_INIT([dwxinfo], [0.1.0])
+
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+AM_SILENT_RULES([yes])
+
+: ${CFLAGS="-O2"}
+
+AC_PROG_CC
+AC_C_CONST
+AC_C_VARARRAYS
+AC_FUNC_MALLOC
+AC_PROG_SED
+AC_CHECK_INCLUDES_DEFAULT
+
+AC_CHECK_HEADER([fcntl.h], [], [
+ echo "Missing fcntl.h header"
+ exit -1
+])
+
+AC_CHECK_HEADER([errno.h], [], [
+ echo "Missing errno.h header"
+ exit -1
+])
+
+AC_CHECK_HEADER([signal.h], [], [
+ echo "Missing signal.h header"
+ exit -1
+])
+
+AC_CHECK_HEADER([poll.h], [], [
+ echo "Missing poll.h header"
+ exit -1
+])
+
+PKG_CHECK_MODULES([LIBPULSE], [libpulse])
+
+AC_ARG_ENABLE(debug,
+ AS_HELP_STRING([--enable-debug], [enable debugging, default: yes]),
+ [case "${enableval}" in
+ yes) debug=true ;;
+ no) debug=false ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
+ esac],
+ [debug=true])
+
+if test x"$debug" = x"true"; then
+ CFLAGS="$CFLAGS -g"
+fi
+
+CFLAGS="$CFLAGS -Wall"
+
+AC_CONFIG_FILES([
+ Makefile
+])
+AC_OUTPUT
diff --git a/src/dwminfo.c b/src/dwminfo.c
new file mode 100644
index 0000000..8e04b43
--- /dev/null
+++ b/src/dwminfo.c
@@ -0,0 +1,61 @@
+#include "signal.h"
+#include "text.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+struct state {
+ Display * display;
+ Window window;
+ struct text * text;
+};
+
+static int
+init_state(struct state * s)
+{
+ s->display = XOpenDisplay(NULL);
+ s->window = XDefaultRootWindow(s->display);
+ s->text = text_new();
+ return 0;
+}
+
+static void
+deinit_state(struct state * s)
+{
+ XCloseDisplay(s->display);
+ text_free(s->text);
+}
+
+static void
+update_status(struct state * s)
+{
+ text_update(s->text);
+ XStoreName(s->display, s->window, s->text->value);
+ XSync(s->display, 1);
+}
+
+static void
+run_loop(struct state * s)
+{
+ while(signal_running) {
+ update_status(s);
+ usleep(1000 * 500);
+ }
+}
+
+int main(void)
+{
+ struct state s;
+
+ signal_setup_actions();
+
+ init_state(&s);
+ run_loop(&s);
+ deinit_state(&s);
+
+ return 0;
+}
diff --git a/src/modules/.dirstamp b/src/modules/.dirstamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/modules/.dirstamp
diff --git a/src/modules/battery.c b/src/modules/battery.c
new file mode 100644
index 0000000..6c656fe
--- /dev/null
+++ b/src/modules/battery.c
@@ -0,0 +1,73 @@
+#include "battery.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <tgmath.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#define UPDATE_FREQUENCY 20
+
+static int
+open_battery_file(const char * name)
+{
+ char path[128];
+ snprintf(path, 128, "/sys/class/power_supply/BAT0/%s", name);
+ return open(path, O_RDONLY);
+}
+
+static int
+battery_value(int file)
+{
+ int val = 0;
+ char buf[16];
+
+ memset(&buf, '\0', 16);
+ lseek(file, 0, SEEK_SET);
+ read(file, &buf, sizeof(char) * 16);
+ sscanf(buf, "%d", &val);
+
+ return val;
+}
+
+struct battery *
+battery_new()
+{
+ struct battery * b = malloc(sizeof(struct battery));
+ int file = open_battery_file("charge_full");
+
+ b->full = battery_value(file);
+ b->file_current = open_battery_file("charge_now");
+ b->last_update = 0;
+
+ close(file);
+
+ return b;
+}
+
+void
+battery_free(struct battery * b)
+{
+ close(b->file_current);
+ free(b);
+}
+
+void battery_update(struct battery * b)
+{
+ int now;
+ float percentf;
+ int percent;
+ time_t now_time = time(NULL);
+
+ if((now_time - b->last_update) >= UPDATE_FREQUENCY) {
+ b->last_update = now_time;
+
+ now = battery_value(b->file_current);
+
+ percentf = (100.0f / b->full) * now;
+ percent = round(percentf);
+
+ snprintf(b->value, BATTERY_VALUE_SIZE, "%d%%", percent);
+ }
+}
diff --git a/src/modules/battery.h b/src/modules/battery.h
new file mode 100644
index 0000000..92489b5
--- /dev/null
+++ b/src/modules/battery.h
@@ -0,0 +1,22 @@
+#ifndef _DWXINFO_MODULES_BATTERY_H_
+#define _DWXINFO_MODULES_BATTERY_H_
+
+#include <stdio.h>
+#include <time.h>
+
+#define BATTERY_VALUE_SIZE 5
+
+struct battery {
+ int full;
+ int file_current;
+ time_t last_update;
+
+ char value[BATTERY_VALUE_SIZE];
+};
+
+struct battery * battery_new();
+void battery_free(struct battery *);
+
+void battery_update(struct battery *);
+
+#endif
diff --git a/src/modules/pulse.c b/src/modules/pulse.c
new file mode 100644
index 0000000..cbbfe35
--- /dev/null
+++ b/src/modules/pulse.c
@@ -0,0 +1,136 @@
+#include "pulse.h"
+
+#include "../signal.h"
+
+#include <pulse/mainloop.h>
+#include <pulse/context.h>
+#include <pulse/introspect.h>
+#include <pulse/volume.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <tgmath.h>
+
+static void
+run_loop(struct pulse * p)
+{
+ p->run_loop = true;
+ while(p->run_loop && signal_running) {
+ pa_mainloop_iterate(p->ml, 1, NULL);
+ }
+}
+
+static void
+stop_loop(struct pulse * p)
+{
+ p->run_loop = false;
+}
+
+static void
+server_info_cb(pa_context * ctx, const pa_server_info * info, void * ud)
+{
+ struct pulse * p = (struct pulse *) ud;
+
+ size_t s = strlen(info->default_sink_name);
+
+ p->default_sink = malloc(s + 1);
+ memset(p->default_sink, '\0', s + 1);
+ strncpy(p->default_sink, info->default_sink_name, s);
+
+ stop_loop(p);
+}
+
+static void
+state_cb(pa_context * ctx, void * ud)
+{
+ pa_context_state_t state = pa_context_get_state(ctx);
+ struct pulse * p = (struct pulse *) ud;
+
+ switch(state) {
+
+ case PA_CONTEXT_READY:
+ pa_context_get_server_info(p->ctx, server_info_cb, p);
+ break;
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ stop_loop(p);
+ break;
+ default: break;
+
+ }
+}
+
+struct pulse *
+pulse_new()
+{
+ struct pulse * p = malloc(sizeof(struct pulse));
+
+ memset(p->value, '\0', PULSE_VALUE_SIZE);
+
+ p->default_sink = NULL;
+ p->run_loop = false;
+
+ p->ml = pa_mainloop_new();
+ p->ctx = pa_context_new(pa_mainloop_get_api(p->ml), NULL);
+
+ pa_context_set_state_callback(p->ctx, state_cb, p);
+
+ pa_context_connect(p->ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
+
+ run_loop(p);
+
+ return p;
+}
+
+void
+pulse_free(struct pulse * p)
+{
+ if(p->default_sink != NULL) free(p->default_sink);
+
+ if(p->ctx->proplist) {
+ pa_proplist_free(p->ctx->proplist);
+ }
+
+ pa_context_disconnect(p->ctx);
+ pa_context_unref(p->ctx);
+ pa_mainloop_free(p->ml);
+
+ free(p);
+}
+
+static void
+sink_info_cb(pa_context * ctx, const pa_sink_info * info, int eol, void * ud)
+{
+ struct pulse * p = (struct pulse *) ud;
+ pa_volume_t vol, norm;
+
+ if(eol > 0) {
+ stop_loop(p);
+ }
+ else {
+ if(info->mute) {
+ strncpy(p->value, "M", PULSE_VALUE_SIZE);
+ }
+ else {
+ vol = pa_cvolume_avg(&info->volume);
+ vol -= PA_VOLUME_MUTED;
+ norm = PA_VOLUME_NORM - PA_VOLUME_MUTED;
+
+ vol = round((100.0f / norm) * vol);
+ snprintf(p->value, PULSE_VALUE_SIZE, "%d%%", vol);
+ }
+ }
+}
+
+void
+pulse_update(struct pulse * p)
+{
+ pa_operation * op;
+
+ if(p->default_sink != NULL) {
+ op = pa_context_get_sink_info_by_name(p->ctx, p->default_sink, sink_info_cb, p);
+ pa_operation_unref(op);
+ run_loop(p);
+ }
+}
diff --git a/src/modules/pulse.h b/src/modules/pulse.h
new file mode 100644
index 0000000..708d05c
--- /dev/null
+++ b/src/modules/pulse.h
@@ -0,0 +1,26 @@
+#ifndef _DWXINFO_PULSE_H_
+#define _DWXINFO_PULSE_H_
+
+#include <stdbool.h>
+
+#define PULSE_VALUE_SIZE 5
+
+typedef struct pa_mainloop pa_mainloop;
+typedef struct pa_context pa_context;
+
+struct pulse {
+ pa_mainloop * ml;
+ pa_context * ctx;
+ char * default_sink;
+
+ bool run_loop;
+
+ char value[PULSE_VALUE_SIZE];
+};
+
+struct pulse * pulse_new();
+void pulse_free(struct pulse *);
+
+void pulse_update(struct pulse *);
+
+#endif
diff --git a/src/modules/time.c b/src/modules/time.c
new file mode 100644
index 0000000..84f894e
--- /dev/null
+++ b/src/modules/time.c
@@ -0,0 +1,29 @@
+#include "time.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <tgmath.h>
+
+struct time *
+time_new()
+{
+ struct time * t = malloc(sizeof(struct time));
+ return t;
+}
+
+void
+time_free(struct time * t)
+{
+ free(t);
+}
+
+void
+time_update(struct time * t)
+{
+ time_t timer;
+ struct tm * tm;
+
+ time(&timer);
+ tm = gmtime(&timer);
+ strftime(t->value, TIME_VALUE_SIZE, "%F [%a] %T", tm);
+}
diff --git a/src/modules/time.h b/src/modules/time.h
new file mode 100644
index 0000000..2dec7d5
--- /dev/null
+++ b/src/modules/time.h
@@ -0,0 +1,15 @@
+#ifndef _DWXINFO_MODULES_TIME_H_
+#define _DWXINFO_MODULES_TIME_H_
+
+#define TIME_VALUE_SIZE 32
+
+struct time {
+ char value[TIME_VALUE_SIZE];
+};
+
+struct time * time_new();
+void time_free(struct time *);
+
+void time_update(struct time *);
+
+#endif
diff --git a/src/signal.c b/src/signal.c
new file mode 100644
index 0000000..e993ae3
--- /dev/null
+++ b/src/signal.c
@@ -0,0 +1,34 @@
+#include "signal.h"
+
+#include <string.h>
+
+sig_atomic_t signal_running;
+
+static void
+handle_signal_shutdown(int sig)
+{
+ signal_running = 0;
+}
+
+int
+signal_setup_actions()
+{
+ int rc;
+ struct sigaction action;
+
+ signal_running = 1;
+
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = handle_signal_shutdown;
+ rc = sigemptyset(&action.sa_mask);
+ if(rc < 0) return rc;
+ rc = sigaction(SIGINT, &action, 0);
+ if(rc < 0) return rc;
+
+ rc = sigemptyset(&action.sa_mask);
+ if(rc < 0) return rc;
+ rc = sigaction(SIGTERM, &action, 0);
+ if(rc < 0) return rc;
+
+ return rc;
+}
diff --git a/src/signal.h b/src/signal.h
new file mode 100644
index 0000000..d3a513a
--- /dev/null
+++ b/src/signal.h
@@ -0,0 +1,10 @@
+#ifndef _DWXINFO_SIGNAL_H_
+#define _DWXINFO_SIGNAL_H_
+
+#include <signal.h>
+
+extern sig_atomic_t signal_running;
+
+int signal_setup_actions();
+
+#endif
diff --git a/src/somebarinfo.c b/src/somebarinfo.c
new file mode 100644
index 0000000..0dc2d50
--- /dev/null
+++ b/src/somebarinfo.c
@@ -0,0 +1,86 @@
+#include "signal.h"
+#include "text.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define SOMEBAR_CMD "status"
+
+struct state {
+ FILE * file;
+ struct text * text;
+};
+
+static int
+init_state(struct state * s)
+{
+ char * dir = getenv("XDG_RUNTIME_DIR");
+ char * file = "/somebar-0";
+ size_t dir_len = strlen(dir);
+ size_t file_len = strlen(file);
+ size_t path_len = dir_len + file_len + 1;
+ char path[path_len];
+
+ memset(path, '\0', path_len);
+
+ strncat(path, dir, dir_len);
+ strncat(path, file, file_len);
+
+ s->text = NULL;
+
+ s->file = fopen(path, "a");
+ if(s->file == NULL) return -1;
+
+ s->text = text_new();
+ return 0;
+}
+
+static void
+deinit_state(struct state * s)
+{
+ if(s->file) fclose(s->file);
+ if(s->text) text_free(s->text);
+}
+
+static void
+update_status(struct state * s)
+{
+ const size_t
+ cmd_len = strlen(SOMEBAR_CMD),
+ msg_len = TEXT_SIZE + cmd_len + 3;
+ char msg[msg_len];
+
+ text_update(s->text);
+
+ snprintf(msg, msg_len, "%s %s\n", SOMEBAR_CMD, s->text->value);
+
+ fputs(msg, s->file);
+ fflush(s->file);
+}
+
+static void
+run_loop(struct state * s)
+{
+ while(signal_running) {
+ update_status(s);
+ usleep(1000 * 800);
+ }
+}
+
+int main(void)
+{
+ int rc;
+ struct state s;
+
+ signal_setup_actions();
+
+ rc = init_state(&s);
+
+ if(rc == 0) run_loop(&s);
+
+ deinit_state(&s);
+
+ return 0;
+}
diff --git a/src/text.c b/src/text.c
new file mode 100644
index 0000000..df3b3c4
--- /dev/null
+++ b/src/text.c
@@ -0,0 +1,49 @@
+#include "text.h"
+
+#include "modules/pulse.h"
+#include "modules/time.h"
+#include "modules/battery.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tgmath.h>
+
+struct text *
+text_new()
+{
+ struct text * t = malloc(sizeof(struct text));
+
+ memset(t->value, '\0', TEXT_SIZE);
+
+ t->battery = battery_new();
+ t->time = time_new();
+ t->pulse = pulse_new();
+
+ return t;
+}
+
+void
+text_free(struct text * t)
+{
+ time_free(t->time);
+ pulse_free(t->pulse);
+ battery_free(t->battery);
+ free(t);
+}
+
+void
+text_update(struct text * t)
+{
+ time_update(t->time);
+ pulse_update(t->pulse);
+ battery_update(t->battery);
+
+ snprintf(
+ t->value, TEXT_SIZE,
+ "VOL: %s | BAT: %s | %s",
+ t->pulse->value,
+ t->battery->value,
+ t->time->value);
+}
diff --git a/src/text.h b/src/text.h
new file mode 100644
index 0000000..752d15f
--- /dev/null
+++ b/src/text.h
@@ -0,0 +1,21 @@
+#ifndef _DWXINFO_TEXT_H_
+#define _DWXINFO_TEXT_H_
+
+#include <stdio.h>
+
+#define TEXT_SIZE 512
+
+struct text {
+ char value[TEXT_SIZE];
+
+ struct battery * battery;
+ struct pulse * pulse;
+ struct time * time;
+};
+
+struct text * text_new();
+void text_free(struct text *);
+
+void text_update(struct text *);
+
+#endif