commit 11f4b123bf2c5da2ccfb76f6f212345f761f0db2
parent aee37eed9a9c1d9257ec8263667d0d9950dabf4d
Author: Daniel Barlow <dan@telent.net>
Date: Sun, 16 Jan 2022 14:49:54 +0000
add saturn
Diffstat:
5 files changed, 185 insertions(+), 0 deletions(-)
diff --git a/saturn/Makefile b/saturn/Makefile
@@ -0,0 +1,15 @@
+FENNEL?=$(fennel)
+PREFIX?=/usr/local
+
+MODULES=main.fnl
+
+%.lua : %.fnl
+ lua $(FENNEL) --compile $< > $@
+
+saturn: $(patsubst %.fnl,%.lua,$(MODULES)) Makefile
+ (echo -e "#!/usr/bin/lua\n" ; cat main.lua ) > $@
+ chmod +x $@
+
+install:
+ mkdir -p $(PREFIX)/bin
+ cp saturn $(PREFIX)/bin
diff --git a/saturn/README.md b/saturn/README.md
@@ -0,0 +1,9 @@
+# Saturn
+
+> Saturn 5, you really were the greatest sight
+
+A very simple launcher app for the Pinephone, written using Fennel and
+the LGI bindings to gobject-introspection.
+
+I may someday separate this from the rest of Slab but for the moment
+it's more convenient to keep it all together
diff --git a/saturn/default.nix b/saturn/default.nix
@@ -0,0 +1,60 @@
+{ stdenv
+, callPackage
+, fetchFromGitHub
+, fetchurl
+, gobject-introspection
+, gtk3
+, lib
+, librsvg
+, lua53Packages
+, lua5_3
+, makeWrapper
+}:
+let 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; [
+ inifile
+ inspect
+ lgi
+ luafilesystem
+ luaposix
+ readline
+ ]);
+in stdenv.mkDerivation {
+ pname = "saturn";
+ version = "0.4.9"; # nearly Saturn 0.5
+ 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 = ''
+ echo $GI_TYPELIB_PATH
+ wrapProgram $out/bin/saturn --prefix GDK_PIXBUF_MODULE_FILE : ${librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache --prefix GI_TYPELIB_PATH : "$GI_TYPELIB_PATH"
+ '';
+}
diff --git a/saturn/main.fnl b/saturn/main.fnl
@@ -0,0 +1,94 @@
+
+(local lfs (require :lfs))
+(local inifile (require :inifile))
+(local inspect (require :inspect))
+(local posix (require :posix))
+
+(local lgi (require :lgi))
+(local Gtk lgi.Gtk)
+(local Pango lgi.Pango)
+
+(local icon-theme (Gtk.IconTheme.get_default))
+
+(fn find-icon [name]
+ (var found false)
+ (if (= (name.sub 1 1) "/")
+ (Gtk.Image.new_from_file name)
+ (let [sizes (icon-theme:get_icon_sizes name)]
+
+ (each [_ res (pairs [64 48]) :until found]
+ (set found (icon-theme:load_icon
+ name res
+ (+ Gtk.IconLookupFlags.FORCE_SVG Gtk.IconLookupFlags.USE_BUILTIN))))
+ (Gtk.Image.new_from_pixbuf found))))
+
+(fn read-desktop-file [f]
+ (let [parsed (inifile.parse f)
+ vals (. parsed "Desktop Entry")]
+ (when vals.Icon (tset vals "IconImage" (find-icon vals.Icon)))
+ vals))
+
+(fn all-apps []
+ (var apps-table [])
+ ;; for i in ${XDG_DATA_DIRS//:/ /} ; do ls $i/applications/*.desktop ;done
+ (each [path (string.gmatch (os.getenv "XDG_DATA_DIRS") "[^:]*")]
+ (let [apps (.. path "/applications/")]
+ (when (lfs.attributes apps)
+ (each [f (lfs.dir apps)]
+ (when (= (f:sub -8) ".desktop")
+ (let [attrs (read-desktop-file (.. apps f))]
+ (when (not attrs.NoDisplay)
+ (table.insert apps-table attrs))))))))
+ apps-table)
+
+;; Exec entries in desktop files may contain %u %f and other characters
+;; in which the launcheris supposed to interpolate filenames/urls etc.
+;; We don't
+(fn parse-percents [str]
+ (str:gsub "%%(.)" (fn [c] (if (= c "%") "%" ""))))
+
+(fn spawn-async [vec]
+ (let [pid (posix.unistd.fork)]
+ (if (> pid 0)
+ true
+ (< pid 0)
+ (assert (= "can't spawn" nil))
+ (posix.spawn vec))))
+
+(fn launch [app]
+; (print (if app.DBusActivatable "dbus" "not dbus"))
+ (let [cmd (parse-percents app.Exec)]
+ (if app.Terminal
+ (spawn-async ["/usr/bin/env" "kitty" cmd])
+ (spawn-async ["/usr/bin/env" "sh" "-c" cmd]))
+ (os.exit)))
+
+(fn button-for [app]
+ (doto (Gtk.Button
+ {
+ :label app.Name
+ :image-position Gtk.PositionType.TOP
+ :relief Gtk.ReliefStyle.NONE
+ :on_clicked #(launch app) })
+ (: :set_image app.IconImage)))
+
+(let [grid (Gtk.Grid {
+; :orientation "vertical"
+ :column_spacing 8
+ :row_spacing 8
+ })
+ scrolled-window (Gtk.ScrolledWindow {})
+ window (Gtk.Window {
+ :title "Saturn V"
+ :default_width 720
+ :default_height 800
+ })]
+ (each [i app (ipairs (all-apps))]
+ (let [x (% (- i 1) 8)
+ y (// (- i 1) 8)]
+ (grid:attach (button-for app) x y 1 1)))
+ (scrolled-window:add grid)
+ (window:add scrolled-window)
+ (window:show_all))
+
+(Gtk:main)
diff --git a/saturn/shell.nix b/saturn/shell.nix
@@ -0,0 +1,7 @@
+with import <nixpkgs> {} ;
+(callPackage ./. {
+}).overrideAttrs(o: {
+ GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache";
+ nativeBuildInputs = o.nativeBuildInputs ++
+ [ ] ;
+})