diff options
| author | Arpit Chakladar <arpitchakladar+git@gmail.com> | 2026-08-27 01:55:13 +0530 |
|---|---|---|
| committer | Arpit Chakladar <arpitchakladar+git@gmail.com> | 2026-08-29 03:50:30 +0530 |
| commit | 9a6f21b65da927fb064773bd83e92151c50b6823 (patch) | |
| tree | 897de5d11ba347529e0f16fe554eac0d5d908fd1 /modules/desktop/eww | |
| parent | f3407d3d21c29eb4a59732d02f8f309b113fa480 (diff) | |
| download | home-manager-config-9a6f21b65da927fb064773bd83e92151c50b6823.tar.gz home-manager-config-9a6f21b65da927fb064773bd83e92151c50b6823.zip | |
desktop: added some of basic system information in the system section
- added date, time, memory used (percent), cpu usage (percent), network
status (icons for up or down)
Diffstat (limited to 'modules/desktop/eww')
| -rw-r--r-- | modules/desktop/eww/eww.mustache.scss | 4 | ||||
| -rw-r--r-- | modules/desktop/eww/system-stats.py | 91 | ||||
| -rw-r--r-- | modules/desktop/eww/yuck.nix | 155 |
3 files changed, 189 insertions, 61 deletions
diff --git a/modules/desktop/eww/eww.mustache.scss b/modules/desktop/eww/eww.mustache.scss index 52049af..5004e65 100644 --- a/modules/desktop/eww/eww.mustache.scss +++ b/modules/desktop/eww/eww.mustache.scss @@ -45,6 +45,10 @@ window#eww-bar { border: none; } +.system-item .system-label.small { + font-size: 12px; +} + .workspace-button.active, .window-button.focused { border-color: #{{base07}}; } diff --git a/modules/desktop/eww/system-stats.py b/modules/desktop/eww/system-stats.py new file mode 100644 index 0000000..380dc25 --- /dev/null +++ b/modules/desktop/eww/system-stats.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +"""system-stats: emit {cpu, ram, net} as JSON. CPU/RAM sample on an interval +inside one long-lived process (no per-tick spawn)""" +import json +import subprocess +import threading +import time + +STATE_LOCK = threading.Lock() +STATE = {"cpu": 0, "ram": 0, "net": "down"} + + +def read_cpu_times(): + with open("/proc/stat") as f: + parts = f.readline().split()[1:] + vals = list(map(int, parts)) + idle = vals[3] + vals[4] # idle + iowait + total = sum(vals) + return idle, total + + +def cpu_ram_loop(interval=2.0): + prev_idle, prev_total = read_cpu_times() + while True: + time.sleep(interval) + idle, total = read_cpu_times() + d_idle = idle - prev_idle + d_total = total - prev_total + prev_idle, prev_total = idle, total + cpu_pct = round((1 - d_idle / d_total) * 100) if d_total else 0 + + with open("/proc/meminfo") as f: + meminfo = {} + for line in f: + k, v, *_ = line.split() + meminfo[k.rstrip(":")] = int(v) + total_kb = meminfo["MemTotal"] + avail_kb = meminfo["MemAvailable"] + ram_pct = round((1 - avail_kb / total_kb) * 100) if total_kb else 0 + + with STATE_LOCK: + STATE["cpu"] = cpu_pct + STATE["ram"] = ram_pct + emit() + + +def check_net_status() -> str: + try: + with open("/run/systemd/netif/state") as f: + state = dict( + line.strip().split("=", 1) for line in f if "=" in line + ) + except FileNotFoundError: + return "down" + + oper = state.get("OPER_STATE", "off") + if oper == "routable": + return "up" + if oper in ("degraded", "carrier", "degraded-carrier"): + return "limited" + return "down" + + +def net_loop(): + with STATE_LOCK: + STATE["net"] = check_net_status() + emit() + + proc = subprocess.Popen( + ["inotifywait", "-m", "-e", "modify", "/run/systemd/netif/state"], + stdout=subprocess.PIPE, text=True, bufsize=1, + ) + for _ in proc.stdout: + with STATE_LOCK: + STATE["net"] = check_net_status() + emit() + + +def emit(): + with STATE_LOCK: + print(json.dumps(STATE), flush=True) + + +def main(): + threading.Thread(target=cpu_ram_loop, daemon=True).start() + threading.Thread(target=net_loop, daemon=True).start() + threading.Event().wait() # keep main thread alive + + +if __name__ == "__main__": + main() diff --git a/modules/desktop/eww/yuck.nix b/modules/desktop/eww/yuck.nix index d522d9b..03de4bf 100644 --- a/modules/desktop/eww/yuck.nix +++ b/modules/desktop/eww/yuck.nix @@ -8,71 +8,91 @@ config = lib.mkIf config.desktop.enable { programs.eww.yuckConfig = let - workspaces = - let - pythonEnv = pkgs.python3.withPackages (ps: [ ps.pygobject3 ]); - in - pkgs.stdenv.mkDerivation { - pname = "eww-workspaces"; - version = "0.1.0"; - src = ./workspaces.py; - dontUnpack = true; - meta.mainProgram = "eww-workspaces"; - - nativeBuildInputs = [ - pkgs.wrapGAppsHook3 - pkgs.gobject-introspection - ]; - buildInputs = [ pkgs.gtk3 ]; - - installPhase = '' - mkdir -p $out/bin - install -m755 $src $out/bin/eww-workspaces - patchShebangs $out/bin/eww-workspaces - ''; - - # wrapGAppsHook3 wraps every executable in $out/bin automatically, - # setting GI_TYPELIB_PATH etc. from buildInputs' closure. - preFixup = '' - gappsWrapperArgs+=(--prefix PATH : "${pythonEnv}/bin") - ''; - }; - - activate-windows = - let - pythonEnv = pkgs.python3.withPackages (ps: [ ps.pygobject3 ]); - in - pkgs.stdenv.mkDerivation { - pname = "eww-activate-windows"; - version = "0.1.0"; - src = ./activate-windows.py; - dontUnpack = true; - meta.mainProgram = "eww-activate-windows"; - - nativeBuildInputs = [ - pkgs.wrapGAppsHook3 - pkgs.gobject-introspection - ]; - buildInputs = [ pkgs.gtk3 ]; - - installPhase = '' - mkdir -p $out/bin - install -m755 $src $out/bin/eww-activate-windows - patchShebangs $out/bin/eww-activate-windows - ''; - - # wrapGAppsHook3 wraps every executable in $out/bin automatically, - # setting GI_TYPELIB_PATH etc. from buildInputs' closure. - preFixup = '' - gappsWrapperArgs+=(--prefix PATH : "${pythonEnv}/bin") - ''; - }; + pythonEnv = pkgs.python3.withPackages (ps: [ ps.pygobject3 ]); + system-stats = pkgs.stdenv.mkDerivation { + pname = "eww-system-stats"; + version = "0.1.0"; + src = ./system-stats.py; + dontUnpack = true; + meta.mainProgram = "eww-system-stats"; + + nativeBuildInputs = [ + pkgs.wrapGAppsHook3 + pkgs.gobject-introspection + ]; + buildInputs = [ pkgs.gtk3 ]; + + installPhase = '' + mkdir -p $out/bin + install -m755 $src $out/bin/eww-system-stats + patchShebangs $out/bin/eww-system-stats + ''; + + # wrapGAppsHook3 wraps every executable in $out/bin automatically, + # setting GI_TYPELIB_PATH etc. from buildInputs' closure. + preFixup = '' + gappsWrapperArgs+=(--prefix PATH : "${pythonEnv}/bin") + ''; + }; + + workspaces = pkgs.stdenv.mkDerivation { + pname = "eww-workspaces"; + version = "0.1.0"; + src = ./workspaces.py; + dontUnpack = true; + meta.mainProgram = "eww-workspaces"; + + nativeBuildInputs = [ + pkgs.wrapGAppsHook3 + pkgs.gobject-introspection + ]; + buildInputs = [ pkgs.gtk3 ]; + + installPhase = '' + mkdir -p $out/bin + install -m755 $src $out/bin/eww-workspaces + patchShebangs $out/bin/eww-workspaces + ''; + + # wrapGAppsHook3 wraps every executable in $out/bin automatically, + # setting GI_TYPELIB_PATH etc. from buildInputs' closure. + preFixup = '' + gappsWrapperArgs+=(--prefix PATH : "${pythonEnv}/bin") + ''; + }; + + activate-windows = pkgs.stdenv.mkDerivation { + pname = "eww-activate-windows"; + version = "0.1.0"; + src = ./activate-windows.py; + dontUnpack = true; + meta.mainProgram = "eww-activate-windows"; + + nativeBuildInputs = [ + pkgs.wrapGAppsHook3 + pkgs.gobject-introspection + ]; + buildInputs = [ pkgs.gtk3 ]; + + installPhase = '' + mkdir -p $out/bin + install -m755 $src $out/bin/eww-activate-windows + patchShebangs $out/bin/eww-activate-windows + ''; + + # wrapGAppsHook3 wraps every executable in $out/bin automatically, + # setting GI_TYPELIB_PATH etc. from buildInputs' closure. + preFixup = '' + gappsWrapperArgs+=(--prefix PATH : "${pythonEnv}/bin") + ''; + }; in '' (defpoll time :interval "10s" "date '+%H:%M'") (defpoll date :interval "60s" "date '+%d/%m'") (deflisten workspaces :initial "[]" "${lib.getExe workspaces}") (deflisten active-windows :initial "[]" "${lib.getExe activate-windows}") + (deflisten system_stats :initial "{\"cpu\":0,\"ram\":0,\"net\":\"down\"}" "${lib.getExe system-stats}") (defwindow bar :monitor 0 @@ -123,8 +143,21 @@ (defwidget system-widget [] (box :orientation "v" :space-evenly false :spacing 6 :halign "fill" :class "system" - (label :class "system-item" :text time) - (label :class "system-item" :text date))) + (box :orientation "v" :class "system-item" :space-evenly false :spacing 4 + (label :class "system-icon" :text "''${system_stats.net == "up" ? " " : " "}") + (label :class "system-label" :text "")) + (box :orientation "v" :class "system-item" :space-evenly false :spacing 4 + (label :class "system-icon" :text " ") + (label :class "system-label" :text "''${system_stats.cpu}%")) + (box :orientation "v" :class "system-item" :space-evenly false :spacing 4 + (label :class "system-icon" :text " ") + (label :class "system-label" :text "''${system_stats.ram}%")) + (box :orientation "v" :class "system-item" :space-evenly false :spacing 4 + (label :class "system-icon" :text " ") + (label :class "system-label small" :text time)) + (box :orientation "v" :class "system-item" :space-evenly false :spacing 4 + (label :class "system-icon" :text "") + (label :class "system-label small" :text date)))) ''; }; } |
