Compare commits
22 Commits
63359b5d06
...
c3b796ef79
Author | SHA1 | Date |
---|---|---|
Daniel Barlow | c3b796ef79 | |
Daniel Barlow | 6fd41b7e1c | |
Daniel Barlow | d12cb03a4e | |
Daniel Barlow | f0de997680 | |
Daniel Barlow | d83cce069c | |
Daniel Barlow | f847830a06 | |
Daniel Barlow | 7ad42c43b2 | |
Daniel Barlow | c5a546f10f | |
Daniel Barlow | 1c61ff87b2 | |
Daniel Barlow | 298822d493 | |
Daniel Barlow | 25ab42dad0 | |
Daniel Barlow | 6d7bf21483 | |
Daniel Barlow | a0e7e97a5c | |
Daniel Barlow | 0bedce6144 | |
Daniel Barlow | 4d968948cd | |
Daniel Barlow | 09a57c4269 | |
Daniel Barlow | 82635955fe | |
Daniel Barlow | ff895276c8 | |
Daniel Barlow | 3174caa0ed | |
Daniel Barlow | 4e78ad4d91 | |
Daniel Barlow | 1ed8201d86 | |
Daniel Barlow | 2932649a51 |
4
Makefile
4
Makefile
|
@ -9,6 +9,10 @@ default toplevel:
|
||||||
android-bootimg android-recovery:
|
android-bootimg android-recovery:
|
||||||
nix-build $(NFLAGS) -A outputs.android.$@ -o $@
|
nix-build $(NFLAGS) -A outputs.android.$@ -o $@
|
||||||
|
|
||||||
|
lk2nd:
|
||||||
|
nix-build $(NFLAGS) ../mobile-nixos --argstr device motorola-harpia -A pkgs.pkgsBuildBuild.lk2nd.msm8916 -o lk2nd
|
||||||
|
|
||||||
|
|
||||||
update: toplevel
|
update: toplevel
|
||||||
nix-copy-closure --to $(DEVICE) -v --include-outputs ./toplevel
|
nix-copy-closure --to $(DEVICE) -v --include-outputs ./toplevel
|
||||||
ssh $(DEVICE) "nix-env --profile /nix/var/nix/profiles/system --set `readlink toplevel` && /nix/var/nix/profiles/system/bin/switch-to-configuration switch"
|
ssh $(DEVICE) "nix-env --profile /nix/var/nix/profiles/system --set `readlink toplevel` && /nix/var/nix/profiles/system/bin/switch-to-configuration switch"
|
||||||
|
|
40
README
40
README
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
Config for my moto potter to turn it into a bike computer. We will
|
Config for my moto harpia to turn it into a bike computer. We will
|
||||||
need
|
need
|
||||||
|
|
||||||
- working gps
|
- working gps
|
||||||
|
@ -19,19 +19,43 @@ write the app in fennel. I want it to
|
||||||
- show where I am on a map
|
- show where I am on a map
|
||||||
- record trail of where I've been (note: indoor counts too)
|
- record trail of where I've been (note: indoor counts too)
|
||||||
|
|
||||||
we can use l"ove2d instead of dragging in that gtk stuff
|
|
||||||
|
|
||||||
SDL2
|
|
||||||
|
|
||||||
To run an SDL2 application on Wayland, set
|
can we somehow do non-flakey bluetooth (is it dbus?)
|
||||||
SDL_VIDEODRIVER=wayland.
|
|
||||||
|
|
||||||
can we do bluetooth not through dbus? dbus seems to make it flakey
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cool extras
|
cool extras
|
||||||
===========
|
===========
|
||||||
|
|
||||||
adjust screen brightness (go dark when not moving)
|
adjust screen brightness
|
||||||
|
|
||||||
|
* turn off backlight when stopped after a minute
|
||||||
|
* dim the screen when following a route and the next
|
||||||
|
navigation instruction is still some way off
|
||||||
|
* tap to wake screen
|
||||||
|
|
||||||
|
note that IPS LCD requires as much battery for dark pixels
|
||||||
|
as light ones, so we get no power saving by colouring only part
|
||||||
|
of the screen
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
random notes follow ...
|
||||||
|
|
||||||
|
1) Satellite requires these commands to be run before
|
||||||
|
it will work.
|
||||||
|
|
||||||
|
mmcli -m 0 --enable
|
||||||
|
mmcli -m 0 --location-enable-gps-raw
|
||||||
|
mmcli -m 0 --location-enable-gps-nmea
|
||||||
|
mmcli -m 0 --location-status
|
||||||
|
|
||||||
|
|
||||||
|
2) we should make saturn give visual feedback while it's loading an
|
||||||
|
app. How does it know when the app has finished loading? Maybe it
|
||||||
|
could get told when its window is obscured
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ let
|
||||||
makeFlags = ["prefix=${placeholder "out"}"];
|
makeFlags = ["prefix=${placeholder "out"}"];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
saturn = pkgs.callPackage ./pkgs/saturn {};
|
||||||
|
|
||||||
drm-framebuffer = pkgs.stdenv.mkDerivation {
|
drm-framebuffer = pkgs.stdenv.mkDerivation {
|
||||||
name = "drm-framebuffer";
|
name = "drm-framebuffer";
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
|
@ -38,12 +40,21 @@ in {
|
||||||
];
|
];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev:
|
||||||
|
let mm = pkgs.callPackage ./pkgs/modem-manager {};
|
||||||
|
in {
|
||||||
|
wlr-randr = prev.wlr-randr.overrideAttrs(o: {
|
||||||
|
depsBuildBuild = [ final.pkgsBuildBuild.pkg-config ];
|
||||||
|
});
|
||||||
|
modemmanager-small = mm;
|
||||||
|
satellite = prev.satellite.override { modemmanager = mm; };
|
||||||
|
maps = final.callPackage ./pkgs/maps {};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
mobile = {
|
mobile = {
|
||||||
adbd.enable = true;
|
adbd.enable = true;
|
||||||
# boot.stage-1.gui.enable = false;
|
|
||||||
# beautification.splash = false;
|
|
||||||
# quirks.fb-refresher.enable = lib.mkForce false;
|
|
||||||
# quirks.qualcomm.msm8953-modem.enable = true;
|
|
||||||
boot.stage-1.firmware = [
|
boot.stage-1.firmware = [
|
||||||
modemFirmware
|
modemFirmware
|
||||||
pkgs.wireless-regdb
|
pkgs.wireless-regdb
|
||||||
|
@ -56,28 +67,142 @@ in {
|
||||||
system.stateVersion = "23.11";
|
system.stateVersion = "23.11";
|
||||||
|
|
||||||
boot.kernelParams = [
|
boot.kernelParams = [
|
||||||
"dyndbg=\"file drivers/base/firmware_loader/main.c +fmp\""
|
# "dyndbg=\"file drivers/base/firmware_loader/main.c +fmp\""
|
||||||
# "dyndbg=\"file drivers/gpu/drm/panel/msm8953-generated/panel-boe-bs052fhm-a00-6c01.c +fmp\""
|
# "dyndbg=\"file drivers/gpu/drm/panel/msm8953-generated/panel-boe-bs052fhm-a00-6c01.c +fmp\""
|
||||||
# "dyndbg=\"file drivers/video/backlight/qcom-wled.c +fmp\""
|
# "dyndbg=\"file drivers/video/backlight/qcom-wled.c +fmp\""
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# according to fdisk, /dev/mmcblk0p41 is 30469887-7471104=22998783
|
||||||
|
# blocks, and if we let it get resized by whatever magic this is
|
||||||
|
# (I'm assuming systemd-growfs), on the subsequent boot we'll get
|
||||||
|
# an error
|
||||||
|
|
||||||
|
# EXT4-fs (mmcblk0p41): bad geometry: block count 2883067 exceeds size of device (2874848 blocks)
|
||||||
|
|
||||||
|
# in which neither number matches the reported size (they're both
|
||||||
|
# about 10% of it). cool.
|
||||||
|
|
||||||
|
boot.growPartition = lib.mkForce false;
|
||||||
|
fileSystems."/" = lib.mkDefault {
|
||||||
|
autoResize = lib.mkForce false;
|
||||||
|
};
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
ACTION!="add|change|move|bind", GOTO="mm_qcom_soc_end"
|
||||||
|
|
||||||
|
# Process only known wwan, net and rpmsg ports
|
||||||
|
SUBSYSTEM=="net", DRIVERS=="bam-dmux", GOTO="mm_qcom_soc_process"
|
||||||
|
# SUBSYSTEM=="platform", DRIVERS=="bam-dmux", GOTO="mm_qcom_soc_process"
|
||||||
|
SUBSYSTEM=="net", DRIVERS=="ipa", GOTO="mm_qcom_soc_process"
|
||||||
|
SUBSYSTEM=="wwan", DRIVERS=="qcom-q6v5-mss", GOTO="mm_qcom_soc_process"
|
||||||
|
SUBSYSTEM=="rpmsg", DRIVERS=="qcom-q6v5-mss", GOTO="mm_qcom_soc_process"
|
||||||
|
GOTO="mm_qcom_soc_end"
|
||||||
|
|
||||||
|
LABEL="mm_qcom_soc_process"
|
||||||
|
|
||||||
|
# Flag the port as being part of the SoC
|
||||||
|
ENV{ID_MM_QCOM_SOC}="1"
|
||||||
|
|
||||||
|
# #
|
||||||
|
# # Add a common physdev UID to all ports in the Qualcomm SoC, so that they
|
||||||
|
# # are all bound together to the same modem object.
|
||||||
|
# #
|
||||||
|
# # The MSM8916, MSM8974, .... Qualcomm SoCs use the combination of RPMSG/WWAN
|
||||||
|
# # based control ports plus BAM-DMUX based network ports.
|
||||||
|
# #
|
||||||
|
ENV{ID_MM_PHYSDEV_UID}="qcom-soc"
|
||||||
|
|
||||||
|
# port type hints for the rpmsgexport-ed ports
|
||||||
|
SUBSYSTEM=="rpmsg", ATTR{name}=="DATA*", ATTR{name}=="*_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1"
|
||||||
|
SUBSYSTEM=="rpmsg", ATTR{name}=="DATA*", ATTR{name}!="*_CNTL", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||||
|
|
||||||
|
# ignore every other port without explicit hints
|
||||||
|
SUBSYSTEM=="rpmsg", ENV{ID_MM_PORT_TYPE_QMI}!="1", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}!="1", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
|
||||||
|
# explicitly ignore ports intended for USB tethering (DATA40, DATA40_CNTL)
|
||||||
|
SUBSYSTEM=="rpmsg", ATTR{name}=="DATA40*", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
KERNEL=="rmnet_usb*", ENV{ID_MM_PORT_IGNORE}="1"
|
||||||
|
|
||||||
|
# flag all rpmsg ports under this plugin as candidate
|
||||||
|
# KERNEL=="rpmsg*", SUBSYSTEM=="rpmsg", ENV{ID_MM_CANDIDATE}="1"
|
||||||
|
KERNEL=="rpmsg*", SUBSYSTEM=="rpmsg", ENV{ID_MM_CANDIDATE}="1"
|
||||||
|
|
||||||
|
LABEL="mm_qcom_soc_end"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ACTION!="add|change|move|bind", GOTO="mm_candidate_end"
|
||||||
|
|
||||||
|
# # Opening bound but disconnected Bluetooth RFCOMM ttys would initiate the
|
||||||
|
# # connection. Don't do that.
|
||||||
|
|
||||||
|
KERNEL=="rfcomm*", DEVPATH=="*/virtual/*", GOTO="mm_candidate_end" # */
|
||||||
|
|
||||||
|
SUBSYSTEM=="net", ENV{ID_MM_CANDIDATE}="1"
|
||||||
|
|
||||||
|
# WWAN subsystem port handling
|
||||||
|
# - All USB devices ignored for now, only PCI devices expected
|
||||||
|
# - Only "wwan_port" device types processed (single ports); we fully ignore
|
||||||
|
# the "wwan_dev" device type (full device, not just one port)
|
||||||
|
|
||||||
|
SUBSYSTEMS=="usb", GOTO="mm_candidate_end"
|
||||||
|
SUBSYSTEM=="wwan", ENV{DEVTYPE}=="wwan_dev", GOTO="mm_candidate_end"
|
||||||
|
SUBSYSTEM=="wwan", ENV{ID_MM_CANDIDATE}="1"
|
||||||
|
|
||||||
|
LABEL="mm_candidate_end"
|
||||||
|
|
||||||
|
# unlock the gps engine
|
||||||
|
SUBSYSTEM=="wwan", ENV{DEVNAME}=="/dev/wwan0qmi0", ENV{DEVTYPE}=="wwan_port", \
|
||||||
|
RUN+="${pkgs.libqmi}/bin/qmicli -pd $env{DEVNAME} --loc-set-engine-lock=none"
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
|
systemd.services.ModemManager = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig =
|
||||||
|
let script = pkgs.writeScript "start-modem-manager" ''
|
||||||
|
#!${pkgs.bash}/bin/bash
|
||||||
|
source ${config.system.build.setEnvironment}
|
||||||
|
${pkgs.modemmanager-small}/bin/ModemManager
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
StandardInput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
SyslogIdentifier = "ModemManager";
|
||||||
|
ExecStart = script;
|
||||||
|
Restart = "always";
|
||||||
|
BindsTo = ["dbus.service"];
|
||||||
|
};
|
||||||
|
};
|
||||||
networking = {
|
networking = {
|
||||||
useDHCP = true;
|
useDHCP = true;
|
||||||
hostName = "biscuit";
|
hostName = "biscuit";
|
||||||
networkmanager = { enable = false; };
|
networkmanager = { enable = false; };
|
||||||
|
useNetworkd = true;
|
||||||
inherit (secrets) wireless;
|
inherit (secrets) wireless;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
||||||
# environment.systemPackages = [ qrtr tqftpserv ];
|
services.cage =
|
||||||
services.udev.extraRules = ''
|
let wlinit = pkgs.writeScript "wlinit" ''
|
||||||
# copied from https://github.com/andersson/rpmsgexport
|
${pkgs.wlr-randr}/bin/wlr-randr --output DSI-1 --scale 2
|
||||||
ACTION=="add", SUBSYSTEM=="rpmsg", KERNEL=="rpmsg_ctrl[0-9]*", ATTRS{rpmsg_name}=="pronto", RUN+="${rpmsgexport}/bin/rpmsgexport /dev/$name APPS_RIVA_CTRL"
|
exec ${saturn}/bin/saturn
|
||||||
SUBSYSTEM=="rpmsg", KERNEL=="rpmsg_ctrl[0-9]*", ATTRS{rpmsg_name}=="?*", SYMLINK+="rpmsg/$attr{rpmsg_name}/ctrl"
|
'';
|
||||||
SUBSYSTEM=="rpmsg", KERNEL=="rpmsg[0-9]*", ATTR{name}=="?*", ATTRS{rpmsg_name}=="?*", SYMLINK+="rpmsg/$attr{rpmsg_name}/$attr{name}"
|
in {
|
||||||
'';
|
enable = true;
|
||||||
environment.systemPackages = with pkgs; [ drm-framebuffer];
|
program = wlinit;
|
||||||
|
user = "dan";
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
drm-framebuffer
|
||||||
|
saturn
|
||||||
|
satellite
|
||||||
|
wlr-randr
|
||||||
|
modemmanager-small
|
||||||
|
maps
|
||||||
|
];
|
||||||
|
|
||||||
users.users.dan = {
|
users.users.dan = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
|
@ -95,5 +220,30 @@ in {
|
||||||
hardware.opengl = {
|
hardware.opengl = {
|
||||||
enable = true; driSupport = true;
|
enable = true; driSupport = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.services = {
|
||||||
|
rmtfs =
|
||||||
|
# the four files in here are partition images:
|
||||||
|
# partlabel => filename
|
||||||
|
# modemst1 => modem_fs1
|
||||||
|
# modemst2 => modem_fs2
|
||||||
|
# fsc => modem_fsc
|
||||||
|
# fsg => modem_fsg
|
||||||
|
|
||||||
|
let files = pkgs.runCommand "rmtfs" {} ''
|
||||||
|
mkdir -p $out/lib/firmware
|
||||||
|
cp ${./local/uncompressed-firmware/rmtfs}/* $out/lib/firmware
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
# https://github.com/andersson/rmtfs/blob/7a5ae7e0a57be3e09e0256b51b9075ee6b860322/rmtfs.c#L507-L541
|
||||||
|
ExecStart = "${pkgs.rmtfs}/bin/rmtfs -s -r -o ${files}/lib/firmware";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "10";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
FENNEL?=fennel
|
||||||
|
PREFIX?=/usr/local
|
||||||
|
NAME?=maps
|
||||||
|
|
||||||
|
MODULES=main.fnl
|
||||||
|
|
||||||
|
%.lua : %.fnl
|
||||||
|
$(FENNEL) --compile $< > $@
|
||||||
|
|
||||||
|
$(NAME): $(patsubst %.fnl,%.lua,$(MODULES)) Makefile
|
||||||
|
(echo -e "#!/usr/bin/env lua\n" ; cat main.lua ) > $@
|
||||||
|
chmod +x $@
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(PREFIX)/bin $(PREFIX)/
|
||||||
|
cp $(NAME) $(PREFIX)/bin
|
|
@ -0,0 +1,85 @@
|
||||||
|
{ stdenv
|
||||||
|
, pkg-config
|
||||||
|
, buildPackages
|
||||||
|
, callPackage
|
||||||
|
, clutter
|
||||||
|
, fetchFromGitHub
|
||||||
|
, fetchurl
|
||||||
|
, gobject-introspection
|
||||||
|
, gtk3
|
||||||
|
, lib
|
||||||
|
, lua53Packages
|
||||||
|
, lua5_3
|
||||||
|
, makeDesktopItem
|
||||||
|
, makeWrapper
|
||||||
|
, wrapGAppsHook3
|
||||||
|
, writeText
|
||||||
|
, osm-gps-map
|
||||||
|
, glib-networking
|
||||||
|
, copyDesktopItems
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
luaPackages = lua53Packages;
|
||||||
|
fennel = luaPackages.fennel;
|
||||||
|
lgi = luaPackages.buildLuaPackage {
|
||||||
|
pname = "lgi";
|
||||||
|
version = "0.9.2-2";
|
||||||
|
buildInputs = [ gobject-introspection ];
|
||||||
|
nativeBuildInputs = [ pkg-config ];
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "lgi-devs";
|
||||||
|
repo = "lgi";
|
||||||
|
rev = "e06ad94c8a1c84e3cdb80cee293450a280dfcbc7";
|
||||||
|
hash = "sha256-VYr/DV1FAyzPe6p6Quc1nmsHup23IAMfz532rL167Q4=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
lua = lua5_3.withPackages (ps: with ps; [
|
||||||
|
lgi
|
||||||
|
luafilesystem
|
||||||
|
luaposix
|
||||||
|
readline
|
||||||
|
]);
|
||||||
|
pname = "maps";
|
||||||
|
in stdenv.mkDerivation {
|
||||||
|
inherit pname;
|
||||||
|
version = "0.1";
|
||||||
|
src =./.;
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
lua
|
||||||
|
gtk3.dev
|
||||||
|
gobject-introspection # .dev
|
||||||
|
osm-gps-map
|
||||||
|
glib-networking
|
||||||
|
# gdk-pixbuf
|
||||||
|
# glib
|
||||||
|
# libchamplain
|
||||||
|
];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
buildPackages.lua
|
||||||
|
gobject-introspection
|
||||||
|
makeWrapper
|
||||||
|
fennel
|
||||||
|
wrapGAppsHook3
|
||||||
|
copyDesktopItems
|
||||||
|
];
|
||||||
|
GIO_EXTRA_MODULES = [ "${glib-networking.out}/lib/gio/modules" ];
|
||||||
|
|
||||||
|
makeFlags = [ "PREFIX=${placeholder "out"}" "NAME=${pname}" ];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/share/icons/
|
||||||
|
cp icon.svg $out/share/icons/${pname}.svg
|
||||||
|
'';
|
||||||
|
|
||||||
|
desktopItems = [
|
||||||
|
(makeDesktopItem {
|
||||||
|
name = pname;
|
||||||
|
desktopName = "Maps";
|
||||||
|
exec = pname;
|
||||||
|
type = "Application";
|
||||||
|
icon = "nix-snowflake"; # "${placeholder "out"}/share/icons/${pname}.svg";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
; (local { : view } (require :fennel))
|
||||||
|
|
||||||
|
(local {
|
||||||
|
: Gtk
|
||||||
|
: OsmGpsMap
|
||||||
|
: Gdk
|
||||||
|
}
|
||||||
|
(require :lgi))
|
||||||
|
|
||||||
|
(local CSS "
|
||||||
|
label.readout {
|
||||||
|
font: 48px \"Noto Sans\";
|
||||||
|
margin: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
")
|
||||||
|
|
||||||
|
(fn styles []
|
||||||
|
(let [style_provider (Gtk.CssProvider)]
|
||||||
|
(Gtk.StyleContext.add_provider_for_screen
|
||||||
|
(Gdk.Screen.get_default)
|
||||||
|
style_provider
|
||||||
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||||
|
)
|
||||||
|
(style_provider:load_from_data CSS)))
|
||||||
|
|
||||||
|
(local window (Gtk.Window {
|
||||||
|
:title "Map"
|
||||||
|
:name "toplevel"
|
||||||
|
:default_width 720
|
||||||
|
:default_height 800
|
||||||
|
|
||||||
|
:on_destroy Gtk.main_quit
|
||||||
|
}))
|
||||||
|
|
||||||
|
(fn osm-widget []
|
||||||
|
(doto (OsmGpsMap.Map {})
|
||||||
|
(tset :map-source OsmGpsMap.MapSource_t.OPENSTREETMAP)
|
||||||
|
(: :set_center_and_zoom 52.595 -0.1 14)
|
||||||
|
(: :layer_add (OsmGpsMap.MapOsd {
|
||||||
|
:show_copyright true
|
||||||
|
; :show_coordinates true
|
||||||
|
:show_scale true
|
||||||
|
}))
|
||||||
|
))
|
||||||
|
|
||||||
|
(fn readout [text]
|
||||||
|
(doto (Gtk.Label {:label text})
|
||||||
|
(-> (: :get_style_context) (: :add_class :readout))))
|
||||||
|
|
||||||
|
(fn readouts []
|
||||||
|
(doto (Gtk.Box
|
||||||
|
{
|
||||||
|
:orientation Gtk.Orientation.VERTICAL
|
||||||
|
:halign Gtk.Align.END
|
||||||
|
})
|
||||||
|
(-> (: :get_style_context) (: :add_class :readouts))
|
||||||
|
(: :add (readout "21:05:00"))
|
||||||
|
(: :add (readout "00:00"))
|
||||||
|
(: :add (readout "25 km/h"))))
|
||||||
|
|
||||||
|
(window:add
|
||||||
|
(doto (Gtk.Overlay {})
|
||||||
|
(: :add (osm-widget))
|
||||||
|
(: :add_overlay (readouts))
|
||||||
|
))
|
||||||
|
|
||||||
|
(window:show_all)
|
||||||
|
(styles)
|
||||||
|
(Gtk:main)
|
|
@ -0,0 +1,9 @@
|
||||||
|
with import <nixpkgs> {};
|
||||||
|
let package = pkgs.callPackage ./. {};
|
||||||
|
in
|
||||||
|
package.overrideAttrs(o: {
|
||||||
|
shellHook = ''
|
||||||
|
export LUA_CPATH=$(lua -e "print(package.cpath)")
|
||||||
|
export LUA_PATH=$(lua -e "print(package.path)")
|
||||||
|
'';
|
||||||
|
})
|
|
@ -0,0 +1,84 @@
|
||||||
|
{
|
||||||
|
stdenv,
|
||||||
|
fetchFromGitLab,
|
||||||
|
libxslt,
|
||||||
|
bash, # shebangs in share/ModemManager/fcc-unlock.available.d/,
|
||||||
|
bash-completion,
|
||||||
|
dbus,
|
||||||
|
gettext,
|
||||||
|
glib,
|
||||||
|
libgudev,
|
||||||
|
libqmi,
|
||||||
|
meson,
|
||||||
|
ninja,
|
||||||
|
cmake,
|
||||||
|
pkg-config,
|
||||||
|
python3,
|
||||||
|
systemd,
|
||||||
|
gobject-introspection,
|
||||||
|
pkgsBuildBuild,
|
||||||
|
buildPackages
|
||||||
|
}: stdenv.mkDerivation rec {
|
||||||
|
pname = "modemmanager";
|
||||||
|
version = "1.22.0";
|
||||||
|
|
||||||
|
src = fetchFromGitLab {
|
||||||
|
domain = "gitlab.freedesktop.org";
|
||||||
|
owner = "mobile-broadband";
|
||||||
|
repo = "ModemManager";
|
||||||
|
rev = version;
|
||||||
|
hash = "sha256-/D9b2rCCUhpDCUfSNAWR65+3EyUywzFdH1R17eSKRDo=";
|
||||||
|
};
|
||||||
|
patches = [
|
||||||
|
/home/dan/src/nixpkgs/pkgs/tools/networking/modemmanager/no-dummy-dirs-in-sysconfdir.patch
|
||||||
|
];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
meson
|
||||||
|
ninja
|
||||||
|
gobject-introspection
|
||||||
|
gettext
|
||||||
|
pkg-config
|
||||||
|
libxslt
|
||||||
|
python3
|
||||||
|
cmake
|
||||||
|
glib # for gdbus-codegen
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
glib
|
||||||
|
libgudev
|
||||||
|
# polkit
|
||||||
|
pkg-config
|
||||||
|
# ppp
|
||||||
|
# libmbim
|
||||||
|
libqmi
|
||||||
|
systemd
|
||||||
|
bash-completion
|
||||||
|
dbus
|
||||||
|
# cmake
|
||||||
|
bash # shebangs in share/ModemManager/fcc-unlock.available.d/
|
||||||
|
];
|
||||||
|
|
||||||
|
depsBuildBuild = [
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
mesonFlags = [
|
||||||
|
"-Dudevdir=${placeholder "out"}/lib/udev"
|
||||||
|
"-Ddbus_policy_dir=${placeholder "out"}/share/dbus-1/system.d"
|
||||||
|
"--sysconfdir=/etc"
|
||||||
|
"--localstatedir=/var"
|
||||||
|
"-Dvapi=false"
|
||||||
|
"-Dmbim=false"
|
||||||
|
"-Dqmi=true"
|
||||||
|
"-Dqrtr=false"
|
||||||
|
"-Dpolkit=no"
|
||||||
|
"-Dplugin_foxconn=disabled"
|
||||||
|
"-Dplugin_quectel=disabled"
|
||||||
|
"-Dman=false"
|
||||||
|
"-Dexamples=false"
|
||||||
|
"-Dtests=false"
|
||||||
|
# "-Dintrospection=false"
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
FENNEL?=fennel
|
||||||
|
PREFIX?=/usr/local
|
||||||
|
|
||||||
|
MODULES=main.fnl
|
||||||
|
|
||||||
|
%.lua : %.fnl
|
||||||
|
$(FENNEL) --compile $< > $@
|
||||||
|
|
||||||
|
saturn: $(patsubst %.fnl,%.lua,$(MODULES)) Makefile
|
||||||
|
(echo -e "#!/usr/bin/env lua\n" ; cat main.lua ) > $@
|
||||||
|
chmod +x $@
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(PREFIX)/bin
|
||||||
|
cp saturn $(PREFIX)/bin
|
|
@ -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
|
|
@ -0,0 +1,99 @@
|
||||||
|
{ stdenv
|
||||||
|
, pkg-config
|
||||||
|
, buildPackages
|
||||||
|
, callPackage
|
||||||
|
, fennel
|
||||||
|
, fetchFromGitHub
|
||||||
|
, fetchurl
|
||||||
|
, gdk-pixbuf
|
||||||
|
, glib
|
||||||
|
, gobject-introspection
|
||||||
|
, gtk3
|
||||||
|
, harfbuzz
|
||||||
|
, lib
|
||||||
|
, librsvg
|
||||||
|
, lua53Packages
|
||||||
|
, lua5_3
|
||||||
|
, makeWrapper
|
||||||
|
, pango
|
||||||
|
, wrapGAppsHook3
|
||||||
|
, writeText
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
luaPackages = lua53Packages;
|
||||||
|
lgi = luaPackages.buildLuaPackage {
|
||||||
|
pname = "lgi";
|
||||||
|
version = "0.9.2-2";
|
||||||
|
buildInputs = [ gobject-introspection ];
|
||||||
|
nativeBuildInputs = [ pkg-config ];
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "lgi-devs";
|
||||||
|
repo = "lgi";
|
||||||
|
rev = "e06ad94c8a1c84e3cdb80cee293450a280dfcbc7";
|
||||||
|
hash = "sha256-VYr/DV1FAyzPe6p6Quc1nmsHup23IAMfz532rL167Q4=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
luaDbusProxy = callPackage ./lua-dbus-proxy.nix {
|
||||||
|
inherit (luaPackages) buildLuaPackage;
|
||||||
|
inherit lgi;
|
||||||
|
lua = lua5_3;
|
||||||
|
};
|
||||||
|
inifile = luaPackages.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 {
|
||||||
|
pname = "saturn";
|
||||||
|
version = "0.4.9"; # nearly Saturn 0.5
|
||||||
|
src =./.;
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
lua
|
||||||
|
gtk3.dev
|
||||||
|
gobject-introspection # .dev
|
||||||
|
gdk-pixbuf
|
||||||
|
glib
|
||||||
|
];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
buildPackages.lua
|
||||||
|
gobject-introspection
|
||||||
|
makeWrapper
|
||||||
|
fennel
|
||||||
|
wrapGAppsHook3
|
||||||
|
];
|
||||||
|
|
||||||
|
makeFlags = [ "PREFIX=${placeholder "out"}" ];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/share/dbus-1/services
|
||||||
|
|
||||||
|
cat <<SERVICE > $out/share/dbus-1/services/net.telent.saturn.service
|
||||||
|
[D-BUS Service]
|
||||||
|
Name=net.telent.saturn
|
||||||
|
Exec=$out/bin/saturn
|
||||||
|
SERVICE
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{ lua, lgi, pkg-config, buildLuaPackage, fetchFromGitHub }:
|
||||||
|
let
|
||||||
|
simpleName = "dbus_proxy";
|
||||||
|
in buildLuaPackage rec {
|
||||||
|
version = "0.10.2";
|
||||||
|
pname = simpleName;
|
||||||
|
nativeBuildInputs = [ pkg-config ];
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "stefano-m";
|
||||||
|
repo = "lua-${simpleName}";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "0kl8ff1g1kpmslzzf53cbzfl1bmb5cb91w431hbz0z0vdrramh6l";
|
||||||
|
};
|
||||||
|
|
||||||
|
propagatedBuildInputs = [ lgi ];
|
||||||
|
|
||||||
|
buildPhase = ":";
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p "$out/share/lua/${lua.luaversion}"
|
||||||
|
cp -r src/${pname} "$out/share/lua/${lua.luaversion}/"
|
||||||
|
'';
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,301 @@
|
||||||
|
(local {: Gio
|
||||||
|
: GLib
|
||||||
|
: GObject
|
||||||
|
: Gtk
|
||||||
|
: GdkPixbuf
|
||||||
|
: Gdk
|
||||||
|
: Pango}
|
||||||
|
(require :lgi))
|
||||||
|
|
||||||
|
(local {: List
|
||||||
|
: stringx
|
||||||
|
: tablex
|
||||||
|
}
|
||||||
|
((require :pl.import_into)))
|
||||||
|
|
||||||
|
(local dbus (require :dbus_proxy))
|
||||||
|
(local inspect (require :inspect))
|
||||||
|
(local lfs (require :lfs))
|
||||||
|
(local inifile (require :inifile))
|
||||||
|
(local posix (require :posix))
|
||||||
|
|
||||||
|
(local ICON_SIZE 64)
|
||||||
|
|
||||||
|
(local CSS "
|
||||||
|
* {
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
text-shadow:
|
||||||
|
0px 1px rgba(0, 0, 0, 255)
|
||||||
|
, 1px 0px rgba(0, 0, 0, 255)
|
||||||
|
, 0px -1px rgba(0, 0, 0, 255)
|
||||||
|
, -1px 0px rgba(0, 0, 0, 255)
|
||||||
|
, 1px 1px rgba(0, 0, 0, 255)
|
||||||
|
, 1px -1px rgba(0, 0, 0, 255)
|
||||||
|
, -1px 1px rgba(0, 0, 0, 255)
|
||||||
|
, -1px -1px rgba(0, 0, 0, 255)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
button.appbutton {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
#toplevel {
|
||||||
|
background-color: rgba(0.2, 0.2, 0.4, 1.0);
|
||||||
|
}
|
||||||
|
")
|
||||||
|
|
||||||
|
(local dbus-service-attrs
|
||||||
|
{
|
||||||
|
:bus dbus.Bus.SESSION
|
||||||
|
:name "net.telent.saturn"
|
||||||
|
:interface "net.telent.saturn"
|
||||||
|
:path "/net/telent/saturn"
|
||||||
|
})
|
||||||
|
|
||||||
|
(local bus (dbus.Proxy:new
|
||||||
|
{
|
||||||
|
:bus dbus.Bus.SESSION
|
||||||
|
:name "org.freedesktop.DBus"
|
||||||
|
:interface "org.freedesktop.DBus"
|
||||||
|
:path "/org/freedesktop/DBus"
|
||||||
|
}))
|
||||||
|
|
||||||
|
(local interface-info
|
||||||
|
(let [xml
|
||||||
|
"<node>
|
||||||
|
<interface name='net.telent.saturn'>
|
||||||
|
<method name='SetVisible'>
|
||||||
|
<arg type='b' name='visible' direction='in'/>
|
||||||
|
<doc:doc><doc:description>
|
||||||
|
Switch visibility of launcher window
|
||||||
|
</doc:description></doc:doc>
|
||||||
|
</method>
|
||||||
|
<method name='ToggleVisible'>
|
||||||
|
<doc:doc><doc:description>
|
||||||
|
Toggle launcher window visible/invisible
|
||||||
|
</doc:description></doc:doc>
|
||||||
|
</method>
|
||||||
|
<property name='Visible' type='b' access='read'>
|
||||||
|
</property>
|
||||||
|
</interface>
|
||||||
|
</node>"
|
||||||
|
node-info (Gio.DBusNodeInfo.new_for_xml xml)]
|
||||||
|
(. node-info.interfaces 1)))
|
||||||
|
|
||||||
|
;; these values don't seem to be available through introspection
|
||||||
|
(local DBUS_NAME_FLAG_DO_NOT_QUEUE 4)
|
||||||
|
(local DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1)
|
||||||
|
(local DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2)
|
||||||
|
(local DBUS_REQUEST_NAME_REPLY_EXISTS 3)
|
||||||
|
(local DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4)
|
||||||
|
|
||||||
|
(let [ret (bus:RequestName dbus-service-attrs.name
|
||||||
|
DBUS_NAME_FLAG_DO_NOT_QUEUE)]
|
||||||
|
(match ret
|
||||||
|
DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
|
||||||
|
true
|
||||||
|
|
||||||
|
DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER
|
||||||
|
true
|
||||||
|
|
||||||
|
DBUS_REQUEST_NAME_REPLY_IN_QUEUE
|
||||||
|
(error "unexpected DBUS_REQUEST_NAME_REPLY_IN_QUEUE")
|
||||||
|
|
||||||
|
DBUS_REQUEST_NAME_REPLY_EXISTS
|
||||||
|
;; Show the currently running instance
|
||||||
|
(let [saturn (dbus.Proxy:new dbus-service-attrs)]
|
||||||
|
(saturn:SetVisible true)
|
||||||
|
(os.exit 0))))
|
||||||
|
|
||||||
|
|
||||||
|
(local path {
|
||||||
|
:absolute? (fn [str] (= (str:sub 1 1) "/"))
|
||||||
|
:concat (fn [...] (table.concat [...] "/"))
|
||||||
|
})
|
||||||
|
(local search-path {
|
||||||
|
:concat (fn [...] (table.concat [...] ":"))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
(local icon-theme (Gtk.IconTheme.get_default))
|
||||||
|
|
||||||
|
;; Use the declared CSS for this app
|
||||||
|
(let [style_provider (Gtk.CssProvider)]
|
||||||
|
(style_provider:load_from_data CSS)
|
||||||
|
(Gtk.StyleContext.add_provider_for_screen
|
||||||
|
(Gdk.Screen.get_default)
|
||||||
|
style_provider
|
||||||
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||||
|
))
|
||||||
|
|
||||||
|
(local window (Gtk.Window {
|
||||||
|
:title "Saturn"
|
||||||
|
:name "toplevel"
|
||||||
|
:default_width 720
|
||||||
|
:default_height 800
|
||||||
|
:on_destroy Gtk.main_quit
|
||||||
|
}))
|
||||||
|
|
||||||
|
;; Using RGBA visual for semi-transparent backgrounds
|
||||||
|
;; Requires compositing (e.g. a compositor on X11)
|
||||||
|
(let [screen (window:get_screen)
|
||||||
|
visual (screen:get_rgba_visual)]
|
||||||
|
(window:set_visual visual))
|
||||||
|
|
||||||
|
(fn find-icon [name]
|
||||||
|
(var found false)
|
||||||
|
(if (path.absolute? name)
|
||||||
|
;; From a direct path
|
||||||
|
(set found (GdkPixbuf.Pixbuf.new_from_file_at_size name ICON_SIZE ICON_SIZE))
|
||||||
|
;; From icon theme
|
||||||
|
(let [sizes (icon-theme:get_icon_sizes name)]
|
||||||
|
;; Uses a list of "safe fallback" values
|
||||||
|
;; Try the desired size first
|
||||||
|
(each [_ res (pairs [ICON_SIZE 128 64 48]) :until found]
|
||||||
|
(set found
|
||||||
|
(-?> (icon-theme:load_icon
|
||||||
|
name res
|
||||||
|
(+ Gtk.IconLookupFlags.FORCE_SVG Gtk.IconLookupFlags.USE_BUILTIN))
|
||||||
|
(: :scale_simple ICON_SIZE ICON_SIZE GdkPixbuf.InterpType.BILINEAR))))
|
||||||
|
))
|
||||||
|
(Gtk.Image.new_from_pixbuf found))
|
||||||
|
|
||||||
|
(fn read-desktop-file [f]
|
||||||
|
(let [parsed (inifile.parse f)
|
||||||
|
vals (. parsed "Desktop Entry")]
|
||||||
|
(tset vals "IconImage"
|
||||||
|
(find-icon (or vals.Icon "application-x-executable")))
|
||||||
|
(tset vals "ID" (f:sub 0 -9))
|
||||||
|
vals))
|
||||||
|
|
||||||
|
(fn current-user-home []
|
||||||
|
"Returns current user's home directory."
|
||||||
|
(-> (posix.unistd.getuid)
|
||||||
|
(posix.pwd.getpwuid)
|
||||||
|
(. :pw_dir)))
|
||||||
|
|
||||||
|
(fn xdg-data-home []
|
||||||
|
"Provides XDG_DATA_HOME or its default fallback value"
|
||||||
|
(or (os.getenv "XDG_DATA_HOME")
|
||||||
|
(path.concat (current-user-home) ".local/share/")))
|
||||||
|
|
||||||
|
(fn xdg-data-dirs []
|
||||||
|
"Provides all data-dirs as a List. Most important first."
|
||||||
|
;; Expected to be used with gmatch as a generator.
|
||||||
|
(let [dirs (List)]
|
||||||
|
(dirs:append (xdg-data-home))
|
||||||
|
(dirs:extend (stringx.split (os.getenv "XDG_DATA_DIRS") ":"))
|
||||||
|
dirs
|
||||||
|
))
|
||||||
|
|
||||||
|
(fn all-apps []
|
||||||
|
;; Each desktop entry representing an application is identified
|
||||||
|
;; by its desktop file ID, which is based on its filename.
|
||||||
|
;; — https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id
|
||||||
|
"Provides apps in a List, sorted by name"
|
||||||
|
(var apps-table {})
|
||||||
|
;; Reversing the data dirs gives priority to the first elements.
|
||||||
|
;; This means conflicting `.desktop` files (or: desktop file ID) are given
|
||||||
|
;; priority to the first elements by "simply" reading it last.
|
||||||
|
(each [path (List.iter (List.reverse (xdg-data-dirs)))]
|
||||||
|
(let [apps-dir (.. path "/applications/")]
|
||||||
|
(when (lfs.attributes apps-dir)
|
||||||
|
(each [f (lfs.dir apps-dir)]
|
||||||
|
(when (= (f:sub -8) ".desktop")
|
||||||
|
(let [attrs (read-desktop-file (.. apps-dir f))]
|
||||||
|
(when (not attrs.NoDisplay)
|
||||||
|
(tset apps-table attrs.ID attrs))))))))
|
||||||
|
;; We have a table indexed by IDs, we don't care about the indexing.
|
||||||
|
;; Make a List and sort it by name.
|
||||||
|
(List.sort (List (tablex.values apps-table))
|
||||||
|
(fn [a b] (< (string.upper a.Name) (string.upper b.Name)))))
|
||||||
|
|
||||||
|
;; Exec entries in desktop files may contain %u %f and other characters
|
||||||
|
;; in which the launcher is supposed to interpolate filenames/urls etc.
|
||||||
|
;; We don't afford the user any way to pick filenames, but we do need
|
||||||
|
;; to remove the placeholders.
|
||||||
|
(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 fork" nil))
|
||||||
|
(do
|
||||||
|
(for [f 3 255] (posix.unistd.close f))
|
||||||
|
(posix.execp "/usr/bin/env" vec)))))
|
||||||
|
|
||||||
|
(fn launch [app]
|
||||||
|
;; FIXME check app.DBusActivatable and do DBus launch if true
|
||||||
|
(let [cmd (parse-percents app.Exec)]
|
||||||
|
(if app.Terminal
|
||||||
|
(spawn-async ["kitty" cmd])
|
||||||
|
(spawn-async ["sh" "-c" cmd]))
|
||||||
|
; (window:hide)
|
||||||
|
))
|
||||||
|
|
||||||
|
(fn button-for [app]
|
||||||
|
(doto (Gtk.Button
|
||||||
|
{
|
||||||
|
:image-position Gtk.PositionType.TOP
|
||||||
|
:relief Gtk.ReliefStyle.NONE
|
||||||
|
:on_clicked #(launch app)
|
||||||
|
})
|
||||||
|
(-> (: :get_style_context) (: :add_class "appbutton"))
|
||||||
|
(: :add
|
||||||
|
(doto (Gtk.Box {:orientation Gtk.Orientation.VERTICAL})
|
||||||
|
(: :pack_start app.IconImage false false 0)
|
||||||
|
(: :pack_start
|
||||||
|
(doto
|
||||||
|
(Gtk.Label {
|
||||||
|
;; https://stackoverflow.com/questions/27462926/how-to-set-max-width-of-gtklabel-properly
|
||||||
|
:label app.Name
|
||||||
|
:justify Gtk.Justification.CENTER
|
||||||
|
:ellipsize Pango.EllipsizeMode.END
|
||||||
|
:hexpand true
|
||||||
|
})
|
||||||
|
(: :set_max_width_chars 1))
|
||||||
|
true true 0)
|
||||||
|
))))
|
||||||
|
|
||||||
|
(fn handle-dbus-method-call [conn sender path interface method params invocation]
|
||||||
|
(when (and (= path dbus-service-attrs.path)
|
||||||
|
(= interface dbus-service-attrs.interface))
|
||||||
|
(match method
|
||||||
|
"SetVisible"
|
||||||
|
(let [[value] (dbus.variant.strip params)]
|
||||||
|
(if value (window:show_all) (window:hide))
|
||||||
|
(invocation:return_value nil))
|
||||||
|
"ToggleVisible"
|
||||||
|
(let [v window.visible]
|
||||||
|
(if v (window:hide) (window:show_all))
|
||||||
|
(invocation:return_value nil)))))
|
||||||
|
|
||||||
|
(fn handle-dbus-get [conn sender path interface name]
|
||||||
|
(when (and (= path dbus-service-attrs.path)
|
||||||
|
(= interface dbus-service-attrs.interface)
|
||||||
|
(= name "Visible"))
|
||||||
|
(GLib.Variant "b" window.visible)))
|
||||||
|
|
||||||
|
(Gio.DBusConnection.register_object
|
||||||
|
bus.connection
|
||||||
|
dbus-service-attrs.path
|
||||||
|
interface-info
|
||||||
|
(GObject.Closure handle-dbus-method-call)
|
||||||
|
(GObject.Closure handle-dbus-get)
|
||||||
|
(GObject.Closure (fn [a] (print "set"))))
|
||||||
|
|
||||||
|
(let [grid (Gtk.FlowBox {
|
||||||
|
:orientation Gtk.Orientation.HORIZONTAL
|
||||||
|
:valign Gtk.Align.START
|
||||||
|
:column_spacing 2
|
||||||
|
:row_spacing 5
|
||||||
|
:homogeneous true
|
||||||
|
})
|
||||||
|
scrolled-window (Gtk.ScrolledWindow {})]
|
||||||
|
(each [app (List.iter (all-apps))]
|
||||||
|
(grid:insert (button-for app) -1))
|
||||||
|
(scrolled-window:add grid)
|
||||||
|
(window:add scrolled-window))
|
||||||
|
|
||||||
|
(window:show_all)
|
||||||
|
(Gtk:main)
|
|
@ -0,0 +1,7 @@
|
||||||
|
with import <nixpkgs> { overlays = [ (import ../../overlay.nix) ]; } ;
|
||||||
|
(callPackage ./. {
|
||||||
|
}).overrideAttrs(o: {
|
||||||
|
GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache";
|
||||||
|
nativeBuildInputs = o.nativeBuildInputs ++
|
||||||
|
[ ] ;
|
||||||
|
})
|
Loading…
Reference in New Issue