diff --git a/blinkenlicht/README.md b/blinkenlicht/README.md new file mode 100644 index 0000000..f1992b8 --- /dev/null +++ b/blinkenlicht/README.md @@ -0,0 +1,37 @@ +# Blinkenlicht + +Yet another "bar" program for wlroots-basd Wayland compositors, but +this one is written in [Fennel](https://fennel-lang.org/) and +therefore better than all the others because it is more niche. + +More seriously: you might prefer this over another status bar program +if you want fine-grained control over what is shown in your bar and +you are happy to exert that control in a Lua-based Lisp language. + +```fennel +(bar + { + :anchor [:top :right] + :orientation :horizontal + :indicators + [ + (indicator { + :interval 200 + :icon #(if (> loadavg 2) "sad-face" "happy-face") + }) + (let [f (io.open "/tmp/statuspipe" "r")] + (indicator { + :poll [f] + :text #(f:read:sub 1 10) + })) + (indicator { + :interval 5000 + :text #(.. (disk-free-percent "/") "%") + :on-click #(spawn "baobab") + }) + (indicator { + :interval 1000 + :text #(os.date "%X") + }) + ]}) +``` diff --git a/blinkenlicht/bl.fnl b/blinkenlicht/bl.fnl new file mode 100644 index 0000000..1e11817 --- /dev/null +++ b/blinkenlicht/bl.fnl @@ -0,0 +1,42 @@ +(local {: bar : indicator : run} (require :blinkenlicht)) + +(fn loadavg [] + (with-open [f (io.open "/proc/loadavg" :r)] + (tonumber (: (f:read "*a") :match "[0-9.]+" )))) + +(fn disk-free-percent [] + 83) + +(fn spawn [] + true) + +(bar + { + :anchor [:top :right] + :orientation :horizontal + :indicators + [ + (indicator { + :interval 200 + :icon #(if (> (loadavg) 2) "face-sad" "face-smile") + }) + ;; (let [f (io.open "/tmp/statuspipe" "r")] + ;; (indicator { + ;; :poll [f] + ;; :text #((f:read):sub 1 10) + ;; })) + (indicator { + :text "HI!" + }) + (indicator { + :interval 5000 + :text #(.. (disk-free-percent "/") "%") + :on-click #(spawn "baobab") + }) + (indicator { + :interval 1000 + :text #(os.date "%X") + }) + ]}) + +(run) diff --git a/blinkenlicht/blinkenlicht.fnl b/blinkenlicht/blinkenlicht.fnl new file mode 100644 index 0000000..1d95f14 --- /dev/null +++ b/blinkenlicht/blinkenlicht.fnl @@ -0,0 +1,95 @@ +(local {: Gtk + : Gdk + : GdkPixbuf + : GLib + : cairo } (require :lgi)) + +(local {: view} (require :fennel)) + +(local icon-theme (Gtk.IconTheme.get_default)) + +(local HEIGHT 48) + +(fn resolve [f] + (match (type f) + "string" f + "function" (f))) + +(fn find-icon-pixbuf [name] + (var found nil) + (each [_ res (pairs [HEIGHT 128 64 48]) :until found] + (let [pixbuf (icon-theme:load_icon + name res + (+ Gtk.IconLookupFlags.FORCE_SVG + Gtk.IconLookupFlags.USE_BUILTIN))] + (when pixbuf + (set found (pixbuf:scale_simple + HEIGHT (* pixbuf.width (/ HEIGHT pixbuf.height)) + GdkPixbuf.InterpType.BILINEAR))))) + found) + +(fn find-icon [name] + (if (= (name:sub 1 1) "/") + ;; From a direct path + (GdkPixbuf.Pixbuf.new_from_file_at_scale name HEIGHT -1 true) + ;; From icon theme + (Gtk.Image.new_from_pixbuf (find-icon-pixbuf name)))) + +(fn update-button [button icon text] + (match (button:get_child) it (button:remove it)) + (let [i (resolve icon)] + (print :update i (resolve text)) + (if i + (button:add (find-icon i)) + (button:add (Gtk.Label {:label (resolve text)}))) + (button:show_all) + )) + +(fn indicator [{: interval + : icon + : poll + : text + : on-click}] + (let [button + (Gtk.Button { :relief Gtk.ReliefStyle.NONE}) + update #(update-button button icon text)] + (update) + { + : interval + : poll + : button + : update + })) + +(local bars []) + +(fn bar [{ : anchor : orientation : indicators }] + (let [window (Gtk.Window {} ) + orientation (match orientation + :vertical Gtk.Orientation.VERTICAL + :horizontal Gtk.Orientation.HORIZONTAL) + box (Gtk.Box { :orientation orientation})] + (table.insert bars { : window : anchor : indicators }) + (each [_ i (ipairs indicators)] + (box:pack_start i.button false false 0)) + (window:add box))) + +(fn run [] + (GLib.timeout_add + 0 + 1000 + (fn [] + (print :update) + (each [_ bar (ipairs bars)] + (each [_ indicator (ipairs bar.indicators)] + (indicator:update))) + true)) + (each [_ b (ipairs bars)] + (b.window:show_all)) + (Gtk.main)) + +{ + : bar + : indicator + : run + } diff --git a/blinkenlicht/default.nix b/blinkenlicht/default.nix new file mode 100644 index 0000000..395d557 --- /dev/null +++ b/blinkenlicht/default.nix @@ -0,0 +1,70 @@ +{ stdenv +, callPackage +, fetchFromGitHub +, fetchurl +, gobject-introspection +, gtk3 +, lib +, librsvg +, lua53Packages +#, luaDbusProxy +, lua5_3 +, makeWrapper +, writeText +}: +let + pname = "blinkenlicht"; + fennel = fetchurl { + name = "fennel.lua"; + url = "https://fennel-lang.org/downloads/fennel-1.0.0"; + hash = "sha256:1nha32yilzagfwrs44hc763jgwxd700kaik1is7x7lsjjvkgapw7"; + }; + inifile = let lua = lua5_3; in lua53Packages.buildLuaPackage rec { + pname = "inifile"; + name = "${pname}-${version}"; + version = "1.0.2"; + src = fetchFromGitHub { + owner = "bartbes"; + repo = "inifile"; + rev = "f0b41a8a927f3413310510121c5767021957a4e0"; + sha256 = "1ry0q238vbp8wxwy4qp1aychh687lvbckcf647pmc03rwkakxm4r"; + }; + buildPhase = ":"; + installPhase = '' + mkdir -p "$out/share/lua/${lua.luaversion}" + cp inifile.lua "$out/share/lua/${lua.luaversion}/" + ''; + }; + + lua = lua5_3.withPackages (ps: with ps; [ + # luaDbusProxy + # inifile + # inspect + lgi + luafilesystem + luaposix + # penlight + readline + ]); + +in stdenv.mkDerivation { + inherit pname; + version = "0.1"; + src =./.; + + inherit fennel; + + buildInputs = [ lua gtk3 gobject-introspection.dev ]; + nativeBuildInputs = [ lua makeWrapper ]; + + makeFlags = [ "PREFIX=${placeholder "out"}" ]; + # GDK_PIXBUF_MODULE_FILE setting is to support SVG icons without + # their having been transformed to bitmaps. + # This makes a big difference to how many icons are displayed on + # my machine + postInstall = '' + mkdir -p $out/share/dbus-1/services + + wrapProgram $out/bin/${pname} --set GDK_PIXBUF_MODULE_FILE ${librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache --set GI_TYPELIB_PATH "$GI_TYPELIB_PATH" + ''; +} diff --git a/blinkenlicht/shell.nix b/blinkenlicht/shell.nix new file mode 100644 index 0000000..e404c8c --- /dev/null +++ b/blinkenlicht/shell.nix @@ -0,0 +1,2 @@ +with import <nixpkgs> {} ; +callPackage ./. {}