Commit Diff


commit - 0c5cb071191e1ef383a3460f0ffd8356692e4913
commit + 1157627b862a560c1fc5bc7187ec0b77bd75d146
blob - 5d2fc8e15b42e88ca7161f818e2d0e78ac4758e2
blob + 6efe31da62cbed8fe0aed6abb85dd8e3df8ccf02
--- Makefile
+++ Makefile
@@ -10,7 +10,7 @@ CFLAGS = -std=c11 -pedantic -Wall -Wextra $(shell pkg-
 LDFLAGS = 
 LDLIBS = $(shell pkg-config --libs xft x11)
 
-all: bxbar bxinfo
+all: bxbar bxinfo bxnet
 
 bxbar: bxbar.o
 	$(CC) $(LDFLAGS) -o $@ bxbar.o $(LDLIBS)
@@ -24,19 +24,25 @@ bxbar.o: bxbar.c config.h
 bxinfo: bxinfo.o
 	$(CC) -o $@ bxinfo.o -lX11
 
+bxnet: bxnet.o
+	$(CC) -o $@ bxnet.o -lX11
+
 clean:
 	rm -f bxbar bxbar.o
 	rm -f bxinfo bxinfo.o
+	rm -f bxnet bxnet.o
 
 install:
 	install -d $(DESTDIR)$(PREFIX)/bin
 	install -m 755 bxbar $(DESTDIR)$(PREFIX)/bin/bxbar
 	install -m 755 bxinfo $(DESTDIR)$(PREFIX)/bin/bxinfo
+	install -m 755 bxnet $(DESTDIR)$(PREFIX)/bin/bxnet
 	install -m 755 bxbarrc.lua $(DESTDIR)$(PREFIX)/bin/bxbarrc.lua
 
 uninstall:
 	rm -f $(DESTDIR)$(PREFIX)/bin/bxbar
 	rm -f $(DESTDIR)$(PREFIX)/bin/bxinfo
+	rm -f $(DESTDIR)$(PREFIX)/bin/bxnet
 	rm -f $(DESTDIR)$(PREFIX)/bin/bxbarrc.lua
 
 .PHONY: all clean install uninstall
blob - 8fa6c143e0075ca003d757ad1ba6f17179818ac2
blob + 2f76ebb2abc7bd4924b30f1350d2cd0a8d5396e9
--- bxbarrc.lua
+++ bxbarrc.lua
@@ -76,6 +76,14 @@ local function get_battery(bat_path)
     return "[" .. bar .. "] " .. cap .. "%" .. charging
 end
 
+local function get_network()
+    local h = io.popen("bxnet", "r")
+    if not h then return "--/--" end
+    local status = h:read("*l")
+    h:close()
+    return status or "--/--"
+end
+
 -- Discover battery path once at startup
 local bat_path = find_battery_path()
 
@@ -84,9 +92,10 @@ while true do
     local ws, title = get_x11_info()
     local dt  = os.date("%Y-%m-%d %a %H:%M")
     local bat = bat_path and get_battery(bat_path) or ""
+    local net = get_network()
 
     local left  = ws .. "    " .. title
-    local right = bat .. "     " .. dt
+    local right = net .. "    " .. bat .. "     " .. dt
 
     io.write(left .. string.char(1) .. right .. "\n")
     io.flush()
blob - 7d3a78ec662265c9b3363c03bbc80f79e8b96c43
blob + 9ca29e1d98c28da7af66269bdd54a7f44f0d19d2
--- config.def.h
+++ config.def.h
@@ -13,5 +13,10 @@
 #define BG_COLOR        "#000000"
 #define FONT            "monospace:size=14"
 #define DELIMITER       '\x01'
+#define IFNAMSIZ        16
+/* Network Status Icons */
+#define NET_ETH_ICON    "[---]"
+#define NET_WLAN_ICON   "<--->"
+#define NET_NONE_ICON   "--/--"
 #define DEBUG_LOGGING 0
 
blob - /dev/null
blob + 1c4718aba2d64e731392d48fd0990b30ab9f47f7 (mode 644)
--- /dev/null
+++ bxnet.c
@@ -0,0 +1,104 @@
+/*
+ * bxnet - A basic X network helper
+ * Queries /sys/class/net/ and prints the active interface status to stdout.
+ * See LICENSE.md and README.md for details.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#define SYS_NET_PATH "/sys/class/net"
+
+static int is_dir(const char *path);
+
+/* Read a file and trim the trailing newline.
+ * Returns 1 on success, 0 on failure. */
+static int
+read_sys_file(const char *path, char *buf, size_t buflen)
+{
+    FILE *f = fopen(path, "r");
+    if (!f) return 0;
+
+    if (!fgets(buf, buflen, f)) {
+        fclose(f);
+        return 0;
+    }
+    fclose(f);
+
+    /* Strip trailing whitespace/newline */
+    buf[strcspn(buf, "\r\n")] = '\0';
+    return 1;
+}
+
+/* Check the operstate of an interface.
+ * Returns 1 if "up", 0 otherwise. */
+static int
+is_iface_up(const char *iface)
+{
+    char path[256], state[16];
+    snprintf(path, sizeof(path), "%s/%s/operstate", SYS_NET_PATH, iface);
+    if (!read_sys_file(path, state, sizeof(state)))
+        return 0;
+    return strcmp(state, "up") == 0;
+}
+
+/* Check if a path is a directory.
+ * Returns 1 if directory, 0 otherwise. */
+static int
+is_dir(const char *path)
+{
+    struct stat st;
+    if (stat(path, &st) != 0)
+        return 0;
+    return S_ISDIR(st.st_mode);
+}
+
+int
+main(void)
+{
+    DIR *d = opendir(SYS_NET_PATH);
+    if (!d) {
+        /* If we can't even read /sys, just return the down state */
+        puts(NET_NONE_ICON);
+        return 1;
+    }
+
+    struct dirent *de;
+    int found_eth = 0, found_wlan = 0;
+
+    while ((de = readdir(d)) != NULL) {
+        if (de->d_name[0] == '.' || strcmp(de->d_name, "lo") == 0)
+            continue;
+
+        if (!is_iface_up(de->d_name))
+            continue;
+
+        /* Check for wireless/ subdirectory — kernel-level indicator of WiFi */
+        char wireless_path[64];
+        int iface_len = strnlen(de->d_name, IFNAMSIZ);
+        snprintf(wireless_path, sizeof(wireless_path),
+                 "%s/%.*s/wireless", SYS_NET_PATH, iface_len, de->d_name);
+        if (is_dir(wireless_path)) {
+            found_wlan = 1;
+        } else {
+            /* Assume Ethernet for other "up" interfaces */
+            found_eth = 1;
+        }
+    }
+    closedir(d);
+
+    if (found_eth)       puts(NET_ETH_ICON);
+    else if (found_wlan) puts(NET_WLAN_ICON);
+    else                 puts(NET_NONE_ICON);
+
+    return 0;
+}
+