Compare commits
276 Commits
wip-nix-fa
...
wip-s6-2
Author | SHA1 | Date | |
---|---|---|---|
b129321af9 | |||
a5c36d39f4 | |||
787e6af646 | |||
4fd2db4e51 | |||
ac04dc639f | |||
4a2eb7ebec | |||
b8bf763c11 | |||
b82a31a3ac | |||
c8e5edd61a | |||
1b4a6207e2 | |||
3c43fba878 | |||
7904957544 | |||
b25df1d997 | |||
d08f318e4b | |||
f655c31d77 | |||
288d57e5d5 | |||
f669f2bfe8 | |||
5554ad9fe2 | |||
6595d177be | |||
d194abb4bf | |||
eaf45e2366 | |||
66e04857b6 | |||
fa0dcdc5be | |||
23b87a283a | |||
849ca59f68 | |||
5e1a6062af | |||
8dacb93861 | |||
eafabe87c4 | |||
4510352c07 | |||
430592632c | |||
ac22b36d78 | |||
4439491bf0 | |||
56aca78d84 | |||
546482dc80 | |||
2f07fff084 | |||
294563c655 | |||
f6c3557b8c | |||
7513811111 | |||
eabd113262 | |||
01fa9919fd | |||
56a2c4e49f | |||
bf953fbdb5 | |||
4f2d0f2e56 | |||
500c989e61 | |||
08ee0375cc | |||
afd1a42ec7 | |||
21691fc2fd | |||
c1edf96ce0 | |||
21714849cf | |||
379f3ef9e0 | |||
c07c23a9f8 | |||
f44a4c84ee | |||
6822dad9c0 | |||
9f8e42ef92 | |||
bda374db13 | |||
180a217744 | |||
f13ece2212 | |||
00ab28fcac | |||
bb18f7355a | |||
0905a658ad | |||
90b9d00f37 | |||
40effc08d6 | |||
73a2c9d923 | |||
d93380938d | |||
573a50fedc | |||
f8797a77ff | |||
92115709f6 | |||
e6111c9d5e | |||
975df698a4 | |||
ce8c4a4f6f | |||
df33576090 | |||
4d6eb705eb | |||
fd70b6acbf | |||
1d3576b892 | |||
30d49dc3c3 | |||
8e0031e770 | |||
7a50fcf566 | |||
c453dbac8e | |||
053b8cf737 | |||
8af962c3a6 | |||
9ea39799a5 | |||
e695459b40 | |||
f2e760710d | |||
dc70ed8bd8 | |||
b41c249830 | |||
8f986e4616 | |||
2b73ebb4c1 | |||
bffcaa668e | |||
ebb037bd48 | |||
df98ef30e0 | |||
e45d4d6ae7 | |||
f3568b3ffc | |||
9eaf4d71b2 | |||
3200188a32 | |||
a4ab60b836 | |||
3282b40e9b | |||
39411164af | |||
c0a94995a5 | |||
f4b5d3a70a | |||
07373b5e6b | |||
7281b94e23 | |||
0e83742096 | |||
7d8205352c | |||
c4994162e1 | |||
24a211bd3d | |||
3cf651b212 | |||
cb1c76a0db | |||
27c12edec0 | |||
b41320ffb3 | |||
ac41cfcd42 | |||
62cbc65f12 | |||
ccb856faf5 | |||
d7f4438371 | |||
f44c3f2e1f | |||
bb300a4eb5 | |||
fd4842ab5b | |||
1cdc3b8bda | |||
531ea11b3d | |||
041ce0654e | |||
526a02bb73 | |||
1d0458ab10 | |||
4358f9471e | |||
cb3a1fb3fe | |||
72d52f9239 | |||
219fe67f34 | |||
b36d224b85 | |||
90e3c33536 | |||
a9419b7351 | |||
f0d0343b32 | |||
bd27f3a015 | |||
6a3e632335 | |||
a4c4b0575c | |||
4730a65008 | |||
63d95edcbe | |||
687e72897b | |||
0e84744115 | |||
1ee38d3aec | |||
5f4e421ab9 | |||
471339d237 | |||
085232f18c | |||
18c7fc17fd | |||
a7567dfbe6 | |||
bc0660b623 | |||
cf86b4a67c | |||
d39bed46b5 | |||
525450e21a | |||
a4ee820921 | |||
4b5d6b16e1 | |||
41a141dba6 | |||
d5811f142d | |||
4d6d79cc81 | |||
53d76920e4 | |||
db892273ac | |||
65e206afde | |||
6765fe8d7d | |||
955119e07b | |||
daddf9314a | |||
e59123fd62 | |||
d43cc6c61c | |||
a8bc77d40c | |||
dfc768e2e6 | |||
3544b4b132 | |||
c86afca795 | |||
5f3ef37050 | |||
3b8252fe43 | |||
1e6e4d2644 | |||
60c447b6c4 | |||
4fc2ffef56 | |||
9416ef1ff6 | |||
b1dff9bfa8 | |||
0003acc091 | |||
0630037f86 | |||
9513680538 | |||
0affeb098a | |||
979d07d693 | |||
fd072883dc | |||
ed87792f9b | |||
8821b3ca7d | |||
5e5a1fbaae | |||
d2f470dc74 | |||
7933ef41a2 | |||
6b45589e54 | |||
b04357c9de | |||
4b04cbc078 | |||
1498e364b2 | |||
0aaa3eaaeb | |||
3ac6b92c18 | |||
c747855810 | |||
711865018d | |||
f33fcc2018 | |||
96ec0106ee | |||
0c4d7761d3 | |||
fe10640821 | |||
1f208083be | |||
6ec3126321 | |||
8029744c90 | |||
1fcf0bfcb1 | |||
a3ae650273 | |||
7e0bef549f | |||
3b603519ff | |||
f69ca166f4 | |||
a45e42910d | |||
3dd1d18dcd | |||
28cb705bd4 | |||
7fa1dbc5d5 | |||
8b7575c205 | |||
52e9902fa1 | |||
ab765a81af | |||
a7bd831ad8 | |||
063d99dd73 | |||
0d48c462cb | |||
f4ec09f010 | |||
a7ef9fc0b8 | |||
a40cefc8a5 | |||
f55bb3518f | |||
3d16aa62ea | |||
2548cfeadc | |||
90acbf716d | |||
4d98593b3f | |||
db89ac88f0 | |||
bba149c670 | |||
c056984003 | |||
2324d75165 | |||
9296b7731b | |||
75e9ce509e | |||
95c95d6f53 | |||
fca23e661a | |||
9a7ebbd9d3 | |||
56b00d998e | |||
01ef182073 | |||
b6daeddfa2 | |||
c6e956f3d2 | |||
f9510e5d24 | |||
2e737c2ab1 | |||
82368eb45a | |||
65fb9e1d57 | |||
b02ae7ef74 | |||
37ddb2ae17 | |||
81e02e2885 | |||
4a3f59468c | |||
daab5939e7 | |||
e7430c41f9 | |||
5849e75577 | |||
296123651c | |||
7f0d5e7810 | |||
7af928a6d2 | |||
b73569d675 | |||
50ee15ef2b | |||
9764d5f095 | |||
43386f3ba5 | |||
a3a6278a59 | |||
083f743c1f | |||
626ad97005 | |||
6253d1799a | |||
d8a8038cae | |||
7fd56b63cb | |||
7a65bd36c7 | |||
bd4eeeeb3b | |||
7c22b59b9d | |||
9e504676bd | |||
b515127101 | |||
40e30cf2f8 | |||
812c0c8029 | |||
7ca5ae84b7 | |||
a4248fd5cc | |||
70229e0839 | |||
cd303a76bc | |||
e43aa3bb8b | |||
6c2d80715c | |||
db8456f152 | |||
d912190db5 | |||
c380f61bea | |||
ff8cfc9372 | |||
b302113fc0 | |||
9749ff0442 | |||
0d97191f74 |
@@ -15,8 +15,9 @@ the only hard dependency for my exported pkgs/modules should be [nixpkgs][nixpkg
|
||||
building [hosts/](./hosts/) will require [sops][sops].
|
||||
|
||||
you might specifically be interested in these files (elaborated further in #key-points-of-interest):
|
||||
- [`sxmo-utils`](./pkgs/additional/sxmo-utils/default.nix)
|
||||
- [example SXMO deployment](./hosts/modules/gui/sxmo/default.nix)
|
||||
- ~~[`sxmo-utils`](./pkgs/additional/sxmo-utils/default.nix)~~
|
||||
- ~~[example SXMO deployment](./hosts/modules/gui/sxmo/default.nix)~~
|
||||
- these files will remain until my config settles down, but i no longer use or maintain SXMO.
|
||||
- [my implementation of impermanence](./modules/persist/default.nix)
|
||||
- my way of deploying dotfiles/configuring programs per-user:
|
||||
- [modules/fs/](./modules/fs/default.nix)
|
||||
|
15
TODO.md
15
TODO.md
@@ -11,16 +11,15 @@
|
||||
### sops/secrets
|
||||
- rework secrets to leverage `sane.fs`
|
||||
- remove sops activation script as it's covered by my systemd sane.fs impl
|
||||
- user secrets could just use `gocryptfs`, like with ~/private?
|
||||
- can gocryptfs support nested filesystems, each with different perms (for desko, moby, etc)?
|
||||
|
||||
### roles
|
||||
- allow any host to take the role of `uninsane.org`
|
||||
- will make it easier to test new services?
|
||||
|
||||
### upstreaming
|
||||
- split out a sxmo module usable by NUR consumers
|
||||
- bump nodejs version in lemmy-ui
|
||||
- add updateScripts to all my packages in nixpkgs
|
||||
- fix lightdm-mobile-greeter for newer libhandy
|
||||
- REVIEW/integrate jellyfin dataDir config: <https://github.com/NixOS/nixpkgs/pull/233617>
|
||||
|
||||
#### upstreaming to non-nixpkgs repos
|
||||
@@ -47,6 +46,8 @@
|
||||
- limit access to `~/knowledge/secrets` through an agent that requires GUI approval, so a firefox exploit can't steal all my logins
|
||||
- port sane-sandboxed to a compiled language (hare?)
|
||||
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
||||
- remove /run/wrappers from the sandbox path
|
||||
- they're mostly useless when using no-new-privs, just an opportunity to forget to specify deps
|
||||
- make dconf stuff less monolithic
|
||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||
- canaries for important services
|
||||
@@ -54,6 +55,11 @@
|
||||
- integrate `nix check` into Gitea actions?
|
||||
|
||||
### user experience
|
||||
- xdg-desktop-portal shouldn't kill children on exit
|
||||
- *maybe* a job for `setsid -f`?
|
||||
- replace starship prompt with something more efficient
|
||||
- watch `forkstat`: it does way too much
|
||||
- cleanup waybar so that it's not invoking playerctl every 2 seconds
|
||||
- install apps:
|
||||
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
||||
- shopping list (not in nixpkgs): <https://linuxphoneapps.org/apps/ro.hume.cosmin.shoppinglist/>
|
||||
@@ -76,6 +82,7 @@
|
||||
|
||||
#### moby
|
||||
- fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html>
|
||||
- moby: tune keyboard layout
|
||||
- SwayNC:
|
||||
- don't show MPRIS if no players detected
|
||||
- this is a problem of playerctld, i guess
|
||||
@@ -97,6 +104,7 @@
|
||||
- RSS: integrate a paywall bypass
|
||||
- e.g. self-hosted [ladder](https://github.com/everywall/ladder) (like 12ft.io)
|
||||
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
|
||||
- neovim: integrate LLMs
|
||||
- Helix: make copy-to-system clipboard be the default
|
||||
- firefox/librewolf: persist history
|
||||
- just not cookies or tabs
|
||||
@@ -114,7 +122,6 @@
|
||||
|
||||
### perf
|
||||
- debug nixos-rebuild times
|
||||
- i bet sane.programs adds a LOT of time, with how it automatically creates an attrs for EVERY package in nixpkgs.
|
||||
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
|
||||
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
|
||||
- would be super handy for package prototyping!
|
||||
|
199
flake.lock
generated
199
flake.lock
generated
@@ -1,15 +1,34 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"locked": {
|
||||
"lastModified": 1688025799,
|
||||
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "flake-compat",
|
||||
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
"nixpkgs-lib": [
|
||||
"nixpkgs-wayland",
|
||||
"nix-eval-jobs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1698882062,
|
||||
"narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=",
|
||||
"lastModified": 1701473968,
|
||||
"narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "8c9fa2545007b49a5db5f650ae91f227672c3877",
|
||||
"rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,6 +37,43 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lib-aggregate": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710184940,
|
||||
"narHash": "sha256-FzYm4td3FJfzOAuEkCXt3KdUgZuA072OAQXqIq+IAMo=",
|
||||
"owner": "nix-community",
|
||||
"repo": "lib-aggregate",
|
||||
"rev": "45b75bf534592c0c1c881a1c447f7fdb37a87eaf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "lib-aggregate",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mobile-nixos": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@@ -35,33 +91,56 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-fast-build": {
|
||||
"nix-eval-jobs": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1703607026,
|
||||
"narHash": "sha256-Emh0BPoqlS4ntp2UJrwydXfIP4qIMF0VBB2FUE3/M/E=",
|
||||
"owner": "Mic92",
|
||||
"repo": "nix-fast-build",
|
||||
"rev": "4376b8a33b217ee2f78ba3dcff01a3e464d13a46",
|
||||
"lastModified": 1705242886,
|
||||
"narHash": "sha256-TLj334vRwFtSym3m+NnKcNCnKKPNoTC/TDZL40vmOso=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-eval-jobs",
|
||||
"rev": "6b03a93296faf174b97546fd573c8b379f523a8d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Mic92",
|
||||
"repo": "nix-fast-build",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-eval-jobs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-wayland",
|
||||
"nix-eval-jobs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701208414,
|
||||
"narHash": "sha256-xrQ0FyhwTZK6BwKhahIkUVZhMNk21IEI1nUcWSONtpo=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "93e39cc1a087d65bcf7a132e75a650c44dd2b734",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1698890957,
|
||||
"narHash": "sha256-DJ+SppjpPBoJr0Aro9TAcP3sxApCSieY6BYBCoWGUX8=",
|
||||
"lastModified": 1703134684,
|
||||
"narHash": "sha256-SQmng1EnBFLzS7WSRyPM9HgmZP2kLJcPAz+Ug/nug6o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c082856b850ec60cda9f0a0db2bc7bd8900d708c",
|
||||
"rev": "d6863cbcbbb80e71cecfc03356db1cda38919523",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -73,29 +152,26 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"dir": "lib",
|
||||
"lastModified": 1698611440,
|
||||
"narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
|
||||
"lastModified": 1710031547,
|
||||
"narHash": "sha256-pkUg3hOKuGWMGF9WEMPPN/G4pqqdbNGJQ54yhyQYDVY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "630ebdc047ca96d8126e16bb664c7730dc52f6e6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "lib",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-next-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1708992120,
|
||||
"narHash": "sha256-t/8QV+lEroW5fK44w5oEUalIM0eYYVGs833AHDCIl4s=",
|
||||
"lastModified": 1710337169,
|
||||
"narHash": "sha256-u2/74bhQuWykUZDWUIhHd6IpZiaQ0hSpTBbx0y9opkE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6daf4de0662e1d895d220a4a4ddb356eb000abe9",
|
||||
"rev": "4ee0840ba2ecc50458ab1677d108afcd691f4815",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -107,11 +183,11 @@
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1708819810,
|
||||
"narHash": "sha256-1KosU+ZFXf31GPeCBNxobZWMgHsSOJcrSFA6F2jhzdE=",
|
||||
"lastModified": 1710033658,
|
||||
"narHash": "sha256-yiZiVKP5Ya813iYLho2+CcFuuHpaqKc/CoxOlANKcqM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "89a2a12e6c8c6a56c72eb3589982c8e2f89c70ea",
|
||||
"rev": "b17375d3bb7c79ffc52f3538028b2ec06eb79ef8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -123,11 +199,11 @@
|
||||
},
|
||||
"nixpkgs-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1708995544,
|
||||
"narHash": "sha256-YJgLopKOKVTggnKzjX4OiAS22hx/vNv397DcsAyTZgY=",
|
||||
"lastModified": 1710339354,
|
||||
"narHash": "sha256-+P5ccUPiLouHexb8aJrUOVOIja9qm+fG57pgAu7uIRs=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5bd8df40204f47a12263f3614c72cd5b6832a9a0",
|
||||
"rev": "2dbc8f62d8af7a1ab962e4b20d12b25ddcb86ced",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -137,12 +213,35 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-wayland": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"lib-aggregate": "lib-aggregate",
|
||||
"nix-eval-jobs": "nix-eval-jobs",
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unpatched"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710317949,
|
||||
"narHash": "sha256-bwReMiWPA2wYBvKEMhO8pJcu+o+7ocy5hGkSoawTHu0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs-wayland",
|
||||
"rev": "771cb198c281db6918829651f194bf4db32e342d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs-wayland",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"mobile-nixos": "mobile-nixos",
|
||||
"nix-fast-build": "nix-fast-build",
|
||||
"nixpkgs-next-unpatched": "nixpkgs-next-unpatched",
|
||||
"nixpkgs-unpatched": "nixpkgs-unpatched",
|
||||
"nixpkgs-wayland": "nixpkgs-wayland",
|
||||
"sops-nix": "sops-nix",
|
||||
"uninsane-dot-org": "uninsane-dot-org"
|
||||
}
|
||||
@@ -155,11 +254,11 @@
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708987867,
|
||||
"narHash": "sha256-k2lDaDWNTU5sBVHanYzjDKVDmk29RHIgdbbXu5sdzBA=",
|
||||
"lastModified": 1710195194,
|
||||
"narHash": "sha256-KFxCJp0T6TJOz1IOKlpRdpsCr9xsvlVuWY/VCiAFnTE=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "a1c8de14f60924fafe13aea66b46157f0150f4cf",
|
||||
"rev": "e52d8117b330f690382f1d16d81ae43daeb4b880",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -168,19 +267,35 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nix-fast-build",
|
||||
"nixpkgs-wayland",
|
||||
"nix-eval-jobs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1698438538,
|
||||
"narHash": "sha256-AWxaKTDL3MtxaVTVU5lYBvSnlspOS0Fjt8GxBgnU0Do=",
|
||||
"lastModified": 1702979157,
|
||||
"narHash": "sha256-RnFBbLbpqtn4AoJGXKevQMCGhra4h6G2MPcuTSZZQ+g=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "5deb8dc125a9f83b65ca86cf0c8167c46593e0b1",
|
||||
"rev": "2961375283668d867e64129c22af532de8e77734",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
85
flake.nix
85
flake.nix
@@ -48,6 +48,11 @@
|
||||
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging-next";
|
||||
nixpkgs-next-unpatched.url = "github:nixos/nixpkgs?ref=staging-next";
|
||||
|
||||
nixpkgs-wayland = {
|
||||
url = "github:nix-community/nixpkgs-wayland";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||
};
|
||||
|
||||
mobile-nixos = {
|
||||
# <https://github.com/nixos/mobile-nixos>
|
||||
# only used for building disk images, not relevant after deployment
|
||||
@@ -57,10 +62,6 @@
|
||||
url = "github:nixos/mobile-nixos?ref=d25d3b87e7f300d8066e31d792337d9cd7ecd23b";
|
||||
flake = false;
|
||||
};
|
||||
nix-fast-build = {
|
||||
# https://github.com/Mic92/nix-fast-build
|
||||
url = "github:Mic92/nix-fast-build";
|
||||
};
|
||||
sops-nix = {
|
||||
# <https://github.com/Mic92/sops-nix>
|
||||
# used to distribute secrets to my hosts
|
||||
@@ -80,8 +81,8 @@
|
||||
self,
|
||||
nixpkgs-unpatched,
|
||||
nixpkgs-next-unpatched ? nixpkgs-unpatched,
|
||||
nixpkgs-wayland,
|
||||
mobile-nixos,
|
||||
nix-fast-build,
|
||||
sops-nix,
|
||||
uninsane-dot-org,
|
||||
...
|
||||
@@ -102,30 +103,7 @@
|
||||
patchNixpkgs = variant: nixpkgs: (import ./nixpatches/flake.nix).outputs {
|
||||
inherit variant nixpkgs;
|
||||
self = patchNixpkgs variant nixpkgs;
|
||||
} // {
|
||||
# sourceInfo includes fields (square brackets for the ones which are not always present):
|
||||
# - [dirtyRev]
|
||||
# - [dirtyShortRev]
|
||||
# - lastModified
|
||||
# - lastModifiedDate
|
||||
# - narHash
|
||||
# - outPath
|
||||
# - [rev]
|
||||
# - [revCount]
|
||||
# - [shortRev]
|
||||
# - submodules
|
||||
#
|
||||
# these values are used within nixpkgs:
|
||||
# - to give a friendly name to the nixos system (`readlink /run/current-system` -> `...nixos-system-desko-24.05.20240227.dirty`)
|
||||
# - to alias `import <nixpkgs>` so that nix uses the system's nixpkgs when called externally (supposedly).
|
||||
#
|
||||
# these values seem to exist both within the `sourceInfo` attrset and at the top-level.
|
||||
# for a list of all implicit flake outputs (which is what these seem to be):
|
||||
# $ nix-repl
|
||||
# > lf .
|
||||
# > <tab>
|
||||
inherit (self) sourceInfo;
|
||||
} // self.sourceInfo;
|
||||
};
|
||||
|
||||
nixpkgs' = patchNixpkgs "master" nixpkgs-unpatched;
|
||||
nixpkgsCompiledBy = system: nixpkgs'.legacyPackages."${system}";
|
||||
@@ -212,12 +190,18 @@
|
||||
let
|
||||
mobile = (import "${mobile-nixos}/overlay/overlay.nix");
|
||||
uninsane = uninsane-dot-org.overlays.default;
|
||||
# TODO: why do i have to use `self.inputs.nix-fast-build` instead of just `nix-fast-build` here?
|
||||
nix-fast-build = (_: prev: self.inputs.nix-fast-build.packages."${prev.stdenv.system}" or {});
|
||||
wayland = final: prev: {
|
||||
# default is to dump the packages into `waylandPkgs` *and* the toplevel.
|
||||
# but i just want the `waylandPkgs` set
|
||||
inherit (nixpkgs-wayland.overlays.default final prev)
|
||||
waylandPkgs
|
||||
new-wayland-protocols #< 2024/03/10: nixpkgs-wayland assumes this will be in the toplevel
|
||||
;
|
||||
};
|
||||
in
|
||||
(mobile final prev)
|
||||
// (nix-fast-build final prev)
|
||||
// (uninsane final prev)
|
||||
// (wayland final prev)
|
||||
;
|
||||
};
|
||||
|
||||
@@ -273,6 +257,8 @@
|
||||
pkgs = self.legacyPackages."x86_64-linux";
|
||||
sanePkgs = import ./pkgs { inherit pkgs; };
|
||||
deployScript = host: addr: action: pkgs.writeShellScript "deploy-${host}" ''
|
||||
set -e
|
||||
|
||||
host="${host}"
|
||||
addr="${addr}"
|
||||
action="${if action != null then action else ""}"
|
||||
@@ -286,8 +272,8 @@
|
||||
fi
|
||||
}
|
||||
|
||||
nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --out-link "./result-$host" "$@"
|
||||
storePath="$(readlink ./result-$host)"
|
||||
nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --out-link "./build/result-$host" "$@"
|
||||
storePath="$(readlink ./build/result-$host)"
|
||||
|
||||
# mimic `nixos-rebuild --target-host`, in effect:
|
||||
# - nix-copy-closure ...
|
||||
@@ -390,6 +376,8 @@
|
||||
- or `nix run '.#preDeploy'` to target all hosts
|
||||
- `nix run '.#check'`
|
||||
- make sure all systems build; NUR evaluates
|
||||
- `nix run '.#bench'`
|
||||
- benchmark the eval time of common targets this flake provides
|
||||
|
||||
specific build targets of interest:
|
||||
- `nix build '.#imgs.rescue'`
|
||||
@@ -533,6 +521,7 @@
|
||||
--option allow-import-from-derivation true \
|
||||
--drv-path --show-trace \
|
||||
-I nixpkgs=${nixpkgs-unpatched} \
|
||||
-I nixpkgs-overlays=${./.}/hosts/common/nix/overlay \
|
||||
-I ../../ \
|
||||
| tee # tee to prevent interactive mode
|
||||
'');
|
||||
@@ -544,7 +533,7 @@
|
||||
checkHost = host: let
|
||||
shellHost = pkgs.lib.replaceStrings [ "-" ] [ "_" ] host;
|
||||
in ''
|
||||
nix build -v '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./result-${host} -j2 "$@"
|
||||
nix build -v '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./build/result-${host} -j2 "$@"
|
||||
RC_${shellHost}=$?
|
||||
'';
|
||||
in builtins.toString (pkgs.writeShellScript
|
||||
@@ -593,7 +582,31 @@
|
||||
check.rescue = {
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "check-rescue" ''
|
||||
nix build -v '.#imgs.rescue' --out-link ./result-rescue-img -j2
|
||||
nix build -v '.#imgs.rescue' --out-link ./build/result-rescue-img -j2
|
||||
'');
|
||||
};
|
||||
|
||||
bench = {
|
||||
type = "app";
|
||||
program = builtins.toString (pkgs.writeShellScript "bench" ''
|
||||
doBench() {
|
||||
attrPath="$1"
|
||||
shift
|
||||
echo -n "benchmarking eval of '$attrPath'... "
|
||||
/run/current-system/sw/bin/time -f "%e sec" -o /dev/stdout \
|
||||
nix eval --no-eval-cache --quiet --raw ".#$attrPath" --apply 'result: if result != null then "" else "unexpected null"' $@ 2> /dev/null
|
||||
}
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
doBench "$@"
|
||||
else
|
||||
doBench hostConfigs
|
||||
doBench hostConfigs.lappy
|
||||
doBench hostConfigs.lappy.sane.programs
|
||||
doBench hostConfigs.lappy.sane.users.colin
|
||||
doBench hostConfigs.lappy.sane.fs
|
||||
doBench hostConfigs.lappy.environment.systemPackages
|
||||
fi
|
||||
'');
|
||||
};
|
||||
};
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
./polyfill.nix
|
||||
];
|
||||
|
||||
sane.roles.client = true;
|
||||
|
@@ -1,41 +0,0 @@
|
||||
# doesn't actually *enable* anything,
|
||||
# but sets up any modules such that if they *were* enabled, they'll act as expected.
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.gui.sxmo = {
|
||||
noidle = true; #< power button requires 1s hold, which makes it impractical to be dealing with.
|
||||
settings = {
|
||||
# XXX: make sure the user is part of the `input` group!
|
||||
SXMO_LISGD_INPUT_DEVICE = "/dev/input/by-id/usb-Wacom_Co._Ltd._Pen_and_multitouch_sensor-event-if00";
|
||||
# these identifiers are from `swaymsg -t get_inputs`
|
||||
SXMO_VOLUME_BUTTON = "1:1:AT_Translated_Set_2_keyboard";
|
||||
# SXMO_VOLUME_BUTTON = "none";
|
||||
# N.B.: thinkpad's power button requires a full second press to do anything
|
||||
SXMO_POWER_BUTTON = "0:1:Power_Button";
|
||||
# SXMO_POWER_BUTTON = "none";
|
||||
SXMO_DISABLE_LEDS = "1";
|
||||
SXMO_UNLOCK_IDLE_TIME = "120"; # default
|
||||
# sxmo tries to determine device type from /proc/device-tree/compatible,
|
||||
# but that doesn't seem to exist on NixOS? (or maybe it just doesn't exist
|
||||
# on non-aarch64 builds).
|
||||
# the device type informs (at least):
|
||||
# - SXMO_WIFI_MODULE
|
||||
# - SXMO_RTW_SCAN_INTERVAL
|
||||
# - SXMO_TOUCHSCREEN_ID
|
||||
# - SXMO_MONITOR
|
||||
# - SXMO_ALSA_CONTROL_NAME
|
||||
# - SXMO_SWAY_SCALE
|
||||
# see <repo:mil/sxmo-utils:scripts/deviceprofiles>
|
||||
# SXMO_DEVICE_NAME = "pine64,pinephone-1.2";
|
||||
# if sxmo doesn't know the device, it can't decide whether to use one_button or three_button mode
|
||||
# and so it just wouldn't handle any button inputs (sxmo_hook_inputhandler.sh not on path)
|
||||
SXMO_DEVICE_NAME = "three_button_touchscreen";
|
||||
};
|
||||
package = (pkgs.sxmo-utils.override { preferSystemd = true; }).overrideAttrs (base: {
|
||||
postPatch = (base.postPatch or "") + ''
|
||||
# after volume-button navigation mode, restore full keyboard functionality
|
||||
cp ${./xkb_mobile_normal_buttons} ./configs/xkb/xkb_mobile_normal_buttons
|
||||
'';
|
||||
});
|
||||
};
|
||||
}
|
@@ -36,10 +36,15 @@
|
||||
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
|
||||
sane.gui.sxmo.enable = true;
|
||||
# sane.programs.consoleUtils.enableFor.user.colin = false;
|
||||
# sane.programs.guiApps.enableFor.user.colin = false;
|
||||
# sane.gui.sxmo.enable = true;
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.swaylock.enableFor.user.colin = false; #< not usable on touch
|
||||
sane.programs.schlock.enableFor.user.colin = true;
|
||||
sane.programs.swayidle.config.actions.screenoff.delay = 300;
|
||||
sane.programs.swayidle.config.actions.screenoff.enable = true;
|
||||
sane.programs.sane-input-handler.enableFor.user.colin = true;
|
||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
||||
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
||||
sane.programs.nvme-cli.enableFor.system = false; # does not cross compile (libhugetlbfs)
|
||||
|
||||
@@ -52,7 +57,6 @@
|
||||
# sane.programs.signal-desktop.config.autostart = true; # TODO: enable once electron stops derping.
|
||||
# sane.programs."gnome.geary".config.autostart = true;
|
||||
# sane.programs.calls.config.autostart = true;
|
||||
sane.programs.mpv.config.vo = "wlshm"; #< see hosts/common/programs/mpv.nix for details
|
||||
|
||||
sane.programs.firefox.mime.priority = 300; # prefer other browsers when possible
|
||||
# HACK/TODO: make `programs.P.env.VAR` behave according to `mime.priority`
|
||||
@@ -124,42 +128,12 @@
|
||||
# enable rotation sensor
|
||||
hardware.sensor.iio.enable = true;
|
||||
|
||||
# inject specialized alsa configs via the environment.
|
||||
# specifically, this gets the pinephone headphones & internal earpiece working.
|
||||
# see pkgs/patched/alsa-ucm-conf for more info.
|
||||
environment.variables.ALSA_CONFIG_UCM2 = "/run/current-system/sw/share/alsa/ucm2";
|
||||
environment.pathsToLink = [ "/share/alsa/ucm2" ];
|
||||
environment.systemPackages = [
|
||||
(pkgs.alsa-ucm-conf-sane.override {
|
||||
# internal speaker has a tendency to break :(
|
||||
preferEarpiece = true;
|
||||
})
|
||||
];
|
||||
systemd = let
|
||||
ucm-env = config.environment.variables.ALSA_CONFIG_UCM2;
|
||||
in {
|
||||
# cribbed from <repo:nixos/mobile-nixos:modules/quirks/audio.nix>
|
||||
|
||||
# pipewire
|
||||
user.services.pipewire.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
user.services.pipewire-pulse.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
user.services.wireplumber.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
services.pipewire.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
services.pipewire-pulse.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
services.wireplumber.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
|
||||
# pulseaudio
|
||||
# user.services.pulseaudio.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
# services.pulseaudio.environment.ALSA_CONFIG_UCM2 = ucm-env;
|
||||
|
||||
|
||||
# TODO: move elsewhere...
|
||||
services.ModemManager.serviceConfig = {
|
||||
# N.B.: the extra "" in ExecStart serves to force upstream ExecStart to be ignored
|
||||
ExecStart = [ "" "${pkgs.modemmanager}/bin/ModemManager --debug" ];
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
ExecStartPost = [ "${pkgs.modemmanager}/bin/mmcli --set-logging=INFO" ];
|
||||
};
|
||||
# TODO: move elsewhere...
|
||||
systemd.services.ModemManager.serviceConfig = {
|
||||
# N.B.: the extra "" in ExecStart serves to force upstream ExecStart to be ignored
|
||||
ExecStart = [ "" "${pkgs.modemmanager}/bin/ModemManager --debug" ];
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
ExecStartPost = [ "${pkgs.modemmanager}/bin/mmcli --set-logging=INFO" ];
|
||||
};
|
||||
|
||||
services.udev.extraRules = let
|
||||
|
@@ -85,6 +85,7 @@ in
|
||||
"lima.sched_timeout_ms=2000"
|
||||
];
|
||||
|
||||
services.xserver.displayManager.job.preStart = ensureHWReady;
|
||||
systemd.services.greetd.preStart = ensureHWReady;
|
||||
# services.xserver.displayManager.job.preStart = ensureHWReady;
|
||||
# systemd.services.greetd.preStart = ensureHWReady;
|
||||
systemd.services.unl0kr.preStart = ensureHWReady;
|
||||
}
|
||||
|
@@ -24,73 +24,22 @@
|
||||
backlight = "backlight"; # /sys/class/backlight/*backlight*/brightness
|
||||
};
|
||||
|
||||
sane.gui.sxmo = {
|
||||
nogesture = true;
|
||||
settings = {
|
||||
### hardware: touch screen
|
||||
SXMO_LISGD_INPUT_DEVICE = "/dev/input/by-path/platform-1c2ac00.i2c-event";
|
||||
# vol and power are detected correctly by upstream
|
||||
sane.programs.alacritty.config.fontSize = 9;
|
||||
|
||||
### preferences
|
||||
DEFAULT_COUNTRY = "US";
|
||||
sane.programs.sway.config = {
|
||||
font = "pango:monospace 10";
|
||||
mod = "Mod1"; # prefer Alt
|
||||
workspace_layout = "tabbed";
|
||||
};
|
||||
|
||||
SXMO_AUTOROTATE = "1"; # enable auto-rotation at launch. has no meaning in stock/upstream sxmo-utils
|
||||
|
||||
# BEMENU lines (wayland DMENU):
|
||||
# - camera is 9th entry
|
||||
# - flashlight is 10th entry
|
||||
# - config is 14th entry. inside that:
|
||||
# - autorotate is 11th entry
|
||||
# - system menu is 19th entry
|
||||
# - close is 20th entry
|
||||
# - power is 15th entry
|
||||
# - close is 16th entry
|
||||
SXMO_BEMENU_LANDSCAPE_LINES = "11"; # default 8
|
||||
SXMO_BEMENU_PORTRAIT_LINES = "16"; # default 16
|
||||
SXMO_LOCK_IDLE_TIME = "15"; # how long between screenoff -> lock -> back to screenoff (default: 8)
|
||||
# gravity: how far to tilt the device before the screen rotates
|
||||
# for a given setting, normal <-> invert requires more movement then left <-> right
|
||||
# i.e. the settingd doesn't feel completely symmetric
|
||||
# SXMO_ROTATION_GRAVITY default is 16374
|
||||
# SXMO_ROTATION_GRAVITY = "12800"; # uncomfortably high
|
||||
# SXMO_ROTATION_GRAVITY = "12500"; # kinda uncomfortable when walking
|
||||
SXMO_ROTATION_GRAVITY = "12000";
|
||||
SXMO_SCREENSHOT_DIR = "/home/colin/Pictures"; # default: "$HOME"
|
||||
|
||||
# sway/wayland scaling:
|
||||
# - conflicting info out there on how scaling actually works
|
||||
# at the least, for things where it matters (mpv), it seems like scale settings have 0 effect on perf
|
||||
# ways to enforce scaling:
|
||||
# - <https://wiki.archlinux.org/title/HiDPI>
|
||||
# - `swaymsg -- output DSI-1 scale 2.0` (scales everything)
|
||||
# - `dconf write /org/gnome/desktop/interface/text-scaling-factor 2.0` (scales ONLY TEXT)
|
||||
# - `GDK_DPI_SCALE=2.0` (scales ONLY TEXT)
|
||||
#
|
||||
# application notes:
|
||||
# - cozy: in landscape, playback position is not visible unless scale <= 1.7
|
||||
# - if in a tab, then scale 1.6 is the max
|
||||
# SXMO_SWAY_SCALE = "1.5"; # hard to press gPodder icons
|
||||
SXMO_SWAY_SCALE = "1.6";
|
||||
# SXMO_SWAY_SCALE = "1.8";
|
||||
# SXMO_SWAY_SCALE = "2";
|
||||
SXMO_WORKSPACE_WRAPPING = "5"; # how many workspaces. default: 4
|
||||
|
||||
# wvkbd layers:
|
||||
# - full
|
||||
# - landscape
|
||||
# - special (e.g. coding symbols like ~)
|
||||
# - emoji
|
||||
# - nav
|
||||
# - simple (like landscape, but no parens/tab/etc; even fewer chars)
|
||||
# - simplegrid (simple, but grid layout)
|
||||
# - dialer (digits)
|
||||
# - cyrillic
|
||||
# - arabic
|
||||
# - persian
|
||||
# - greek
|
||||
# - georgian
|
||||
WVKBD_LANDSCAPE_LAYERS = "landscape,special,emoji";
|
||||
WVKBD_LAYERS = "full,special,emoji";
|
||||
};
|
||||
sane.programs.waybar.config = {
|
||||
fontSize = 14;
|
||||
height = 26;
|
||||
persistWorkspaces = [ "1" "2" "3" "4" "5" ];
|
||||
modules.media = false;
|
||||
modules.network = false;
|
||||
modules.perf = false;
|
||||
modules.windowTitle = false;
|
||||
# TODO: show modem state
|
||||
};
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
sane.persist.enable = false;
|
||||
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
||||
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
||||
|
||||
# auto-login at shell
|
||||
|
@@ -82,34 +82,34 @@
|
||||
};
|
||||
sane.fs."/mnt/usb-hdd".mount = {};
|
||||
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
# TODO: this is overly broad; only need media and share directories to be persisted
|
||||
{ user = "colin"; group = "users"; path = "/var/lib/uninsane"; method = "bind"; }
|
||||
];
|
||||
# force some problematic directories to always get correct permissions:
|
||||
sane.fs."/var/lib/uninsane/media".dir.acl = {
|
||||
user = "colin"; group = "media"; mode = "0775";
|
||||
};
|
||||
sane.fs."/var/lib/uninsane/media/archive".dir = {};
|
||||
sane.persist.sys.byStore.plaintext = [{
|
||||
path = "/var/media";
|
||||
method = "bind"; #< this HAS to be `bind` if we're going to persist the whole thing but create subdirs, as below.
|
||||
user = "colin";
|
||||
group = "media";
|
||||
mode = "0755";
|
||||
}];
|
||||
sane.fs."/var/media/archive".dir = {};
|
||||
# this is file.text instead of symlink.text so that it may be read over a remote mount (where consumers might not have any /nix/store/.../README.md path)
|
||||
sane.fs."/var/lib/uninsane/media/archive/README.md".file.text = ''
|
||||
sane.fs."/var/media/archive/README.md".file.text = ''
|
||||
this directory is for media i wish to remove from my library,
|
||||
but keep for a short time in case i reverse my decision.
|
||||
treat it like a system trash can.
|
||||
'';
|
||||
sane.fs."/var/lib/uninsane/media/Books".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Books/Audiobooks".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Books/Books".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Books/Visual".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/collections".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/datasets".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/freeleech".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Music".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Pictures".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Videos".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Videos/Film".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Videos/Shows".dir = {};
|
||||
sane.fs."/var/lib/uninsane/media/Videos/Talks".dir = {};
|
||||
sane.fs."/var/media/Books".dir = {};
|
||||
sane.fs."/var/media/Books/Audiobooks".dir = {};
|
||||
sane.fs."/var/media/Books/Books".dir = {};
|
||||
sane.fs."/var/media/Books/Visual".dir = {};
|
||||
sane.fs."/var/media/collections".dir = {};
|
||||
sane.fs."/var/media/datasets".dir = {};
|
||||
sane.fs."/var/media/freeleech".dir = {};
|
||||
sane.fs."/var/media/Music".dir = {};
|
||||
sane.fs."/var/media/Pictures".dir = {};
|
||||
sane.fs."/var/media/Videos".dir = {};
|
||||
sane.fs."/var/media/Videos/Film".dir = {};
|
||||
sane.fs."/var/media/Videos/Shows".dir = {};
|
||||
sane.fs."/var/media/Videos/Talks".dir = {};
|
||||
|
||||
# this is file.text instead of symlink.text so that it may be read over a remote mount (where consumers might not have any /nix/store/.../README.md path)
|
||||
sane.fs."/var/lib/uninsane/datasets/README.md".file.text = ''
|
||||
this directory may seem redundant with ../media/datasets. it isn't.
|
||||
@@ -122,19 +122,19 @@
|
||||
user = "colin";
|
||||
group = "users";
|
||||
mode = "0777";
|
||||
path = "/var/lib/uninsane/media/Videos";
|
||||
path = "/var/media/Videos";
|
||||
}
|
||||
{
|
||||
user = "colin";
|
||||
group = "users";
|
||||
mode = "0777";
|
||||
path = "/var/lib/uninsane/media/freeleech";
|
||||
path = "/var/media/freeleech";
|
||||
}
|
||||
{
|
||||
user = "colin";
|
||||
group = "users";
|
||||
mode = "0777";
|
||||
path = "/var/lib/uninsane/media/datasets";
|
||||
mode = "0775";
|
||||
path = "/var/lib/uninsane/datasets";
|
||||
}
|
||||
];
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
fileSystems."/var/export/media" = {
|
||||
# everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
|
||||
device = "/var/lib/uninsane/media";
|
||||
device = "/var/media";
|
||||
options = [ "rbind" ];
|
||||
};
|
||||
# fileSystems."/var/export/playground" = {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
{ lib, ... }:
|
||||
|
||||
lib.mkIf false #< i don't actively use navidrome
|
||||
{
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
{ user = "navidrome"; group = "navidrome"; path = "/var/lib/navidrome"; method = "bind"; }
|
||||
@@ -9,7 +10,7 @@
|
||||
# docs: https://www.navidrome.org/docs/usage/configuration-options/
|
||||
Address = "127.0.0.1";
|
||||
Port = 4533;
|
||||
MusicFolder = "/var/lib/uninsane/media/Music";
|
||||
MusicFolder = "/var/media/Music";
|
||||
CovertArtPriority = "*.jpg, *.JPG, *.png, *.PNG, embedded";
|
||||
AutoImportPlaylists = false;
|
||||
ScanSchedule = "@every 1h";
|
||||
|
@@ -55,8 +55,8 @@ in
|
||||
|
||||
# web blog/personal site
|
||||
# alternative way to link stuff into the share:
|
||||
# sane.fs."/var/lib/uninsane/share/Ubunchu".mount.bind = "/var/lib/uninsane/media/Books/Visual/HiroshiSeo/Ubunchu";
|
||||
# sane.fs."/var/lib/uninsane/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
||||
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
||||
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
||||
services.nginx.virtualHosts."uninsane.org" = publog {
|
||||
# a lot of places hardcode https://uninsane.org,
|
||||
# and then when we mix http + non-https, we get CORS violations
|
||||
|
@@ -44,13 +44,13 @@
|
||||
# [Alias]/path/on/disk
|
||||
# NOTE: Music library is quick to scan; videos take a solid 10min to scan.
|
||||
# TODO: re-enable the other libraries
|
||||
# "[Audioooks]/var/lib/uninsane/media/Books/Audiobooks"
|
||||
# "[Books]/var/lib/uninsane/media/Books/Books"
|
||||
# "[Manga]/var/lib/uninsane/media/Books/Visual"
|
||||
# "[games]/var/lib/uninsane/media/games"
|
||||
"[Music]/var/lib/uninsane/media/Music"
|
||||
# "[Film]/var/lib/uninsane/media/Videos/Film"
|
||||
# "[Shows]/var/lib/uninsane/media/Videos/Shows"
|
||||
# "[Audioooks]/var/media/Books/Audiobooks"
|
||||
# "[Books]/var/media/Books/Books"
|
||||
# "[Manga]/var/media/Books/Visual"
|
||||
# "[games]/var/media/games"
|
||||
"[Music]/var/media/Music"
|
||||
# "[Film]/var/media/Videos/Film"
|
||||
# "[Shows]/var/media/Videos/Shows"
|
||||
];
|
||||
# directories.downloads = "..." # TODO
|
||||
# directories.incomplete = "..." # TODO
|
||||
|
@@ -72,8 +72,8 @@ in
|
||||
# see: https://git.zknt.org/mirror/transmission/commit/cfce6e2e3a9b9d31a9dafedd0bdc8bf2cdb6e876?lang=bg-BG
|
||||
anti-brute-force-enabled = false;
|
||||
|
||||
download-dir = "/var/lib/uninsane/media";
|
||||
incomplete-dir = "/var/lib/uninsane/media/incomplete";
|
||||
download-dir = "/var/media";
|
||||
incomplete-dir = "/var/media/incomplete";
|
||||
# transmission regularly fails to move stuff from the incomplete dir to the main one, so disable:
|
||||
# TODO: uncomment this line!
|
||||
incomplete-dir-enabled = false;
|
||||
|
@@ -43,17 +43,6 @@
|
||||
fi
|
||||
'';
|
||||
};
|
||||
system.activationScripts.notifyActive = {
|
||||
text = ''
|
||||
# send a notification to any sway users logged in, that the system has been activated/upgraded.
|
||||
# this probably doesn't work if more than one sway session exists on the system.
|
||||
_notifyActiveSwaySock="$(echo /run/user/*/sway-ipc*.sock)"
|
||||
if [ -e "$_notifyActiveSwaySock" ]; then
|
||||
SWAYSOCK="$_notifyActiveSwaySock" ${config.sane.programs.sway.packageUnwrapped}/bin/swaymsg -- exec \
|
||||
"${pkgs.libnotify}/bin/notify-send 'nixos activated' 'version: $(cat $systemConfig/nixos-version)'"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# link debug symbols into /run/current-system/sw/lib/debug
|
||||
# hopefully picked up by gdb automatically?
|
||||
|
@@ -121,6 +121,7 @@ let
|
||||
texts = [
|
||||
(fromDb "acoup.blog/feed") # history, states. author: <https://historians.social/@bretdevereaux/following>
|
||||
(fromDb "amosbbatto.wordpress.com" // tech)
|
||||
(fromDb "anish.lakhwara.com" // tech)
|
||||
(fromDb "applieddivinitystudies.com" // rat)
|
||||
(fromDb "artemis.sh" // tech)
|
||||
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
||||
@@ -161,6 +162,7 @@ let
|
||||
(fromDb "palladiummag.com" // uncat)
|
||||
(fromDb "philosopher.coach" // rat) # Peter Saint-Andre -- side project of stpeter.im
|
||||
(fromDb "pomeroyb.com" // tech)
|
||||
(fromDb "postmarketos.org/blog" // tech)
|
||||
(fromDb "preposterousuniverse.com" // rat) # Sean Carroll
|
||||
(fromDb "profectusmag.com" // uncat)
|
||||
(fromDb "project-insanity.org" // tech) # shared blog by a few NixOS devs, notably onny
|
||||
@@ -172,9 +174,11 @@ let
|
||||
(fromDb "sagacioussuricata.com" // tech) # ian (Sanctuary)
|
||||
(fromDb "semiaccurate.com" // tech)
|
||||
(fromDb "sideways-view.com" // rat) # Paul Christiano
|
||||
(fromDb "slatecave.net" // tech)
|
||||
(fromDb "slimemoldtimemold.com" // rat)
|
||||
(fromDb "spectrum.ieee.org" // tech)
|
||||
(fromDb "stpeter.im/atom.xml" // pol)
|
||||
(fromDb "thediff.co" // pol) # Byrne Hobart
|
||||
# (fromDb "theregister.com" // tech)
|
||||
(fromDb "thisweek.gnome.org" // tech)
|
||||
(fromDb "tuxphones.com" // tech)
|
||||
@@ -182,17 +186,15 @@ let
|
||||
(fromDb "unintendedconsequenc.es" // rat)
|
||||
# (fromDb "vitalik.ca" // tech) # moved to vitalik.eth.limo
|
||||
(fromDb "vitalik.eth.limo" // tech) # Vitalik Buterin
|
||||
(fromDb "webcurious.co.uk" // uncat)
|
||||
# (fromDb "webcurious.co.uk" // uncat) # link aggregator; defunct?
|
||||
(fromDb "xn--gckvb8fzb.com" // tech)
|
||||
(mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
|
||||
(mkSubstack "byrnehobart" // pol // infrequent)
|
||||
# (mkSubstack "doomberg" // tech // weekly) # articles are all pay-walled
|
||||
(mkSubstack "eliqian" // rat // weekly)
|
||||
(mkSubstack "oversharing" // pol // daily)
|
||||
(mkSubstack "samkriss" // humor // infrequent)
|
||||
(mkText "http://benjaminrosshoffman.com/feed" // pol // weekly)
|
||||
(mkText "http://boginjr.com/feed" // tech // infrequent)
|
||||
(mkText "https://anish.lakhwara.com/home.html" // tech // weekly)
|
||||
(mkText "https://forum.merveilles.town/rss.xml" // pol // infrequent) #quality RSS list here: <https://forum.merveilles.town/thread/57/share-your-rss-feeds%21-6/>
|
||||
# (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent)
|
||||
(mkText "https://jvns.ca/atom.xml" // tech // weekly) # Julia Evans
|
||||
@@ -211,6 +213,7 @@ let
|
||||
(fromDb "youtube.com/@Exurb1a")
|
||||
(fromDb "youtube.com/@hbomberguy")
|
||||
(fromDb "youtube.com/@JackStauber")
|
||||
(fromDb "youtube.com/@NativLang")
|
||||
(fromDb "youtube.com/@PolyMatter")
|
||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
||||
|
@@ -79,11 +79,6 @@
|
||||
HandleLidSwitch=lock
|
||||
'';
|
||||
|
||||
# some packages build only if binfmt *isn't* present
|
||||
nix.settings.system-features = lib.mkIf (config.boot.binfmt.emulatedSystems == []) [
|
||||
"no-binfmt"
|
||||
];
|
||||
|
||||
# services.snapper.configs = {
|
||||
# root = {
|
||||
# subvolume = "/";
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ config, ... }:
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
sane.user.persist.byStore.plaintext = [
|
||||
"archive"
|
||||
@@ -29,14 +29,17 @@
|
||||
];
|
||||
|
||||
# convenience
|
||||
sane.user.fs.".persist/private".symlink.target = config.sane.persist.stores.private.origin;
|
||||
sane.user.fs.".persist/plaintext".symlink.target = config.sane.persist.stores.plaintext.origin;
|
||||
sane.user.fs.".persist/ephemeral".symlink.target = config.sane.persist.stores.cryptClearOnBoot.origin;
|
||||
sane.user.fs = let
|
||||
persistEnabled = config.sane.persist.enable;
|
||||
in {
|
||||
".persist/private" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.private.origin; };
|
||||
".persist/plaintext" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.plaintext.origin; };
|
||||
".persist/ephemeral" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.cryptClearOnBoot.origin; };
|
||||
|
||||
sane.user.fs."nixos".symlink.target = "dev/nixos";
|
||||
"nixos".symlink.target = "dev/nixos";
|
||||
|
||||
sane.user.fs."Books/servo".symlink.target = "/mnt/servo/media/Books";
|
||||
sane.user.fs."Videos/servo".symlink.target = "/mnt/servo/media/Videos";
|
||||
# sane.user.fs."Music/servo".symlink.target = "/mnt/servo/media/Music";
|
||||
sane.user.fs."Pictures/servo-macros".symlink.target = "/mnt/servo/media/Pictures/macros";
|
||||
"Books/servo".symlink.target = "/mnt/servo/media/Books";
|
||||
"Videos/servo".symlink.target = "/mnt/servo/media/Videos";
|
||||
"Pictures/servo-macros".symlink.target = "/mnt/servo/media/Pictures/macros";
|
||||
};
|
||||
}
|
||||
|
@@ -53,8 +53,9 @@
|
||||
|
||||
# allow `nix-shell` (and probably nix-index?) to locate our patched and custom packages.
|
||||
# this is actually a no-op, and the real action happens in assigning `nix.settings.nix-path`.
|
||||
nix.nixPath = [
|
||||
nix.nixPath = (lib.optionals config.sane.enableSlowPrograms [
|
||||
"nixpkgs=${pkgs.path}"
|
||||
]) ++ [
|
||||
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
||||
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
||||
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
||||
@@ -63,7 +64,13 @@
|
||||
];
|
||||
|
||||
# ensure new deployments have a source of this repo with which they can bootstrap.
|
||||
environment.etc."nixos".source = ../../..;
|
||||
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
||||
environment.etc."nixos" = lib.mkIf config.sane.enableSlowPrograms {
|
||||
source = ../../..;
|
||||
};
|
||||
environment.etc."nix/registry.json" = lib.mkIf (!config.sane.enableSlowPrograms) {
|
||||
enable = false;
|
||||
};
|
||||
|
||||
systemd.services.nix-daemon.serviceConfig = {
|
||||
# the nix-daemon manages nix builders
|
||||
|
@@ -13,7 +13,7 @@
|
||||
"/run/current-system/sw"
|
||||
];
|
||||
|
||||
# NIXPKGS_CONFIG defaults to "/etc/nix/nixpkgs-config.nix", for idfk why.
|
||||
# NIXPKGS_CONFIG defaults to "/etc/nix/nixpkgs-config.nix" in <nixos/modules/programs/environment.nix>.
|
||||
# that's never existed on my system and everything does fine without it set empty (no nixpkgs API to forcibly *unset* it).
|
||||
environment.variables.NIXPKGS_CONFIG = lib.mkForce "";
|
||||
# XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist.
|
||||
@@ -42,4 +42,26 @@
|
||||
# so as to inform when trying to run a non-nixos binary?
|
||||
# IMO that's confusing: i thought /lib/ld-linux.so was some file actually required by nix.
|
||||
environment.stub-ld.enable = false;
|
||||
|
||||
# `less.enable` sets LESSKEYIN_SYSTEM, LESSOPEN, LESSCLOSE env vars, which does confusing "lesspipe" things, so disable that.
|
||||
# it's enabled by default from `<nixos/modules/programs/environment.nix>`, who also sets `PAGER="less"` and `EDITOR="nano"` (keep).
|
||||
programs.less.enable = lib.mkForce false;
|
||||
environment.variables.PAGER = lib.mkOverride 900 ""; # mkDefault sets 1000. non-override is 100. 900 will beat the nixpkgs `mkDefault` but not anyone else.
|
||||
environment.variables.EDITOR = lib.mkOverride 900 "";
|
||||
|
||||
# several packages (dconf, modemmanager, networkmanager, gvfs, polkit, udisks, bluez/blueman, feedbackd, etc)
|
||||
# will add themselves to the dbus search path.
|
||||
# i prefer dbus to only search XDG paths (/share/dbus-1) for service files, as that's more introspectable.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/services/system/dbus.nix>
|
||||
# TODO: sandbox dbus? i pretty explicitly don't want to use it as a launcher.
|
||||
services.dbus.packages = lib.mkForce [
|
||||
"/run/current-system/sw"
|
||||
# config.system.path
|
||||
# pkgs.dbus
|
||||
# pkgs.polkit.out
|
||||
# pkgs.modemmanager
|
||||
# pkgs.networkmanager
|
||||
# pkgs.udisks
|
||||
# pkgs.wpa_supplicant
|
||||
];
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@
|
||||
{
|
||||
sane.programs.aerc = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace";
|
||||
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf refers to other /share files by absolute path
|
||||
sandbox.net = "clearnet";
|
||||
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
||||
mime.associations."x-scheme-handler/mailto" = "aerc.desktop";
|
||||
|
@@ -3,14 +3,28 @@
|
||||
# - `man 5 alacritty`
|
||||
# - defaults: <https://github.com/alacritty/alacritty/releases> -> alacritty.yml
|
||||
# - irc: #alacritty on libera.chat
|
||||
{ lib, ... }:
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.alacritty;
|
||||
in
|
||||
{
|
||||
sane.programs.alacritty = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options.fontSize = mkOption {
|
||||
type = types.int;
|
||||
default = 14;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sandbox.enable = false;
|
||||
env.TERMINAL = lib.mkDefault "alacritty";
|
||||
|
||||
fs.".config/alacritty/alacritty.toml".symlink.text = ''
|
||||
[font]
|
||||
size = 14
|
||||
size = ${builtins.toString cfg.config.fontSize}
|
||||
|
||||
[[keyboard.bindings]]
|
||||
mods = "Control"
|
||||
@@ -36,6 +50,21 @@
|
||||
mods = "Control|Shift"
|
||||
key = "PageDown"
|
||||
action = "ScrollPageDown"
|
||||
|
||||
# disable OS shortcuts which leak through...
|
||||
# see sway config or sane-input-handler for more info on why these leak through
|
||||
[[keyboard.bindings]]
|
||||
key = "AudioVolumeUp"
|
||||
action = "None"
|
||||
[[keyboard.bindings]]
|
||||
key = "AudioVolumeDown"
|
||||
action = "None"
|
||||
[[keyboard.bindings]]
|
||||
key = "Power"
|
||||
action = "None"
|
||||
[[keyboard.bindings]]
|
||||
key = "PowerOff"
|
||||
action = "None"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
65
hosts/common/programs/alsa-ucm-conf/default.nix
Normal file
65
hosts/common/programs/alsa-ucm-conf/default.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.alsa-ucm-conf;
|
||||
in
|
||||
{
|
||||
sane.programs.alsa-ucm-conf = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options.preferEarpiece = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# upstream alsa ships with PinePhone audio configs, but they don't actually produce sound.
|
||||
# see: <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
||||
# these audio files come from some revision of:
|
||||
# - <https://gitlab.manjaro.org/manjaro-arm/packages/community/phosh/alsa-ucm-pinephone>
|
||||
#
|
||||
# alternative to patching is to plumb `ALSA_CONFIG_UCM2 = "${./ucm2}"` environment variable into the relevant places
|
||||
# e.g. `systemd.services.pulseaudio.environment`.
|
||||
# that leaves more opportunity for gaps (i.e. missing a service),
|
||||
# on the other hand this method causes about 500 packages to be rebuilt (including qt5 and webkitgtk).
|
||||
#
|
||||
# note that with these files, the following audio device support:
|
||||
# - headphones work.
|
||||
# - "internal earpiece" works.
|
||||
# - "internal speaker" doesn't work (but that's probably because i broke the ribbon cable)
|
||||
# - "analog output" doesn't work.
|
||||
packageUnwrapped = pkgs.alsa-ucm-conf.overrideAttrs (upstream: {
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
cp ${./ucm2/PinePhone}/* ucm2/Allwinner/A64/PinePhone/
|
||||
|
||||
# fix the self-contained ucm files i source from to have correct path within the alsa-ucm-conf source tree
|
||||
substituteInPlace ucm2/Allwinner/A64/PinePhone/PinePhone.conf \
|
||||
--replace 'HiFi.conf' '/Allwinner/A64/PinePhone/HiFi.conf'
|
||||
substituteInPlace ucm2/Allwinner/A64/PinePhone/PinePhone.conf \
|
||||
--replace 'VoiceCall.conf' '/Allwinner/A64/PinePhone/VoiceCall.conf'
|
||||
'' + lib.optionalString cfg.config.preferEarpiece ''
|
||||
# decrease the priority of the internal speaker so that sounds are routed
|
||||
# to the earpiece by default.
|
||||
# this is just personal preference.
|
||||
substituteInPlace ucm2/Allwinner/A64/PinePhone/* \
|
||||
--replace 'PlaybackPriority 300' 'PlaybackPriority 100'
|
||||
'';
|
||||
});
|
||||
|
||||
sandbox.enable = false; #< only provides #out/share/alsa
|
||||
|
||||
# alsa-lib package only looks in its $out/share/alsa to find runtime config data, by default.
|
||||
# but ALSA_CONFIG_UCM2 is an env var that can override that.
|
||||
# this is particularly needed by wireplumber;
|
||||
# also *maybe* pipewire and pipewire-pulse.
|
||||
# taken from <repo:nixos/mobile-nixos:modules/quirks/audio.nix>
|
||||
env.ALSA_CONFIG_UCM2 = "/run/current-system/sw/share/alsa/ucm2";
|
||||
|
||||
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||
};
|
||||
|
||||
environment.pathsToLink = lib.mkIf cfg.enabled [
|
||||
"/share/alsa/ucm2"
|
||||
];
|
||||
}
|
@@ -31,7 +31,6 @@
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
|
@@ -62,6 +62,7 @@ in
|
||||
# "iw"
|
||||
"jq"
|
||||
"killall"
|
||||
"less"
|
||||
# "libcap_ng" # for `netcap`
|
||||
"lsof"
|
||||
# "miniupnpc"
|
||||
@@ -165,6 +166,7 @@ in
|
||||
];
|
||||
|
||||
consoleMediaUtils = declPackageSet [
|
||||
"blast-ugjka" # cast audio to UPNP/DLNA devices (via pulseaudio sink)
|
||||
# "catt" # cast videos to chromecast
|
||||
"ffmpeg"
|
||||
"go2tv" # cast videos to UPNP/DLNA device (i.e. tv).
|
||||
@@ -203,19 +205,17 @@ in
|
||||
# INDIVIDUAL PACKAGE DEFINITIONS
|
||||
|
||||
alsaUtils.sandbox.method = "landlock";
|
||||
alsaUtils.sandbox.wrapperType = "wrappedDerivation";
|
||||
alsaUtils.sandbox.whitelistAudio = true; #< not strictly necessary?
|
||||
|
||||
backblaze-b2 = {};
|
||||
|
||||
blanket.sandbox.method = "bwrap";
|
||||
blanket.sandbox.wrapperType = "wrappedDerivation";
|
||||
blanket.sandbox.whitelistAudio = true;
|
||||
# blanket.sandbox.whitelistDbus = [ "user" ]; # TODO: untested
|
||||
blanket.sandbox.whitelistWayland = true;
|
||||
|
||||
blueberry.sandbox.method = "bwrap";
|
||||
blueberry.sandbox.wrapperType = "inplace"; # /etc/xdg/autostart hardcodes paths
|
||||
blueberry.sandbox.wrapperType = "inplace"; #< various /lib scripts refer to the bins by full path
|
||||
blueberry.sandbox.whitelistWayland = true;
|
||||
blueberry.sandbox.extraPaths = [
|
||||
"/dev/rfkill"
|
||||
@@ -225,11 +225,9 @@ in
|
||||
];
|
||||
|
||||
bridge-utils.sandbox.method = "bwrap"; #< bwrap, landlock: both work
|
||||
bridge-utils.sandbox.wrapperType = "wrappedDerivation";
|
||||
bridge-utils.sandbox.net = "all";
|
||||
|
||||
brightnessctl.sandbox.method = "landlock"; # also bwrap, but landlock is more responsive
|
||||
brightnessctl.sandbox.wrapperType = "wrappedDerivation";
|
||||
brightnessctl.sandbox.extraPaths = [
|
||||
"/sys/class/backlight"
|
||||
"/sys/class/leds"
|
||||
@@ -238,7 +236,6 @@ in
|
||||
brightnessctl.sandbox.whitelistDbus = [ "system" ];
|
||||
|
||||
btrfs-progs.sandbox.method = "bwrap"; #< bwrap, landlock: both work
|
||||
btrfs-progs.sandbox.wrapperType = "wrappedDerivation";
|
||||
btrfs-progs.sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
|
||||
|
||||
"cacert.unbundled".sandbox.enable = false;
|
||||
@@ -249,7 +246,6 @@ in
|
||||
|
||||
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
|
||||
cryptsetup.sandbox.method = "landlock";
|
||||
cryptsetup.sandbox.wrapperType = "wrappedDerivation";
|
||||
cryptsetup.sandbox.extraPaths = [
|
||||
"/dev/mapper"
|
||||
"/dev/random"
|
||||
@@ -263,12 +259,10 @@ in
|
||||
cryptsetup.sandbox.autodetectCliPaths = "existing";
|
||||
|
||||
ddrescue.sandbox.method = "landlock"; # TODO:sandbox: untested
|
||||
ddrescue.sandbox.wrapperType = "wrappedDerivation";
|
||||
ddrescue.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
|
||||
# auth token, preferences
|
||||
delfin.sandbox.method = "bwrap";
|
||||
delfin.sandbox.wrapperType = "wrappedDerivation";
|
||||
delfin.sandbox.whitelistAudio = true;
|
||||
delfin.sandbox.whitelistDbus = [ "user" ]; # else `mpris` plugin crashes the player
|
||||
delfin.sandbox.whitelistDri = true;
|
||||
@@ -277,7 +271,6 @@ in
|
||||
delfin.persist.byStore.private = [ ".config/delfin" ];
|
||||
|
||||
dig.sandbox.method = "bwrap";
|
||||
dig.sandbox.wrapperType = "wrappedDerivation";
|
||||
dig.sandbox.net = "all";
|
||||
|
||||
# creds, but also 200 MB of node modules, etc
|
||||
@@ -293,18 +286,15 @@ in
|
||||
dtc.sandbox.autodetectCliPaths = true; # TODO:sandbox: untested
|
||||
|
||||
dtrx.sandbox.method = "bwrap";
|
||||
dtrx.sandbox.wrapperType = "wrappedDerivation";
|
||||
dtrx.sandbox.whitelistPwd = true;
|
||||
dtrx.sandbox.autodetectCliPaths = "existing"; #< for the archive
|
||||
|
||||
duplicity = {};
|
||||
|
||||
e2fsprogs.sandbox.method = "landlock";
|
||||
e2fsprogs.sandbox.wrapperType = "wrappedDerivation";
|
||||
e2fsprogs.sandbox.autodetectCliPaths = "existing";
|
||||
|
||||
efibootmgr.sandbox.method = "landlock";
|
||||
efibootmgr.sandbox.wrapperType = "wrappedDerivation";
|
||||
efibootmgr.sandbox.extraPaths = [
|
||||
"/sys/firmware/efi"
|
||||
];
|
||||
@@ -312,14 +302,12 @@ in
|
||||
eg25-control = {};
|
||||
|
||||
electrum.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
electrum.sandbox.wrapperType = "wrappedDerivation";
|
||||
electrum.sandbox.net = "all"; # TODO: probably want to make this run behind a VPN, always
|
||||
electrum.sandbox.whitelistWayland = true;
|
||||
electrum.persist.byStore.cryptClearOnBoot = [ ".electrum" ]; #< TODO: use XDG dirs!
|
||||
|
||||
endless-sky.persist.byStore.plaintext = [ ".local/share/endless-sky" ];
|
||||
endless-sky.sandbox.method = "bwrap";
|
||||
endless-sky.sandbox.wrapperType = "wrappedDerivation";
|
||||
endless-sky.sandbox.whitelistAudio = true;
|
||||
endless-sky.sandbox.whitelistDri = true;
|
||||
endless-sky.sandbox.whitelistWayland = true;
|
||||
@@ -330,14 +318,12 @@ in
|
||||
emote.persist.byStore.plaintext = [ ".local/share/Emote" ];
|
||||
|
||||
ethtool.sandbox.method = "landlock";
|
||||
ethtool.sandbox.wrapperType = "wrappedDerivation";
|
||||
ethtool.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
# eza `ls` replacement
|
||||
# landlock is OK, only `whitelistPwd` doesn't make the intermediate symlinks traversable, so it breaks on e.g. ~/Videos/servo/Shows/foo
|
||||
# eza.sandbox.method = "landlock";
|
||||
eza.sandbox.method = "bwrap";
|
||||
eza.sandbox.wrapperType = "wrappedDerivation"; # slow to build
|
||||
eza.sandbox.autodetectCliPaths = true;
|
||||
eza.sandbox.whitelistPwd = true;
|
||||
eza.sandbox.extraHomePaths = [
|
||||
@@ -347,11 +333,9 @@ in
|
||||
];
|
||||
|
||||
fatresize.sandbox.method = "landlock";
|
||||
fatresize.sandbox.wrapperType = "wrappedDerivation";
|
||||
fatresize.sandbox.autodetectCliPaths = "parent"; # /dev/sda1 -> needs /dev/sda
|
||||
|
||||
fd.sandbox.method = "landlock";
|
||||
fd.sandbox.wrapperType = "wrappedDerivation"; # slow to build
|
||||
fd.sandbox.autodetectCliPaths = true;
|
||||
fd.sandbox.whitelistPwd = true;
|
||||
fd.sandbox.extraHomePaths = [
|
||||
@@ -361,15 +345,12 @@ in
|
||||
];
|
||||
|
||||
ffmpeg.sandbox.method = "bwrap";
|
||||
ffmpeg.sandbox.wrapperType = "wrappedDerivation"; # slow to build
|
||||
ffmpeg.sandbox.autodetectCliPaths = "existingFileOrParent"; # it outputs uncreated files -> parent dir needs mounting
|
||||
|
||||
file.sandbox.method = "bwrap";
|
||||
file.sandbox.wrapperType = "wrappedDerivation";
|
||||
file.sandbox.autodetectCliPaths = true;
|
||||
|
||||
findutils.sandbox.method = "bwrap";
|
||||
findutils.sandbox.wrapperType = "wrappedDerivation";
|
||||
findutils.sandbox.autodetectCliPaths = true;
|
||||
findutils.sandbox.whitelistPwd = true;
|
||||
findutils.sandbox.extraHomePaths = [
|
||||
@@ -381,14 +362,12 @@ in
|
||||
fluffychat-moby.persist.byStore.plaintext = [ ".local/share/chat.fluffy.fluffychat" ];
|
||||
|
||||
font-manager.sandbox.method = "bwrap";
|
||||
font-manager.sandbox.wrapperType = "inplace"; # .desktop and dbus .service file refer to /libexec
|
||||
font-manager.packageUnwrapped = pkgs.font-manager.override {
|
||||
font-manager.packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.font-manager.override {
|
||||
# build without the "Google Fonts" integration feature, to save closure / avoid webkitgtk_4_0
|
||||
withWebkit = false;
|
||||
};
|
||||
});
|
||||
|
||||
forkstat.sandbox.method = "landlock"; #< doesn't seem to support bwrap
|
||||
forkstat.sandbox.wrapperType = "wrappedDerivation";
|
||||
forkstat.sandbox.extraConfig = [
|
||||
"--sane-sandbox-keep-namespace" "pid"
|
||||
];
|
||||
@@ -396,12 +375,7 @@ in
|
||||
"/proc"
|
||||
];
|
||||
|
||||
# fuzzel: TODO: re-enable sandbox. i use fuzzel both as an entry system (snippets) AND an app-launcher.
|
||||
# as an app-launcher, it cannot be sandboxed without over-restricting the app it launches.
|
||||
# should probably make it not be an app-launcher
|
||||
fuzzel.sandbox.enable = false;
|
||||
fuzzel.sandbox.method = "bwrap"; #< landlock nearly works, but unable to open ~/.cache
|
||||
fuzzel.sandbox.wrapperType = "wrappedDerivation";
|
||||
fuzzel.sandbox.whitelistWayland = true;
|
||||
fuzzel.persist.byStore.private = [
|
||||
# this is a file of recent selections
|
||||
@@ -409,12 +383,11 @@ in
|
||||
];
|
||||
|
||||
gawk.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
gawk.sandbox.wrapperType = "inplace"; # share/gawk libraries refer to /libexec
|
||||
gawk.sandbox.wrapperType = "inplace"; # /share/gawk libraries refer to /libexec
|
||||
gawk.sandbox.autodetectCliPaths = true;
|
||||
|
||||
gdb.sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
|
||||
# gdb.sandbox.method = "landlock"; # permission denied when trying to attach, even as root
|
||||
gdb.sandbox.wrapperType = "wrappedDerivation";
|
||||
gdb.sandbox.autodetectCliPaths = true;
|
||||
|
||||
geoclue2-with-demo-agent = {};
|
||||
@@ -424,7 +397,7 @@ in
|
||||
gh.persist.byStore.private = [ ".config/gh" ];
|
||||
|
||||
gimp.sandbox.method = "bwrap";
|
||||
gimp.sandbox.wrapperType = "wrappedDerivation";
|
||||
gimp.sandbox.net = "clearnet"; #< for Xwayland
|
||||
gimp.sandbox.whitelistWayland = true;
|
||||
gimp.sandbox.extraHomePaths = [
|
||||
"Pictures/albums"
|
||||
@@ -443,39 +416,32 @@ in
|
||||
];
|
||||
|
||||
"gnome.gnome-calculator".sandbox.method = "bwrap";
|
||||
"gnome.gnome-calculator".sandbox.wrapperType = "inplace"; # /libexec/gnome-calculator-search-provider
|
||||
"gnome.gnome-calculator".sandbox.whitelistWayland = true;
|
||||
|
||||
# gnome-calendar surely has data to persist, but i use it strictly to do date math, not track events.
|
||||
"gnome.gnome-calendar".sandbox.method = "bwrap";
|
||||
"gnome.gnome-calendar".sandbox.wrapperType = "wrappedDerivation";
|
||||
"gnome.gnome-calendar".sandbox.whitelistWayland = true;
|
||||
|
||||
"gnome.gnome-clocks".sandbox.method = "bwrap";
|
||||
"gnome.gnome-clocks".sandbox.wrapperType = "wrappedDerivation";
|
||||
"gnome.gnome-clocks".sandbox.whitelistWayland = true;
|
||||
"gnome.gnome-clocks".suggestedPrograms = [ "dconf" ];
|
||||
|
||||
# gnome-disks
|
||||
"gnome.gnome-disk-utility".sandbox.method = "bwrap";
|
||||
"gnome.gnome-disk-utility".sandbox.wrapperType = "inplace"; # /etc/xdg/autostart
|
||||
"gnome.gnome-disk-utility".sandbox.whitelistDbus = [ "system" ];
|
||||
"gnome.gnome-disk-utility".sandbox.whitelistWayland = true;
|
||||
|
||||
# seahorse: dump gnome-keyring secrets.
|
||||
# N.B.: it can also manage ~/.ssh keys, but i explicitly don't add those to the sandbox for now.
|
||||
"gnome.seahorse".sandbox.method = "bwrap";
|
||||
"gnome.seahorse".sandbox.wrapperType = "wrappedDerivation";
|
||||
"gnome.seahorse".sandbox.whitelistDbus = [ "user" ];
|
||||
"gnome.seahorse".sandbox.whitelistWayland = true;
|
||||
|
||||
gnome-2048.sandbox.method = "bwrap";
|
||||
gnome-2048.sandbox.wrapperType = "wrappedDerivation";
|
||||
gnome-2048.sandbox.whitelistWayland = true;
|
||||
gnome-2048.persist.byStore.plaintext = [ ".local/share/gnome-2048/scores" ];
|
||||
|
||||
gnome-frog.sandbox.method = "bwrap";
|
||||
gnome-frog.sandbox.wrapperType = "wrappedDerivation";
|
||||
gnome-frog.sandbox.whitelistWayland = true;
|
||||
gnome-frog.sandbox.whitelistDbus = [ "user" ];
|
||||
gnome-frog.sandbox.extraPaths = [
|
||||
@@ -502,11 +468,9 @@ in
|
||||
# 2. no two shaded tiles can be direct N/S/E/W neighbors
|
||||
# - win once (1) and (2) are satisfied
|
||||
"gnome.hitori".sandbox.method = "bwrap";
|
||||
"gnome.hitori".sandbox.wrapperType = "wrappedDerivation";
|
||||
"gnome.hitori".sandbox.whitelistWayland = true;
|
||||
|
||||
gnugrep.sandbox.method = "bwrap";
|
||||
gnugrep.sandbox.wrapperType = "wrappedDerivation";
|
||||
gnugrep.sandbox.autodetectCliPaths = true;
|
||||
gnugrep.sandbox.whitelistPwd = true;
|
||||
gnugrep.sandbox.extraHomePaths = [
|
||||
@@ -515,20 +479,24 @@ in
|
||||
".persist/plaintext"
|
||||
];
|
||||
|
||||
gnused = {};
|
||||
# sed: there is an edgecase of `--file=<foo>`, wherein `foo` won't be whitelisted.
|
||||
gnused.sandbox.method = "bwrap";
|
||||
gnused.sandbox.autodetectCliPaths = "existingFile";
|
||||
gnused.sandbox.whitelistPwd = true; #< `-i` flag creates a temporary file in pwd (?) and then moves it.
|
||||
|
||||
gpsd = {};
|
||||
|
||||
gptfdisk.sandbox.method = "landlock";
|
||||
gptfdisk.sandbox.wrapperType = "wrappedDerivation";
|
||||
gptfdisk.sandbox.extraPaths = [
|
||||
"/dev"
|
||||
];
|
||||
gptfdisk.sandbox.autodetectCliPaths = "existing"; #< sometimes you'll use gdisk on a device file.
|
||||
|
||||
grim = {};
|
||||
grim.sandbox.method = "bwrap";
|
||||
grim.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
grim.sandbox.whitelistWayland = true;
|
||||
|
||||
hase.sandbox.method = "bwrap";
|
||||
hase.sandbox.wrapperType = "wrappedDerivation";
|
||||
hase.sandbox.net = "clearnet";
|
||||
hase.sandbox.whitelistAudio = true;
|
||||
hase.sandbox.whitelistDri = true;
|
||||
@@ -536,15 +504,12 @@ in
|
||||
|
||||
# hdparm: has to be run as sudo. e.g. `sudo hdparm -i /dev/sda`
|
||||
hdparm.sandbox.method = "bwrap";
|
||||
hdparm.sandbox.wrapperType = "wrappedDerivation";
|
||||
hdparm.sandbox.autodetectCliPaths = true;
|
||||
|
||||
host.sandbox.method = "landlock";
|
||||
host.sandbox.wrapperType = "wrappedDerivation";
|
||||
host.sandbox.net = "all"; #< technically, only needs to contact localhost's DNS server
|
||||
|
||||
htop.sandbox.method = "landlock";
|
||||
htop.sandbox.wrapperType = "wrappedDerivation";
|
||||
htop.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
"/sys/devices"
|
||||
@@ -555,16 +520,13 @@ in
|
||||
];
|
||||
|
||||
iftop.sandbox.method = "landlock";
|
||||
iftop.sandbox.wrapperType = "wrappedDerivation";
|
||||
iftop.sandbox.capabilities = [ "net_raw" ];
|
||||
|
||||
# inetutils: ping, ifconfig, hostname, traceroute, whois, ....
|
||||
# N.B.: inetutils' `ping` is shadowed by iputils' ping (by nixos, intentionally).
|
||||
inetutils.sandbox.method = "landlock"; # want to keep the same netns, at least.
|
||||
inetutils.sandbox.wrapperType = "wrappedDerivation";
|
||||
|
||||
inkscape.sandbox.method = "bwrap";
|
||||
inkscape.sandbox.wrapperType = "wrappedDerivation";
|
||||
inkscape.sandbox.whitelistWayland = true;
|
||||
inkscape.sandbox.extraHomePaths = [
|
||||
"Pictures/albums"
|
||||
@@ -580,7 +542,6 @@ in
|
||||
inkscape.sandbox.autodetectCliPaths = true;
|
||||
|
||||
iotop.sandbox.method = "landlock";
|
||||
iotop.sandbox.wrapperType = "wrappedDerivation";
|
||||
iotop.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
];
|
||||
@@ -588,38 +549,31 @@ in
|
||||
|
||||
# provides `ip`, `routel`, others
|
||||
iproute2.sandbox.method = "landlock";
|
||||
iproute2.sandbox.wrapperType = "wrappedDerivation";
|
||||
iproute2.sandbox.net = "all";
|
||||
iproute2.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
iptables.sandbox.method = "landlock";
|
||||
iptables.sandbox.wrapperType = "wrappedDerivation";
|
||||
iptables.sandbox.net = "all";
|
||||
iptables.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
# iputils provides `ping` (and arping, clockdiff, tracepath)
|
||||
iputils.sandbox.method = "landlock";
|
||||
iputils.sandbox.wrapperType = "wrappedDerivation";
|
||||
iputils.sandbox.net = "all";
|
||||
iputils.sandbox.capabilities = [ "net_raw" ];
|
||||
|
||||
iw.sandbox.method = "landlock";
|
||||
iw.sandbox.wrapperType = "wrappedDerivation";
|
||||
iw.sandbox.net = "all";
|
||||
iw.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
jq.sandbox.method = "bwrap";
|
||||
jq.sandbox.wrapperType = "wrappedDerivation";
|
||||
jq.sandbox.autodetectCliPaths = "existingFile";
|
||||
|
||||
killall.sandbox.method = "landlock";
|
||||
killall.sandbox.wrapperType = "wrappedDerivation";
|
||||
killall.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
];
|
||||
|
||||
krita.sandbox.method = "bwrap";
|
||||
krita.sandbox.wrapperType = "wrappedDerivation";
|
||||
krita.sandbox.whitelistWayland = true;
|
||||
krita.sandbox.autodetectCliPaths = "existing";
|
||||
krita.sandbox.extraHomePaths = [
|
||||
@@ -637,11 +591,9 @@ in
|
||||
libcap_ng.sandbox.enable = false; # there's something about /proc/$pid/fd which breaks `readlink`/stat with every sandbox technique (except capsh-only)
|
||||
|
||||
libnotify.sandbox.method = "bwrap";
|
||||
libnotify.sandbox.wrapperType = "wrappedDerivation";
|
||||
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
|
||||
|
||||
losslesscut-bin.sandbox.method = "bwrap";
|
||||
losslesscut-bin.sandbox.wrapperType = "wrappedDerivation";
|
||||
losslesscut-bin.sandbox.extraHomePaths = [
|
||||
"Music"
|
||||
"Pictures/from" # videos from e.g. mobile phone
|
||||
@@ -656,12 +608,11 @@ in
|
||||
losslesscut-bin.sandbox.whitelistX = true;
|
||||
|
||||
lsof.sandbox.method = "capshonly"; # lsof doesn't sandbox under bwrap or even landlock w/ full access to /
|
||||
lsof.sandbox.wrapperType = "wrappedDerivation";
|
||||
|
||||
lua = {};
|
||||
|
||||
"mate.engrampa".packageUnwrapped = pkgs.rmDbusServices pkgs.mate.engrampa;
|
||||
"mate.engrampa".sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
"mate.engrampa".sandbox.wrapperType = "inplace";
|
||||
"mate.engrampa".sandbox.whitelistWayland = true;
|
||||
"mate.engrampa".sandbox.autodetectCliPaths = "existingOrParent";
|
||||
"mate.engrampa".sandbox.extraHomePaths = [
|
||||
@@ -674,7 +625,6 @@ in
|
||||
];
|
||||
|
||||
mercurial.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
mercurial.sandbox.wrapperType = "wrappedDerivation";
|
||||
mercurial.sandbox.net = "clearnet";
|
||||
mercurial.sandbox.whitelistPwd = true;
|
||||
|
||||
@@ -682,7 +632,6 @@ in
|
||||
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
|
||||
monero-gui.persist.byStore.plaintext = [ ".bitmonero" ];
|
||||
monero-gui.sandbox.method = "bwrap";
|
||||
monero-gui.sandbox.wrapperType = "wrappedDerivation";
|
||||
monero-gui.sandbox.net = "all";
|
||||
monero-gui.sandbox.extraHomePaths = [
|
||||
"records/finance/cryptocurrencies/monero"
|
||||
@@ -691,20 +640,16 @@ in
|
||||
mumble.persist.byStore.private = [ ".local/share/Mumble" ];
|
||||
|
||||
nano.sandbox.method = "bwrap";
|
||||
nano.sandbox.wrapperType = "wrappedDerivation";
|
||||
nano.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
|
||||
netcat.sandbox.method = "landlock";
|
||||
netcat.sandbox.wrapperType = "wrappedDerivation";
|
||||
netcat.sandbox.net = "all";
|
||||
|
||||
nethogs.sandbox.method = "capshonly"; # *partially* works under landlock w/ full access to /
|
||||
nethogs.sandbox.wrapperType = "wrappedDerivation";
|
||||
nethogs.sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||
|
||||
# provides `arp`, `hostname`, `route`, `ifconfig`
|
||||
nettools.sandbox.method = "landlock";
|
||||
nettools.sandbox.wrapperType = "wrappedDerivation";
|
||||
nettools.sandbox.net = "all";
|
||||
nettools.sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||
nettools.sandbox.extraPaths = [
|
||||
@@ -712,7 +657,6 @@ in
|
||||
];
|
||||
|
||||
networkmanagerapplet.sandbox.method = "bwrap";
|
||||
networkmanagerapplet.sandbox.wrapperType = "wrappedDerivation";
|
||||
networkmanagerapplet.sandbox.whitelistWayland = true;
|
||||
networkmanagerapplet.sandbox.whitelistDbus = [ "system" ];
|
||||
|
||||
@@ -725,11 +669,9 @@ in
|
||||
];
|
||||
|
||||
nmap.sandbox.method = "bwrap";
|
||||
nmap.sandbox.wrapperType = "wrappedDerivation";
|
||||
nmap.sandbox.net = "all"; # clearnet and lan
|
||||
|
||||
nmon.sandbox.method = "landlock";
|
||||
nmon.sandbox.wrapperType = "wrappedDerivation";
|
||||
nmon.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
];
|
||||
@@ -738,7 +680,6 @@ in
|
||||
|
||||
# `nvme list` only shows results when run as root.
|
||||
nvme-cli.sandbox.method = "landlock";
|
||||
nvme-cli.sandbox.wrapperType = "wrappedDerivation";
|
||||
nvme-cli.sandbox.extraPaths = [
|
||||
"/sys/devices"
|
||||
"/sys/class/nvme"
|
||||
@@ -750,13 +691,11 @@ in
|
||||
|
||||
# contains only `oathtool`, which i only use for evaluating TOTP codes from CLI/stdin
|
||||
oath-toolkit.sandbox.method = "bwrap";
|
||||
oath-toolkit.sandbox.wrapperType = "wrappedDerivation";
|
||||
|
||||
# settings (electron app)
|
||||
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
||||
|
||||
parted.sandbox.method = "landlock";
|
||||
parted.sandbox.wrapperType = "wrappedDerivation";
|
||||
parted.sandbox.extraPaths = [
|
||||
"/dev"
|
||||
];
|
||||
@@ -765,12 +704,10 @@ in
|
||||
patchelf = {};
|
||||
|
||||
pavucontrol.sandbox.method = "bwrap";
|
||||
pavucontrol.sandbox.wrapperType = "wrappedDerivation";
|
||||
pavucontrol.sandbox.whitelistAudio = true;
|
||||
pavucontrol.sandbox.whitelistWayland = true;
|
||||
|
||||
pciutils.sandbox.method = "landlock";
|
||||
pciutils.sandbox.wrapperType = "wrappedDerivation";
|
||||
pciutils.sandbox.extraPaths = [
|
||||
"/sys/bus/pci"
|
||||
"/sys/devices"
|
||||
@@ -779,7 +716,6 @@ in
|
||||
"perlPackages.FileMimeInfo".sandbox.enable = false; #< TODO: sandbox `mimetype` but not `mimeopen`.
|
||||
|
||||
powertop.sandbox.method = "landlock";
|
||||
powertop.sandbox.wrapperType = "wrappedDerivation";
|
||||
powertop.sandbox.capabilities = [ "ipc_lock" "sys_admin" ];
|
||||
powertop.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
@@ -788,18 +724,23 @@ in
|
||||
"/sys/kernel"
|
||||
];
|
||||
|
||||
# procps: free, pgrep, pidof, pkill, ps, pwait, top, uptime, couple others
|
||||
procps.sandbox.method = "bwrap";
|
||||
procps.sandbox.extraConfig = [
|
||||
"--sane-sandbox-keep-namespace" "pid"
|
||||
];
|
||||
|
||||
pstree.sandbox.method = "landlock";
|
||||
pstree.sandbox.wrapperType = "wrappedDerivation";
|
||||
pstree.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
];
|
||||
|
||||
pulseaudio = {};
|
||||
|
||||
pulsemixer.sandbox.method = "landlock";
|
||||
pulsemixer.sandbox.wrapperType = "wrappedDerivation";
|
||||
pulsemixer.sandbox.whitelistAudio = true;
|
||||
|
||||
pwvucontrol.sandbox.method = "bwrap";
|
||||
pwvucontrol.sandbox.wrapperType = "wrappedDerivation";
|
||||
pwvucontrol.sandbox.whitelistAudio = true;
|
||||
pwvucontrol.sandbox.whitelistWayland = true;
|
||||
|
||||
@@ -807,7 +748,6 @@ in
|
||||
requests
|
||||
]);
|
||||
python3-repl.sandbox.method = "bwrap";
|
||||
python3-repl.sandbox.wrapperType = "wrappedDerivation";
|
||||
python3-repl.sandbox.net = "clearnet";
|
||||
python3-repl.sandbox.extraHomePaths = [
|
||||
"/"
|
||||
@@ -818,22 +758,24 @@ in
|
||||
qemu.slowToBuild = true;
|
||||
|
||||
rsync.sandbox.method = "bwrap";
|
||||
rsync.sandbox.wrapperType = "wrappedDerivation";
|
||||
rsync.sandbox.net = "clearnet";
|
||||
rsync.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
|
||||
rustc = {};
|
||||
|
||||
sane-open-desktop.sandbox.enable = false; #< trivial script, and all our deps are sandboxed
|
||||
sane-open-desktop.suggestedPrograms = [
|
||||
"gdbus"
|
||||
];
|
||||
|
||||
screen.sandbox.enable = false; #< tty; needs to run anything
|
||||
|
||||
sequoia.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
sequoia.sandbox.wrapperType = "wrappedDerivation"; # slow to build
|
||||
sequoia.sandbox.whitelistPwd = true;
|
||||
sequoia.sandbox.autodetectCliPaths = true;
|
||||
|
||||
shattered-pixel-dungeon.persist.byStore.plaintext = [ ".local/share/.shatteredpixel/shattered-pixel-dungeon" ];
|
||||
shattered-pixel-dungeon.sandbox.method = "bwrap";
|
||||
shattered-pixel-dungeon.sandbox.wrapperType = "wrappedDerivation";
|
||||
shattered-pixel-dungeon.sandbox.whitelistAudio = true;
|
||||
shattered-pixel-dungeon.sandbox.whitelistDri = true;
|
||||
shattered-pixel-dungeon.sandbox.whitelistWayland = true;
|
||||
@@ -841,7 +783,8 @@ in
|
||||
# printer/filament settings
|
||||
slic3r.persist.byStore.plaintext = [ ".Slic3r" ];
|
||||
|
||||
slurp = {};
|
||||
slurp.sandbox.method = "bwrap";
|
||||
slurp.sandbox.whitelistWayland = true;
|
||||
|
||||
# use like `sudo smartctl /dev/sda -a`
|
||||
smartmontools.sandbox.method = "landlock";
|
||||
@@ -850,7 +793,6 @@ in
|
||||
smartmontools.sandbox.capabilities = [ "sys_rawio" ];
|
||||
|
||||
sops.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
sops.sandbox.wrapperType = "wrappedDerivation";
|
||||
sops.sandbox.extraHomePaths = [
|
||||
".config/sops"
|
||||
"dev/nixos"
|
||||
@@ -860,7 +802,6 @@ in
|
||||
];
|
||||
|
||||
soundconverter.sandbox.method = "bwrap";
|
||||
soundconverter.sandbox.wrapperType = "wrappedDerivation";
|
||||
soundconverter.sandbox.whitelistWayland = true;
|
||||
soundconverter.sandbox.extraHomePaths = [
|
||||
"Music"
|
||||
@@ -874,19 +815,16 @@ in
|
||||
soundconverter.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
|
||||
sox.sandbox.method = "bwrap";
|
||||
sox.sandbox.wrapperType = "wrappedDerivation";
|
||||
sox.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
sox.sandbox.whitelistAudio = true;
|
||||
|
||||
space-cadet-pinball.persist.byStore.plaintext = [ ".local/share/SpaceCadetPinball" ];
|
||||
space-cadet-pinball.sandbox.method = "bwrap";
|
||||
space-cadet-pinball.sandbox.wrapperType = "wrappedDerivation";
|
||||
space-cadet-pinball.sandbox.whitelistAudio = true;
|
||||
space-cadet-pinball.sandbox.whitelistDri = true;
|
||||
space-cadet-pinball.sandbox.whitelistWayland = true;
|
||||
|
||||
speedtest-cli.sandbox.method = "bwrap";
|
||||
speedtest-cli.sandbox.wrapperType = "wrappedDerivation";
|
||||
speedtest-cli.sandbox.net = "all";
|
||||
|
||||
sqlite = {};
|
||||
@@ -894,7 +832,6 @@ in
|
||||
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
|
||||
|
||||
subversion.sandbox.method = "bwrap";
|
||||
subversion.sandbox.wrapperType = "wrappedDerivation";
|
||||
subversion.sandbox.net = "clearnet";
|
||||
subversion.sandbox.whitelistPwd = true;
|
||||
sudo.sandbox.enable = false;
|
||||
@@ -906,8 +843,11 @@ in
|
||||
superTux.sandbox.whitelistWayland = true;
|
||||
superTux.persist.byStore.plaintext = [ ".local/share/supertux2" ];
|
||||
|
||||
swappy.sandbox.method = "bwrap";
|
||||
swappy.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
swappy.sandbox.whitelistWayland = true;
|
||||
|
||||
tcpdump.sandbox.method = "landlock";
|
||||
tcpdump.sandbox.wrapperType = "wrappedDerivation";
|
||||
tcpdump.sandbox.net = "all";
|
||||
tcpdump.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
tcpdump.sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||
@@ -917,12 +857,10 @@ in
|
||||
tokodon.persist.byStore.private = [ ".cache/KDE/tokodon" ];
|
||||
|
||||
tree.sandbox.method = "landlock";
|
||||
tree.sandbox.wrapperType = "wrappedDerivation";
|
||||
tree.sandbox.autodetectCliPaths = true;
|
||||
tree.sandbox.whitelistPwd = true;
|
||||
|
||||
tumiki-fighters.sandbox.method = "bwrap";
|
||||
tumiki-fighters.sandbox.wrapperType = "wrappedDerivation";
|
||||
tumiki-fighters.sandbox.whitelistAudio = true;
|
||||
tumiki-fighters.sandbox.whitelistDri = true; #< not strictly necessary, but triples CPU perf
|
||||
tumiki-fighters.sandbox.whitelistWayland = true;
|
||||
@@ -931,34 +869,28 @@ in
|
||||
util-linux.sandbox.enable = false; #< TODO: possible to sandbox if i specific a different profile for each of its ~50 binaries
|
||||
|
||||
unzip.sandbox.method = "bwrap";
|
||||
unzip.sandbox.wrapperType = "wrappedDerivation";
|
||||
unzip.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
unzip.sandbox.whitelistPwd = true;
|
||||
|
||||
usbutils.sandbox.method = "bwrap"; # breaks `usbhid-dump`, but `lsusb`, `usb-devices` work
|
||||
usbutils.sandbox.wrapperType = "wrappedDerivation";
|
||||
usbutils.sandbox.extraPaths = [
|
||||
"/sys/devices"
|
||||
"/sys/bus/usb"
|
||||
];
|
||||
|
||||
visidata.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
visidata.sandbox.wrapperType = "wrappedDerivation";
|
||||
visidata.sandbox.autodetectCliPaths = true;
|
||||
|
||||
# `vulkaninfo`, `vkcube`
|
||||
vulkan-tools.sandbox.method = "landlock";
|
||||
vulkan-tools.sandbox.wrapperType = "wrappedDerivation";
|
||||
|
||||
vvvvvv.sandbox.method = "bwrap";
|
||||
vvvvvv.sandbox.wrapperType = "wrappedDerivation";
|
||||
vvvvvv.sandbox.whitelistAudio = true;
|
||||
vvvvvv.sandbox.whitelistDri = true; #< playable without, but burns noticably more CPU
|
||||
vvvvvv.sandbox.whitelistWayland = true;
|
||||
vvvvvv.persist.byStore.plaintext = [ ".local/share/VVVVVV" ];
|
||||
|
||||
w3m.sandbox.method = "bwrap";
|
||||
w3m.sandbox.wrapperType = "wrappedDerivation";
|
||||
w3m.sandbox.net = "all";
|
||||
w3m.sandbox.extraHomePaths = [
|
||||
# little-used feature, but you can save web pages :)
|
||||
@@ -966,11 +898,9 @@ in
|
||||
];
|
||||
|
||||
wdisplays.sandbox.method = "bwrap";
|
||||
wdisplays.sandbox.wrapperType = "wrappedDerivation";
|
||||
wdisplays.sandbox.whitelistWayland = true;
|
||||
|
||||
wget.sandbox.method = "bwrap";
|
||||
wget.sandbox.wrapperType = "wrappedDerivation";
|
||||
wget.sandbox.net = "all";
|
||||
wget.sandbox.whitelistPwd = true; # saves to pwd by default
|
||||
|
||||
@@ -978,16 +908,13 @@ in
|
||||
|
||||
# `wg`, `wg-quick`
|
||||
wireguard-tools.sandbox.method = "landlock";
|
||||
wireguard-tools.sandbox.wrapperType = "wrappedDerivation";
|
||||
wireguard-tools.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
# provides `iwconfig`, `iwlist`, `iwpriv`, ...
|
||||
wirelesstools.sandbox.method = "landlock";
|
||||
wirelesstools.sandbox.wrapperType = "wrappedDerivation";
|
||||
wirelesstools.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
wl-clipboard.sandbox.method = "bwrap";
|
||||
wl-clipboard.sandbox.wrapperType = "wrappedDerivation";
|
||||
wl-clipboard.sandbox.whitelistWayland = true;
|
||||
|
||||
wtype = {};
|
||||
@@ -998,13 +925,11 @@ in
|
||||
xwayland.sandbox.net = "clearnet"; #< just assuming this is needed (X11 traffic)
|
||||
xwayland.sandbox.whitelistDri = true; #< would assume this gives better gfx perf
|
||||
|
||||
xdg-terminal-exec.sandbox.enable = false; # xdg-terminal-exec is a launcher for $TERM
|
||||
xterm.sandbox.enable = false; # need to be able to do everything
|
||||
|
||||
yarn.persist.byStore.plaintext = [ ".cache/yarn" ];
|
||||
|
||||
yt-dlp.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
yt-dlp.sandbox.wrapperType = "wrappedDerivation";
|
||||
yt-dlp.sandbox.net = "all";
|
||||
yt-dlp.sandbox.whitelistPwd = true; # saves to pwd by default
|
||||
|
||||
|
@@ -10,7 +10,6 @@
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.autodetectCliPaths = true;
|
||||
|
@@ -88,7 +88,6 @@ in
|
||||
{
|
||||
sane.programs.bemenu = {
|
||||
sandbox.method = "bwrap"; # landlock works, but requires *all* of /run/user/$ID to be granted.
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".cache/fontconfig" #< else it complains, and is *way* slower
|
||||
|
216
hosts/common/programs/blast-ugjka/blast-to-default
Executable file
216
hosts/common/programs/blast-ugjka/blast-to-default
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p blast-ugjka
|
||||
# vim: set filetype=python :
|
||||
|
||||
import ctypes
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
|
||||
from enum import Enum
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# map from known devices -> required flags
|
||||
DEVICE_MAP = {
|
||||
"Theater TV": [],
|
||||
"[LG] webOS TV OLED55C9PUA": [ "-usewav" ],
|
||||
}
|
||||
|
||||
def set_pdeathsig(sig=signal.SIGTERM):
|
||||
"""
|
||||
helper function to ensure once parent process exits, its children processes will automatically die.
|
||||
see: <https://stackoverflow.com/a/43152455>
|
||||
see: <https://www.man7.org/linux/man-pages/man2/prctl.2.html>
|
||||
"""
|
||||
libc = ctypes.CDLL("libc.so.6")
|
||||
return libc.prctl(1, sig)
|
||||
|
||||
MY_PID = None
|
||||
|
||||
def reap_children(sig=None, frame=None):
|
||||
global MY_PID
|
||||
# reset SIGTERM handler to avoid recursing
|
||||
signal.signal(signal.SIGTERM, signal.Handlers.SIG_DFL)
|
||||
logger.info("killing all children (of pid %d)", MY_PID)
|
||||
os.killpg(MY_PID, signal.SIGTERM)
|
||||
|
||||
def reap_on_exit():
|
||||
"""
|
||||
catch when the parent exits, and map that to SIGTERM for this process.
|
||||
when this process receives SIGTERM, also terminate all descendent processes.
|
||||
|
||||
this is done because:
|
||||
1. mpv invokes this, but (potentially) via the sandbox wrapper.
|
||||
2. when mpv exits, it `SIGKILL`s that sandbox wrapper.
|
||||
3. bwrap does not pass SIGKILL or SIGTERM to its child.
|
||||
4. hence, we neither receive that signal NOR can we pass it on simply by killing our immediate children
|
||||
(since any bwrap'd children wouldn't pass that signal on...)
|
||||
really, the proper fix would be on mpv's side:
|
||||
- mpv should create a new process group when it launches a command, and kill that process group on exit.
|
||||
or fix this in the sandbox wrapper:
|
||||
- why *doesn't* bwrap forward the signals?
|
||||
- there's --die-with-parent, but i can't apply that *system wide* and expect reasonably behavior
|
||||
<https://github.com/containers/bubblewrap/issues/529>
|
||||
"""
|
||||
global MY_PID
|
||||
MY_PID = os.getpid()
|
||||
# create a new process group, pgid = gid
|
||||
os.setpgid(MY_PID, MY_PID)
|
||||
|
||||
set_pdeathsig(signal.SIGTERM)
|
||||
signal.signal(signal.SIGTERM, reap_children)
|
||||
|
||||
def get_ranked_ip_addrs():
|
||||
"""
|
||||
return the IP addresses most likely to be LAN addresses
|
||||
based on: <https://stackoverflow.com/a/1267524>
|
||||
"""
|
||||
_name, _aliases, static_addrs = socket.gethostbyname_ex(socket.gethostname())
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(("1", 53))
|
||||
con_addr, _port = s.getsockname()
|
||||
return sorted(set(static_addrs + [ con_addr ]), key=lambda a: (a.startswith("127"), a))
|
||||
|
||||
|
||||
class ParserState(Enum):
|
||||
Break = "break"
|
||||
Receiver = "receiver"
|
||||
Ips = "ip"
|
||||
|
||||
class Status(Enum):
|
||||
Continue = "continue"
|
||||
Error = "error"
|
||||
RedoWithFlags = "redo_with_flags"
|
||||
Launched = "launched"
|
||||
|
||||
class BlastDriver:
|
||||
parsing: ParserState | None = None
|
||||
last_write: str | None = None
|
||||
def __init__(self, blast_flags: list[str] = []):
|
||||
self.ranked_ips = get_ranked_ip_addrs()
|
||||
self.blast = subprocess.Popen(
|
||||
["blast", "-source", "blast.monitor"] + blast_flags,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
# this pdeathsig isn't necessary; seems it might result in leaked pulse outputs
|
||||
# preexec_fn=set_pdeathsig
|
||||
)
|
||||
self.blast_flags = list(blast_flags)
|
||||
self.receiver_names = []
|
||||
self.ips = []
|
||||
|
||||
def writeline(self, line: str) -> None:
|
||||
logger.debug("[send] %s", line)
|
||||
self.blast.stdin.write(f"{line}\n".encode())
|
||||
self.blast.stdin.flush()
|
||||
self.last_write = line
|
||||
|
||||
def readline(self) -> str:
|
||||
line = self.blast.stdout.readline().decode('utf-8').strip()
|
||||
line = line.replace('\x1b[1A\x1b[K', '') #< escape codes
|
||||
logger.debug("[recv] %r", line)
|
||||
return line
|
||||
|
||||
def set_state(self, state: ParserState):
|
||||
logger.debug("[pars] %s", state)
|
||||
self.parsing = state
|
||||
|
||||
def feedline(self, line: str) -> (Status, str|None):
|
||||
"""
|
||||
apply a line from blast's stdout to modify parser state.
|
||||
returns a status code (e.g. Status.Continue), and optionally a reply to send back to blast.
|
||||
"""
|
||||
if line == "Loading...":
|
||||
return Status.Continue, None
|
||||
elif line == "----------":
|
||||
self.set_state(ParserState.Break)
|
||||
return Status.Continue, None
|
||||
elif line == "DLNA receivers":
|
||||
self.set_state(ParserState.Receiver)
|
||||
return Status.Continue, None
|
||||
elif line == "Your LAN ip addresses":
|
||||
self.set_state(ParserState.Ips)
|
||||
return Status.Continue, None
|
||||
elif line == "Select the DLNA device:":
|
||||
assert len(self.receiver_names) == 1, self.receiver_names
|
||||
name = self.receiver_names[0]
|
||||
if name in DEVICE_MAP and DEVICE_MAP[name] != self.blast_flags:
|
||||
return Status.RedoWithFlags, None
|
||||
return Status.Continue, "0"
|
||||
elif line == "Select the lan IP address for the stream:":
|
||||
for r in self.ranked_ips:
|
||||
if r in self.ips:
|
||||
return Status.Launched, str(self.ips.index(r))
|
||||
# fallback: just guess the best IP
|
||||
return Status.Launched, "0"
|
||||
elif self.parsing == ParserState.Receiver:
|
||||
id_, name = line.split(": ")
|
||||
assert id_ == str(len(self.receiver_names)), (id_, self.receiver_names)
|
||||
self.receiver_names.append(name)
|
||||
return Status.Continue, None
|
||||
elif self.parsing == ParserState.Ips:
|
||||
id_, ip = line.split(": ")
|
||||
assert id_ == str(len(self.ips)), (id_, self.ips)
|
||||
self.ips.append(ip)
|
||||
return Status.Continue, None
|
||||
elif line == f"[{self.last_write}]":
|
||||
# it's echoing to us what we wrote
|
||||
return Status.Continue, None
|
||||
# elif line == "":
|
||||
# return Status.Continue, None
|
||||
else:
|
||||
logger.info("unrecognized output (state=%s): %r", self.parsing, line)
|
||||
return Status.Error, None
|
||||
|
||||
def step(self) -> Status:
|
||||
"""
|
||||
advance the interaction between us and blast.
|
||||
reads a line from blast, modifies internal state, maybe sends a reply.
|
||||
could block indefinitely.
|
||||
"""
|
||||
line = self.readline()
|
||||
status, reply = self.feedline(line)
|
||||
if reply is not None:
|
||||
self.writeline(reply)
|
||||
return status
|
||||
|
||||
def try_blast(*args, **kwargs) -> BlastDriver | None:
|
||||
blast = BlastDriver(*args, **kwargs)
|
||||
status = Status.Continue
|
||||
while status == Status.Continue:
|
||||
status = blast.step()
|
||||
|
||||
if status == Status.RedoWithFlags:
|
||||
dev = blast.receiver_names[0]
|
||||
blast_flags = DEVICE_MAP[dev]
|
||||
logger.info("re-exec blast for %s with flags: %r", dev, blast_flags)
|
||||
blast.blast.terminate()
|
||||
return try_blast(blast_flags=blast_flags)
|
||||
elif status == Status.Error:
|
||||
logger.info("blast error => terminating")
|
||||
blast.blast.terminate()
|
||||
else:
|
||||
# successfully launched
|
||||
return blast
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig()
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
reap_on_exit()
|
||||
|
||||
blast = try_blast()
|
||||
|
||||
if blast is not None:
|
||||
logger.info("waiting until blast exits")
|
||||
blast.blast.wait()
|
||||
|
||||
reap_children()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
51
hosts/common/programs/blast-ugjka/default.nix
Normal file
51
hosts/common/programs/blast-ugjka/default.nix
Normal file
@@ -0,0 +1,51 @@
|
||||
# blast: tunnel audio from a pulseaudio sink to a UPnP/DLNA device (like a TV).
|
||||
# - expect 7s of latency
|
||||
# - can cast the default sink, or create a new one "blast.monitor"
|
||||
# and either assign that to default or assign apps to it.
|
||||
# compatibility:
|
||||
# - there is no single invocation which will be compatible with all known devices.
|
||||
# - sony tv:
|
||||
# - `blast` (default): WORKS
|
||||
# - `-usewav`: FAILS
|
||||
# - LG TV:
|
||||
# - `-usewav`: WORKS!
|
||||
# - `-useaac`: FAILS
|
||||
# - `-useflac`: FAILS
|
||||
# - `-uselpcm`: FAILS
|
||||
# - `-uselpcmle`: FAILS
|
||||
# - `-format aac`: FAILS
|
||||
# - `-bitrate 128`: FAILS
|
||||
# - `-nochunked`: FAILS
|
||||
# - `-format "ogg" -mime 'audio/x-opus+ogg'`: FAILS
|
||||
# - `-mime audio/ac3 -format ac3`: FAILS
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.blast-ugjka;
|
||||
in
|
||||
{
|
||||
sane.programs.blast-ugjka = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.net = "clearnet";
|
||||
};
|
||||
|
||||
sane.programs.blast-to-default = {
|
||||
# helper to deal with blast's interactive CLI
|
||||
packageUnwrapped = pkgs.static-nix-shell.mkPython3Bin {
|
||||
pname = "blast-to-default";
|
||||
pkgs = [ "blast-ugjka" ];
|
||||
srcRoot = ./.;
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.extraConfig = [
|
||||
# else it fails to reap its children (or, maybe, it fails to hook its parent's death signal?)
|
||||
# might be possible to remove this, but kinda hard to see a clean way.
|
||||
"--sane-sandbox-keep-namespace" "pid"
|
||||
];
|
||||
suggestedPrograms = [ "blast-ugjka" ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enabled [ 9000 ];
|
||||
}
|
@@ -111,6 +111,11 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraRuntimePaths = [
|
||||
"/" #< just needs "bonsai", but needs to create it first...
|
||||
];
|
||||
|
||||
services.bonsaid = {
|
||||
description = "bonsai: programmable input dispatcher";
|
||||
after = [ "graphical-session.target" ];
|
||||
|
17
hosts/common/programs/celeste64.nix
Normal file
17
hosts/common/programs/celeste64.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.celeste64 = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraPaths = [
|
||||
"/dev/input" #< for controllers
|
||||
];
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
# save data, controls map
|
||||
".local/share/Celeste64"
|
||||
];
|
||||
};
|
||||
}
|
@@ -1,9 +1,19 @@
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
sane.programs.cozy = {
|
||||
packageUnwrapped = pkgs.cozy.overrideAttrs (upstream: {
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
# disable all reporting.
|
||||
# this can be done via the settings, but that's troublesome and easy to forget.
|
||||
# specifically, i don't want moby to be making these network requests several times per hour
|
||||
# while it might be roaming or trying to put the RF to sleep.
|
||||
substituteInPlace cozy/application_settings.py \
|
||||
--replace-fail 'self._settings.get_int("report-level")' '0'
|
||||
'';
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap"; # landlock gives: _multiprocessing.SemLock: Permission Denied
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -9,17 +9,47 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.dconf = {
|
||||
configOption = with lib; mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
site = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [];
|
||||
description = ''
|
||||
extra packages to link into /etc/dconf
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
|
||||
packageUnwrapped = pkgs.rmDbusServicesInPlace pkgs.dconf;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.wrapperType = "inplace"; #< dbus/systemd services live in `.out` but point to `.lib` data.
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
persist.byStore.private = [
|
||||
".config/dconf"
|
||||
];
|
||||
};
|
||||
|
||||
programs.dconf = lib.mkIf cfg.enabled {
|
||||
# note that `programs.dconf` doesn't allow specifying the dconf package.
|
||||
enable = true;
|
||||
packages = [
|
||||
services.dconf = {
|
||||
description = "dconf configuration database/server";
|
||||
after = [ "graphical-session.target" ];
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${lib.getLib cfg.package}/libexec/dconf-service";
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
};
|
||||
};
|
||||
|
||||
# supposedly necessary for packages which haven't been wrapped (i.e. wrapGtkApp?),
|
||||
# but in practice seems unnecessary.
|
||||
# env.GIO_EXTRA_MODULES = "${pkgs.dconf.lib}/lib/gio/modules";
|
||||
|
||||
config.site = [
|
||||
(pkgs.writeTextFile {
|
||||
name = "dconf-user-profile";
|
||||
destination = "/etc/dconf/profile/user";
|
||||
@@ -30,4 +60,18 @@ in
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
# TODO: get dconf to read these from ~/.config/dconf ?
|
||||
environment.etc.dconf = lib.mkIf cfg.enabled {
|
||||
source = pkgs.symlinkJoin {
|
||||
name = "dconf-system-config";
|
||||
paths = map (x: "${x}/etc/dconf") cfg.config.site;
|
||||
nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
|
||||
postBuild = ''
|
||||
if test -d $out/db; then
|
||||
dconf update $out/db
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
139
hosts/common/programs/deadd-notification-center/deadd.css
Normal file
139
hosts/common/programs/deadd-notification-center/deadd.css
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
/* Notification center */
|
||||
|
||||
.blurredBG, #main_window, .blurredBG.low, .blurredBG.normal {
|
||||
background: rgba(255, 255, 255, 1.0);
|
||||
}
|
||||
|
||||
.noti-center.time {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
|
||||
.notification.content {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.appname {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.blurredBG.notification {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.blurredBG.notification.critical {
|
||||
background: rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.notificationInCenter.critical {
|
||||
background: rgba(155, 0, 20, 0.5);
|
||||
}
|
||||
|
||||
/* Labels */
|
||||
|
||||
label {
|
||||
color: #322;
|
||||
}
|
||||
|
||||
label.notification {
|
||||
color: #322;
|
||||
}
|
||||
|
||||
label.critical {
|
||||
color: #000;
|
||||
}
|
||||
.notificationInCenter label.critical {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
/* Buttons */
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
color: #322;
|
||||
border-radius: 3px;
|
||||
border-width: 0px;
|
||||
background-position: 0px 0px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-radius: 3px;
|
||||
background: rgba(0, 20, 20, 0.2);
|
||||
border-width: 0px;
|
||||
border-top: transparent;
|
||||
border-color: #f00;
|
||||
color: #fee;
|
||||
}
|
||||
|
||||
|
||||
/* Custom Buttons */
|
||||
|
||||
.userbutton {
|
||||
background: rgba(20,0,0, 0.15);
|
||||
}
|
||||
|
||||
.userbuttonlabel {
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.userbutton:hover {
|
||||
background: rgba(20, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.userbuttonlabel:hover {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
button.buttonState1 {
|
||||
background: rgba(20,0,0,0.5);
|
||||
}
|
||||
|
||||
.userbuttonlabel.buttonState1 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
button.buttonState1:hover {
|
||||
background: rgba(20,0,0, 0.4);
|
||||
}
|
||||
|
||||
.userbuttonlabel.buttonState1:hover {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
button.buttonState2 {
|
||||
background: rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
.userbuttonlabel.buttonState2 {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
button.buttonState2:hover {
|
||||
background: rgba(20,0,0, 0.3);
|
||||
}
|
||||
|
||||
.userbuttonlabel.buttonState2:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
/* Images */
|
||||
|
||||
image.deadd-noti-center.notification.image {
|
||||
margin-left: 20px;
|
||||
}
|
263
hosts/common/programs/deadd-notification-center/deadd.yml
Normal file
263
hosts/common/programs/deadd-notification-center/deadd.yml
Normal file
@@ -0,0 +1,263 @@
|
||||
### Margins for notification-center/notifications
|
||||
margin-top: 0
|
||||
margin-right: 0
|
||||
|
||||
### Margins for notification-center
|
||||
margin-bottom: 0
|
||||
|
||||
### Width of the notification center/notifications in pixels.
|
||||
width: 360
|
||||
|
||||
### Command to run at startup. This can be used to setup
|
||||
### button states.
|
||||
# startup-command: deadd-notification-center-startup
|
||||
|
||||
### Monitor on which the notification center/notifications will be
|
||||
### printed. If "follow-mouse" is set true, this does nothing.
|
||||
monitor: 0
|
||||
|
||||
### If true, the notification center/notifications will open on the
|
||||
### screen, on which the mouse is. Overrides the "monitor" setting.
|
||||
follow-mouse: false
|
||||
|
||||
notification-center:
|
||||
### Margin at the top/right/bottom of the notification center in
|
||||
### pixels. This can be used to avoid overlap between the notification
|
||||
### center and bars such as polybar or i3blocks.
|
||||
margin-top: 40
|
||||
# margin-right: 0
|
||||
# margin-bottom: 0
|
||||
|
||||
### Width of the notification center in pixels.
|
||||
# width: 500
|
||||
|
||||
### Monitor on which the notification center will be printed. If
|
||||
### "follow-mouse" is set true, this does nothing.
|
||||
# monitor: 0
|
||||
|
||||
### If true, the notification center will open on the screen, on which
|
||||
### the mouse is. Overrides the "monitor" setting.
|
||||
# follow-mouse: false
|
||||
|
||||
### Notification center closes when the mouse leaves it
|
||||
hide-on-mouse-leave: true
|
||||
|
||||
### If newFirst is set to true, newest notifications appear on the top
|
||||
### of the notification center. Else, notifications stack, from top to
|
||||
### bottom.
|
||||
new-first: true
|
||||
|
||||
### If true, the transient field in notifications will be ignored,
|
||||
### thus the notification will be persisted in the notification
|
||||
### center anyways
|
||||
ignore-transient: false
|
||||
|
||||
### Custom buttons in notification center
|
||||
buttons:
|
||||
### Numbers of buttons that can be drawn on a row of the notification
|
||||
### center.
|
||||
# buttons-per-row: 5
|
||||
|
||||
### Height of buttons in the notification center (in pixels).
|
||||
# buttons-height: 60
|
||||
|
||||
### Horizontal and vertical margin between each button in the
|
||||
### notification center (in pixels).
|
||||
# buttons-margin: 2
|
||||
|
||||
### Button actions and labels. For each button you must specify a
|
||||
### label and a command.
|
||||
actions:
|
||||
# - label: VPN
|
||||
# command: "sudo vpnToggle"
|
||||
# - label: Bluetooth
|
||||
# command: bluetoothToggle
|
||||
# - label: Wifi
|
||||
# command: wifiToggle
|
||||
# - label: Screensaver
|
||||
# command: screensaverToggle
|
||||
# - label: Keyboard
|
||||
# command: keyboardToggle
|
||||
|
||||
notification:
|
||||
### If true, markup (<u>, <i>, <b>, <a>) will be displayed properly
|
||||
use-markup: true
|
||||
|
||||
### If true, html entities (& for &, % for %, etc) will be
|
||||
### parsed properly. This is useful for chromium-based apps, which
|
||||
### tend to send these in notifications.
|
||||
parse-html-entities: true
|
||||
|
||||
dbus:
|
||||
|
||||
### If noti-closed messages are enabled, the sending application
|
||||
### will know that a notification was closed/timed out. This can
|
||||
### be an issue for certain applications, that overwrite
|
||||
### notifications on status updates (e.g. Spotify on each
|
||||
### song). When one of these applications thinks, the notification
|
||||
### has been closed/timed out, they will not overwrite existing
|
||||
### notifications but send new ones. This can lead to redundant
|
||||
### notifications in the notification center, as the close-message
|
||||
### is send regardless of the notification being persisted.
|
||||
send-noti-closed: false
|
||||
|
||||
app-icon:
|
||||
|
||||
### If set to true: If no icon is passed by the app_icon parameter
|
||||
### and no application "desktop-entry"-hint is present, deadd will
|
||||
### try to guess the icon from the application name (if present).
|
||||
guess-icon-from-name: true
|
||||
|
||||
### The display size of the application icons in the notification
|
||||
### pop-ups and in the notification center
|
||||
icon-size: 20
|
||||
|
||||
image:
|
||||
|
||||
### The maximal display size of images that are part of
|
||||
### notifications for notification pop-ups and in the notification
|
||||
### center
|
||||
size: 100
|
||||
|
||||
### The margin around the top, bottom, left, and right of
|
||||
### notification images.
|
||||
margin-top: 15
|
||||
margin-bottom: 15
|
||||
margin-left: 15
|
||||
margin-right: 0
|
||||
|
||||
### Apply modifications to certain notifications:
|
||||
### Each modification rule needs a "match" and either a "modify" or
|
||||
### a "script" entry.
|
||||
modifications:
|
||||
### Match:
|
||||
### Matches the notifications against these rules. If all of the
|
||||
### values (of one modification rule) match, the "modify"/"script"
|
||||
### part is applied.
|
||||
# - match:
|
||||
### Possible match criteria:
|
||||
# title: "Notification title"
|
||||
# body: "Notification body"
|
||||
# time: "12:44"
|
||||
# app-name: "App name"
|
||||
# urgency: "low" # "low", "normal" or "critical"
|
||||
|
||||
# modify:
|
||||
### Possible modifications
|
||||
# title: "abc"
|
||||
# body: "abc"
|
||||
# app-name: "abc"
|
||||
# app-icon: "file:///abc.png"
|
||||
### The timeout has three special values:
|
||||
### timeout: 0 -> don't time out at all
|
||||
### timeout: -1 -> use default timeout
|
||||
### timeout: 1 -> don't show as pop-up
|
||||
### timeout: >1 -> milliseconds until timeout
|
||||
# timeout: 1
|
||||
# margin-right: 10
|
||||
# margin-top: 10
|
||||
# image: "file:///abc.png"
|
||||
# image-size: 10
|
||||
# transient: true
|
||||
# send-noti-closed: false
|
||||
### Remove action buttons from notifications
|
||||
# remove-actions: true
|
||||
### Set the action-icons hint to true, action labels will then
|
||||
### be intergreted as GTK icon names
|
||||
# action-icons: true
|
||||
### List of actions, where the even elements (0, 2, ...) are the
|
||||
### action name and the odd elements are the label
|
||||
# actions:
|
||||
# - previous
|
||||
# - media-skip-backward
|
||||
# - play
|
||||
# - media-playback-start
|
||||
# - next
|
||||
# - media-skip-forward
|
||||
### Action commands, where the keys (e.g. "play") is the action
|
||||
### name and the value is a program call that should be executed
|
||||
### on action. Prevents sending of the action to the application.
|
||||
# action-commands:
|
||||
# play: playerctl play-pause
|
||||
# previous: playerctl previous
|
||||
# next: playerctl next
|
||||
|
||||
### Add a class-name to the notification container, that can be
|
||||
### used for specific styling of notifications using the
|
||||
### deadd.css file
|
||||
# class-name: "abc"
|
||||
|
||||
# - match:
|
||||
# app-name: "Chromium"
|
||||
|
||||
### Instead of modifying a notification directly, a script can be
|
||||
### run, which will receive the notification as JSON on STDIN. It
|
||||
### is expected to return JSON/YAML configuration that defines the
|
||||
### modifications that should be applied. Minimum complete return
|
||||
### value must be '{"modify": {}, "match": {}}'. Always leave the "match"
|
||||
### object empty (technical reasons, i.e. I am lazy).
|
||||
# script: "linux-notification-center-parse-chromium"
|
||||
- match:
|
||||
app-name: "Spotify"
|
||||
modify:
|
||||
image-size: 80
|
||||
timeout: 1
|
||||
send-noti-closed: true
|
||||
class-name: "Spotify"
|
||||
action-icons: true
|
||||
actions:
|
||||
- previous
|
||||
- media-skip-backward
|
||||
- play
|
||||
- media-playback-start
|
||||
- next
|
||||
- media-skip-forward
|
||||
action-commands:
|
||||
play: playerctl play-pause
|
||||
previous: playerctl previous
|
||||
next: playerctl next
|
||||
|
||||
# - match:
|
||||
# title: Bildschirmhelligkeit
|
||||
# modify:
|
||||
# image-size: 60
|
||||
popup:
|
||||
|
||||
### Default timeout used for notifications in milli-seconds. This can
|
||||
### be overwritten with the "-t" option (or "--expire-time") of the
|
||||
### notify-send command.
|
||||
default-timeout: 10000
|
||||
|
||||
### Margin above/right/between notifications (in pixels). This can
|
||||
### be used to avoid overlap between notifications and a bar such as
|
||||
### polybar or i3blocks.
|
||||
margin-top: 50
|
||||
margin-right: 50
|
||||
margin-between: 20
|
||||
|
||||
### Defines after how many lines of text the body will be truncated.
|
||||
### Use 0 if you want to disable truncation.
|
||||
max-lines-in-body: 3
|
||||
|
||||
### Determines whether the GTK widget that displays the notification body
|
||||
### in the notification popup will be hidden when empty. This is especially
|
||||
### useful for transient notifications that display a progress bar.
|
||||
# hide-body-if-empty: false
|
||||
|
||||
### Monitor on which the notifications will be
|
||||
### printed. If "follow-mouse" is set true, this does nothing.
|
||||
# monitor: 0
|
||||
|
||||
### If true, the notifications will open on the
|
||||
### screen, on which the mouse is. Overrides the "monitor" setting.
|
||||
# follow-mouse: false
|
||||
|
||||
click-behavior:
|
||||
|
||||
### The mouse button for dismissing a popup. Must be either "mouse1",
|
||||
### "mouse2", "mouse3", "mouse4", or "mouse5"
|
||||
dismiss: mouse1
|
||||
|
||||
### The mouse button for opening a popup with the default action.
|
||||
### Must be either "mouse1", "mouse2", "mouse3", "mouse4", or "mouse5"
|
||||
default-action: mouse3
|
17
hosts/common/programs/deadd-notification-center/default.nix
Normal file
17
hosts/common/programs/deadd-notification-center/default.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
# docs are via README only:
|
||||
# - <https://github.com/phuhl/linux_notification_center>
|
||||
# reload config:
|
||||
# - `notify-send a --hint=boolean:deadd-notification-center:true --hint=string:type:reloadStyle`
|
||||
# toggle visibility:
|
||||
# - `kill -s USR1 $(pidof deadd-notification-center)`
|
||||
# clear notifications:
|
||||
# - `notify-send a --hint=boolean:deadd-notification-center:true --hint=string:type:clearInCenter`
|
||||
# set state of user button 0 to "highlighted" (true)
|
||||
# - `notify-send a --hint=boolean:deadd-notification-center:true --hint=int:id:0 --hint=boolean:state:true --hint=type:string:buttons`
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.deadd-notification-center = {
|
||||
fs.".config/deadd/deadd.css".symlink.target = ./deadd.css;
|
||||
fs.".config/deadd/deadd.yml".symlink.target = ./deadd.yml;
|
||||
};
|
||||
}
|
@@ -5,25 +5,31 @@
|
||||
./abaddon.nix
|
||||
./aerc.nix
|
||||
./alacritty.nix
|
||||
./alsa-ucm-conf
|
||||
./animatch.nix
|
||||
./assorted.nix
|
||||
./audacity.nix
|
||||
./bemenu.nix
|
||||
./blast-ugjka
|
||||
./bonsai.nix
|
||||
./brave.nix
|
||||
./bubblewrap.nix
|
||||
./calls.nix
|
||||
./cantata.nix
|
||||
./catt.nix
|
||||
./celeste64.nix
|
||||
./chatty.nix
|
||||
./conky
|
||||
./cozy.nix
|
||||
./dconf.nix
|
||||
./deadd-notification-center
|
||||
./dialect.nix
|
||||
./dino.nix
|
||||
./dissent.nix
|
||||
./element-desktop.nix
|
||||
./epiphany.nix
|
||||
./evince.nix
|
||||
./fcitx5.nix
|
||||
./feedbackd.nix
|
||||
./firefox.nix
|
||||
./firejail.nix
|
||||
@@ -45,7 +51,6 @@
|
||||
./gpodder.nix
|
||||
./grimshot.nix
|
||||
./gthumb.nix
|
||||
./gtkcord4.nix
|
||||
./handbrake.nix
|
||||
./helix.nix
|
||||
./imagemagick.nix
|
||||
@@ -53,6 +58,7 @@
|
||||
./kdenlive.nix
|
||||
./komikku.nix
|
||||
./koreader
|
||||
./less.nix
|
||||
./libreoffice.nix
|
||||
./lemoa.nix
|
||||
./loupe.nix
|
||||
@@ -61,7 +67,7 @@
|
||||
./mepo.nix
|
||||
./mimeo
|
||||
./mopidy.nix
|
||||
./mpv.nix
|
||||
./mpv
|
||||
./msmtp.nix
|
||||
./nautilus.nix
|
||||
./neovim.nix
|
||||
@@ -81,7 +87,10 @@
|
||||
./rhythmbox.nix
|
||||
./ripgrep.nix
|
||||
./rofi
|
||||
./sane-input-handler
|
||||
./sane-screenshot.nix
|
||||
./sane-scripts.nix
|
||||
./schlock.nix
|
||||
./sfeed.nix
|
||||
./signal-desktop.nix
|
||||
./splatmoji.nix
|
||||
@@ -94,8 +103,10 @@
|
||||
./supertuxkart.nix
|
||||
./sway
|
||||
./sway-autoscaler
|
||||
./swayidle.nix
|
||||
./swaylock.nix
|
||||
./swaynotificationcenter.nix
|
||||
./swaynotificationcenter
|
||||
./sysvol.nix
|
||||
./tangram.nix
|
||||
./tor-browser.nix
|
||||
./tuba.nix
|
||||
@@ -108,19 +119,19 @@
|
||||
./wireplumber.nix
|
||||
./wireshark.nix
|
||||
./wob
|
||||
./wvkbd.nix
|
||||
./xarchiver.nix
|
||||
./xdg-desktop-portal.nix
|
||||
./xdg-desktop-portal-gtk.nix
|
||||
./xdg-desktop-portal-wlr.nix
|
||||
./xdg-terminal-exec.nix
|
||||
./xdg-utils.nix
|
||||
./zathura.nix
|
||||
./zeal.nix
|
||||
./zecwallet-lite.nix
|
||||
./zsh
|
||||
];
|
||||
|
||||
config = {
|
||||
# XXX: this might not be necessary. try removing this and cacert.unbundled (servo)?
|
||||
environment.etc."ssl/certs".source = "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
|
||||
|
||||
};
|
||||
# XXX: this might not be necessary. try removing this and cacert.unbundled (servo)?
|
||||
environment.etc."ssl/certs".source = "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
|
||||
}
|
||||
|
@@ -5,6 +5,9 @@
|
||||
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.extraHomePaths = [
|
||||
".config/dconf" # won't start without it
|
||||
];
|
||||
suggestedPrograms = [ "dconf" ]; #< to persist settings
|
||||
|
||||
packageUnwrapped = pkgs.dialect.overrideAttrs (upstream: {
|
||||
|
@@ -46,7 +46,6 @@ in
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
|
@@ -3,10 +3,10 @@
|
||||
# - notification sounds can be handled by swaync
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.gtkcord4;
|
||||
cfg = config.sane.programs.dissent;
|
||||
in
|
||||
{
|
||||
sane.programs.gtkcord4 = {
|
||||
sane.programs.dissent = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
@@ -17,22 +17,21 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
packageUnwrapped = pkgs.gtkcord4.overrideAttrs (upstream: {
|
||||
packageUnwrapped = pkgs.dissent.overrideAttrs (upstream: {
|
||||
postConfigure = (upstream.postConfigure or "") + ''
|
||||
# gtkcord4 uses go-keyring to interface with the org.freedesktop.secrets provider (i.e. gnome-keyring).
|
||||
# dissent uses go-keyring to interface with the org.freedesktop.secrets provider (i.e. gnome-keyring).
|
||||
# go-keyring hardcodes `login.keyring` as the keyring to store secrets in, instead of reading `~/.local/share/keyring/default`.
|
||||
# `login.keyring` seems to be a special keyring preconfigured (by gnome-keyring) to encrypt everything to the user's password.
|
||||
# that's redundant with my fs-level encryption and makes the keyring less inspectable,
|
||||
# so patch gtkcord4 to use Default_keyring instead.
|
||||
# so patch dissent to use Default_keyring instead.
|
||||
# see:
|
||||
# - <https://github.com/diamondburned/gtkcord4/issues/139>
|
||||
# - <https://github.com/diamondburned/dissent/issues/139>
|
||||
# - <https://github.com/zalando/go-keyring/issues/46>
|
||||
substituteInPlace vendor/github.com/zalando/go-keyring/secret_service/secret_service.go \
|
||||
--replace '"login"' '"Default_keyring"'
|
||||
'';
|
||||
});
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
@@ -52,18 +51,17 @@ in
|
||||
];
|
||||
|
||||
persist.byStore.private = [
|
||||
".cache/gtkcord4"
|
||||
".config/gtkcord4" # empty?
|
||||
".cache/dissent"
|
||||
".config/dissent" # empty?
|
||||
];
|
||||
|
||||
services.gtkcord4 = {
|
||||
description = "gtkcord4 Discord client";
|
||||
services.dissent = {
|
||||
description = "dissent Discord client";
|
||||
after = [ "graphical-session.target" ];
|
||||
# partOf = [ "graphical-session.target" ];
|
||||
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/gtkcord4";
|
||||
ExecStart = "${cfg.package}/bin/dissent";
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "20s";
|
@@ -17,7 +17,6 @@
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
|
@@ -12,11 +12,13 @@
|
||||
sandbox.wrapperType = "inplace"; # /share/epiphany/default-bookmarks.rdf refers back to /share; dbus files to /libexec
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< silently fails to start without it.
|
||||
# default sandboxing breaks rendering in weird ways. sites are super zoomed in / not scaled.
|
||||
# enabling DRI/DRM (as below) seems to fix that.
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".config/dconf" # else will always prompt "make default browser?"
|
||||
".config/epiphany" #< else it gets angry at launch
|
||||
"tmp"
|
||||
];
|
||||
|
123
hosts/common/programs/fcitx5.nix
Normal file
123
hosts/common/programs/fcitx5.nix
Normal file
@@ -0,0 +1,123 @@
|
||||
# fcitx5 is an "input method", to e.g. allow typing CJK on qwerty.
|
||||
# but i also misuse it to allow typing emoji on qwerty:
|
||||
# - press `Super+backtick`
|
||||
# - type something like "effort"
|
||||
# - it should be underlined, at the least
|
||||
# - if well supported (e.g. Firefox; also gtk4, alacritty on sway 1.10+), a drop-down fuzzy matcher will appear
|
||||
# - press space
|
||||
# - "effort" should be replaced by `(ง •̀_•́)ง`
|
||||
#
|
||||
## debugging
|
||||
# - `fcitx5-diagnose`
|
||||
#
|
||||
## config/docs:
|
||||
# - `fcitx5-configtool`, then check ~/.config/fcitx5 files
|
||||
# - <https://fcitx-im.org/wiki/Fcitx_5>
|
||||
# - <https://wiki.archlinux.org/title/Fcitx5>
|
||||
# - theming: <https://wiki.archlinux.org/title/Fcitx5#Themes_and_appearance>
|
||||
# - <https://en.wikipedia.org/wiki/Fcitx>
|
||||
# - wayland specifics: <https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland>
|
||||
# - quickphrase (emoji): <https://fcitx-im.org/wiki/QuickPhrase>
|
||||
# - override phrases via `~/.config/fcitx/data/QuickPhrase.mb`
|
||||
# - customize bindings via `fcitx5-configtool` > addons > QuickPhrase
|
||||
# - theming:
|
||||
# - nixpkgs has a few themes: `fcitx5-{material-color,nord,rose-pine}`
|
||||
# - NUR has a few themes
|
||||
# - <https://github.com/catppuccin/fcitx5>
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.fcitx5;
|
||||
in
|
||||
{
|
||||
sane.programs.fcitx5 = {
|
||||
packageUnwrapped = pkgs.fcitx5-with-addons.override {
|
||||
addons = with pkgs; [
|
||||
# fcitx5-mozc # japanese input: <https://github.com/fcitx/mozc>
|
||||
fcitx5-gtk # <https://github.com/fcitx/fcitx5-gtk>
|
||||
];
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.whitelistWayland = true; # for `fcitx5-configtool, if nothing else`
|
||||
sandbox.extraHomePaths = [
|
||||
# ".config/fcitx"
|
||||
".config/fcitx5"
|
||||
".local/share/fcitx5"
|
||||
];
|
||||
|
||||
fs.".config/fcitx5/conf/quickphrase.conf".symlink.text = ''
|
||||
# Choose key modifier
|
||||
Choose Modifier=None
|
||||
# Enable Spell check
|
||||
Spell=True
|
||||
FallbackSpellLanguage=en
|
||||
|
||||
[TriggerKey]
|
||||
# defaults: Super+grave, Super+semicolon
|
||||
# gtk apps use ctrl+period, so super+period is a nice complement
|
||||
0=Super+grave
|
||||
1=Super+semicolon
|
||||
2=Super+period
|
||||
'';
|
||||
fs.".config/fcitx5/conf/classicui.conf".symlink.text = ''
|
||||
Theme=sane
|
||||
Font="Sans 20"
|
||||
Vertical Candidate List=True
|
||||
'';
|
||||
fs.".local/share/fcitx5/themes/sane/theme.conf".symlink.text = ''
|
||||
# i omit several keys, especially the ones which don't seem to do much.
|
||||
# for a theme which uses many more options, see:
|
||||
# - <https://github.com/catppuccin/fcitx5/blob/main/src/catppuccin-mocha/theme.conf>
|
||||
[Metadata]
|
||||
Name=sane
|
||||
ScaleWithDPI=True
|
||||
|
||||
[InputPanel]
|
||||
NormalColor=#d8d8d8
|
||||
HighlightCandidateColor=#FFFFFF
|
||||
HighlightColor=#FFFFFF
|
||||
HighlightBackgroundColor=#1f5e54
|
||||
|
||||
[InputPanel/Background]
|
||||
Color=#1f5e54
|
||||
|
||||
[InputPanel/Highlight]
|
||||
Color=#418379
|
||||
|
||||
[InputPanel/Highlight/Margin]
|
||||
Left=20
|
||||
Right=20
|
||||
Top=7
|
||||
Bottom=7
|
||||
|
||||
[InputPanel/TextMargin]
|
||||
Left=20
|
||||
Right=20
|
||||
Top=6
|
||||
Bottom=6
|
||||
'';
|
||||
|
||||
services.fcitx5 = {
|
||||
description = "fcitx5: input method (IME) for emoji/internationalization";
|
||||
after = [ "graphical-session.target" ];
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart="${cfg.package}/bin/fcitx5";
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
|
||||
env.XMODIFIERS = "@im=fcitx";
|
||||
# setting IM_MODULE is generally not required on wayland, but can be used to override the toolkit's own dialogs with our own.
|
||||
# env.GTK_IM_MODULE = "fcitx";
|
||||
# enable if you want them:
|
||||
# env.QT_IM_MODULE = "fcitx";
|
||||
# env.QT_PLUGIN_PATH = [ "${cfg.package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ];
|
||||
# env.SDL_IM_MODULE = "fcitx";
|
||||
# env.GLFW_IM_MODULE = "ibus"; # for KiTTY, as per <https://wiki.archlinux.org/title/Fcitx5#Integration>
|
||||
};
|
||||
}
|
@@ -25,7 +25,6 @@ in
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.whitelistAudio = true;
|
||||
|
||||
|
@@ -234,7 +234,7 @@ in
|
||||
sane.programs.firefox = {
|
||||
inherit packageUnwrapped;
|
||||
sandbox.method = "bwrap"; # landlock works, but requires all of /proc to be linked
|
||||
sandbox.wrapperType = "inplace"; # probably wrappedDerivation could work too.
|
||||
sandbox.wrapperType = "inplace"; # trivial package; cheap enough to wrap inplace
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
@@ -322,6 +322,8 @@ in
|
||||
defaultPref("widget.use-xdg-desktop-portal.mime-handler", 1);
|
||||
defaultPref("widget.use-xdg-desktop-portal.open-uri", 1);
|
||||
|
||||
defaultPref("browser.toolbars.bookmarks.visibility", "never");
|
||||
|
||||
// auto-open mpv:// URIs without prompting.
|
||||
// can do this with other protocols too (e.g. matrix?). see about:config for common handlers.
|
||||
defaultPref("network.protocol-handler.external.mpv", true);
|
||||
|
@@ -1,6 +1,10 @@
|
||||
# to preview fonts:
|
||||
# - `font-manager` (gui)
|
||||
# - useful to determine official name; codepoint support
|
||||
# docs:
|
||||
# - <https://slatecave.net/notebook/fontconfig/>
|
||||
# debugging:
|
||||
# - `fc-conflist` -> show all config files loaded
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
# nerdfonts takes popular open fonts and patches them to support a wider range of glyphs, notably emoji.
|
||||
@@ -30,13 +34,12 @@ in
|
||||
{
|
||||
sane.programs.fontconfig = {
|
||||
sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.autodetectCliPaths = "existingOrParent"; #< this might be overkill; or, how many programs reference fontconfig internally?
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
# < 10 MiB
|
||||
".cache/fontconfig"
|
||||
];
|
||||
# persist.byStore.plaintext = [
|
||||
# # < 10 MiB. however, nixos generates its own fontconfig cache at build time now.
|
||||
# ".cache/fontconfig"
|
||||
# ];
|
||||
};
|
||||
|
||||
fonts = lib.mkIf config.sane.programs.fontconfig.enabled {
|
||||
@@ -44,8 +47,8 @@ in
|
||||
fontconfig.defaultFonts = {
|
||||
emoji = [
|
||||
"Noto Color Emoji"
|
||||
"Font Awesome 6 Free"
|
||||
"Font Awesome 6 Brands"
|
||||
# "Font Awesome 6 Free"
|
||||
# "Font Awesome 6 Brands"
|
||||
];
|
||||
monospace = [
|
||||
"Hack Nerd Font Propo"
|
||||
@@ -67,7 +70,7 @@ in
|
||||
# TODO: reduce this font set.
|
||||
# - probably need only one of dejavu/freefont/liberation
|
||||
dejavu_fonts # 10 MiB; DejaVu {Sans,Serif,Sans Mono,Math TeX Gyre}; also available as a NerdFonts (Sans Mono only)
|
||||
font-awesome # 2 MiB; Font Awesome 6 {Free,Brands}
|
||||
# font-awesome # 2 MiB; Font Awesome 6 {Free,Brands}
|
||||
freefont_ttf # 11 MiB; Free{Mono,Sans,Serif}
|
||||
gyre-fonts # 4 MiB; Tex Gyre *; ttf substitutes for standard PostScript fonts
|
||||
# hack-font # 1 MiB; Hack; also available as a NerdFonts
|
||||
|
@@ -28,7 +28,6 @@ in
|
||||
# packageUnwrapped = pkgs.fractal-next;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
@@ -60,9 +59,9 @@ in
|
||||
|
||||
persist.byStore.private = [
|
||||
# XXX by default fractal stores its state in ~/.local/share/<build-profile>/<UUID>.
|
||||
".local/share/hack" # for debug-like builds
|
||||
".local/share/stable" # for normal releases
|
||||
".local/share/fractal" # for version 5+, i think?
|
||||
# ".local/share/hack" # for debug-like builds
|
||||
# ".local/share/stable" # for normal releases
|
||||
".local/share/fractal" # for version 5+
|
||||
];
|
||||
|
||||
suggestedPrograms = [ "gnome-keyring" ];
|
||||
|
@@ -3,7 +3,6 @@
|
||||
{
|
||||
sane.programs.frozen-bubble = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet"; # net play
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -9,7 +9,6 @@
|
||||
{
|
||||
sane.programs.g4music = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -4,7 +4,6 @@
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.glib "bin/gdbus";
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ]; #< XXX: maybe future users will also want system access
|
||||
};
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ in
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -19,7 +19,6 @@ in
|
||||
'';
|
||||
});
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.autodetectCliPaths = true; # necessary for git-upload-pack
|
||||
|
@@ -6,10 +6,10 @@ in
|
||||
sane.programs.gnome-keyring = {
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome.gnome-keyring;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.extraRuntimePaths = [
|
||||
"keyring/control"
|
||||
"keyring" #< only needs keyring/control, but has to *create* that.
|
||||
# "keyring/control"
|
||||
];
|
||||
sandbox.capabilities = [
|
||||
# ipc_lock: used to `mlock` the secrets so they don't get swapped out.
|
||||
@@ -28,7 +28,7 @@ in
|
||||
|
||||
fs.".local/share/keyrings/default" = {
|
||||
file.text = "Default_keyring.keyring"; #< no trailing newline
|
||||
wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
|
||||
# wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
|
||||
wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
|
||||
"gnome-keyring.service" # TODO: sane.programs should declare this dependency for us
|
||||
];
|
||||
@@ -43,7 +43,7 @@ in
|
||||
lock-on-idle=false
|
||||
lock-after=false
|
||||
'';
|
||||
wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
|
||||
# wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
|
||||
wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
|
||||
"gnome-keyring.service"
|
||||
];
|
||||
@@ -55,6 +55,7 @@ in
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/gnome-keyring-daemon --start --foreground --components=secrets";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0700 -p %t/keyring";
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "20s";
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs."gnome.gnome-maps" = {
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome.gnome-maps;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace"; #< dbus files
|
||||
sandbox.whitelistDri = true; # for perf
|
||||
sandbox.whitelistDbus = [
|
||||
"system" # system is required for non-portal location services
|
||||
|
@@ -4,7 +4,7 @@
|
||||
{
|
||||
sane.programs."gnome.gnome-weather" = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace";
|
||||
sandbox.wrapperType = "inplace"; #< /share/org.gnome.Weather/org.gnome.Weather file refers to bins by full path
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
suggestedPrograms = [ "dconf" ]; #< stores city/location settings
|
||||
|
@@ -34,7 +34,6 @@ in
|
||||
{
|
||||
sane.programs.go2tv = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
# for GUI invocation, allow the common media directories
|
||||
|
@@ -23,7 +23,6 @@ in {
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ]; # it won't launch without it, dunno exactly why.
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
|
@@ -15,7 +15,6 @@
|
||||
"wl-clipboard"
|
||||
];
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
sane.programs.handbrake = {
|
||||
sandbox.method = "landlock"; #< also supports bwrap, but landlock ensures we don't write to non-mounted tmpfs dir
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
sane.programs.kdenlive = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.extraHomePaths = [
|
||||
"Music"
|
||||
"Pictures/from" # e.g. Videos taken from my phone
|
||||
|
@@ -11,7 +11,6 @@
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap"; # TODO:sandbox untested
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistDbus = [ "user" ]; # needs to connect to dconf via dbus
|
||||
sandbox.whitelistDri = true; #< required
|
||||
|
@@ -46,7 +46,6 @@ in {
|
||||
sane.programs.koreader = {
|
||||
packageUnwrapped = pkgs.koreader-from-src;
|
||||
sandbox.method = "bwrap"; # sandboxes fine under landlock too, except for FTP
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistDri = true; # reduces startup time and subjective page flip time
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
sane.programs.lemoa = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for clicking links
|
||||
sandbox.whitelistDri = true;
|
||||
|
8
hosts/common/programs/less.nix
Normal file
8
hosts/common/programs/less.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.less = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
env.PAGER = "less";
|
||||
};
|
||||
}
|
@@ -12,7 +12,6 @@
|
||||
}));
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.autodetectCliPaths = "parent";
|
||||
sandbox.extraHomePaths = [
|
||||
|
@@ -10,19 +10,13 @@
|
||||
# bwrap (loupe image viewer) doesn't like to run inside landlock
|
||||
# "bwrap: failed to make / slave: Operation not permitted"
|
||||
sandbox.method = "bwrap"; # supports landlock or bwrap
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< so that it can in theory open the image viewer using fdo portal... but it doesn't :|
|
||||
sandbox.extraHomePaths = [
|
||||
".config/dconf" #< else it segfaults during post-process
|
||||
# ".config/megapixels"
|
||||
# ".config/xcb"
|
||||
# ".xcb"
|
||||
".local/share/applications" #< needed for viewing photos, until i can sort out the portal stuff
|
||||
# ".local/share/icons"
|
||||
# ".icons" #< actually needed!
|
||||
# ".themes"
|
||||
# ".nix-profile"
|
||||
".cache/mesa_shader_cache" # loads way faster
|
||||
"tmp"
|
||||
"Pictures" #< TODO: make this Pictures/Photos and save photos there
|
||||
|
@@ -5,7 +5,6 @@
|
||||
{
|
||||
sane.programs.mepo = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "all"; # for tiles *and* for localhost comm to gpsd
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -1,6 +1,8 @@
|
||||
# mimeo is an exec dispatcher like xdg-open, but why allows mapping different URL regexes to different handlers.
|
||||
# mimeo is an exec dispatcher like xdg-open, but which allows mapping different URL regexes to different handlers.
|
||||
# my setup sets mimeo as the default http/https handler,
|
||||
# and from there it dispatches specialized rules, falling back to the original http/https handler if no URL specialization exists
|
||||
#
|
||||
# alternative to mimeo is jaro: <https://github.com/isamert/jaro>
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
mimeo-open-desktop = pkgs.static-nix-shell.mkPython3Bin {
|
||||
|
@@ -1,195 +0,0 @@
|
||||
# mpv docs:
|
||||
# - <https://mpv.io/manual/master>
|
||||
# - <https://github.com/mpv-player/mpv/wiki>
|
||||
# curated mpv mods/scripts/users:
|
||||
# - <https://github.com/stax76/awesome-mpv>
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.sane.programs.mpv;
|
||||
in
|
||||
{
|
||||
sane.programs.mpv = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options.vo = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "--vo=FOO flag to pass to mpv";
|
||||
};
|
||||
};
|
||||
};
|
||||
packageUnwrapped = (pkgs.wrapMpv pkgs.mpv-unwrapped {
|
||||
scripts = with pkgs.mpvScripts; [
|
||||
mpris
|
||||
uosc
|
||||
# pkgs.mpv-uosc-latest
|
||||
];
|
||||
extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
||||
# 2023/08/29: fixes an error where mpv on moby launches with the message
|
||||
# "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
|
||||
# audio still works, and controls, screenshotting, etc -- just not the actual rendering
|
||||
#
|
||||
# this is likely a regression for mpv 0.36.0.
|
||||
# the actual error message *appears* to come from the mesa library, but it's tough to trace.
|
||||
#
|
||||
# TODO(2023/12/03): remove once mesa 23.3.1 lands: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||
#
|
||||
# backend compatibility (2023/10/22):
|
||||
# run with `--vo=help` to see a list of all output options.
|
||||
# non-exhaustive (W=works, F=fails, A=audio-only, U=audio+ui only (no video))
|
||||
# ? null Null video output
|
||||
# A (default)
|
||||
# A dmabuf-wayland Wayland dmabuf video output
|
||||
# A libmpv render API for libmpv (mpv plays the audio, but doesn't even render a window)
|
||||
# A vdpau VDPAU with X11
|
||||
# F drm Direct Rendering Manager (software scaling)
|
||||
# F gpu-next Video output based on libplacebo
|
||||
# F vaapi VA API with X11
|
||||
# F x11 X11 (software scaling)
|
||||
# F xv X11/Xv
|
||||
# U gpu Shader-based GPU Renderer
|
||||
# W caca libcaca (terminal rendering)
|
||||
# W sdl SDL 2.0 Renderer
|
||||
# W wlshm Wayland SHM video output (software scaling)
|
||||
"--add-flags" "--vo=${cfg.config.vo}"
|
||||
];
|
||||
}).overrideAttrs (base: {
|
||||
buildCommand = base.buildCommand + ''
|
||||
# runHook postFixup to allow sandbox wrappers to wrap the binaries
|
||||
runHook postFixup
|
||||
'';
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< mpris
|
||||
sandbox.whitelistDri = true; #< mpv has excellent fallbacks to non-DRI, but DRI offers a good 30%-50% reduced CPU
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".config/mpv" #< else mpris plugin crashes on launch
|
||||
# it's common for album (or audiobook, podcast) images/lyrics/metadata to live adjacent to the primary file.
|
||||
# CLI detection is too poor to pick those up, so expose the common media dirs to the sandbox to make that *mostly* work.
|
||||
"Books/local"
|
||||
"Books/servo"
|
||||
"Music"
|
||||
"Videos/local"
|
||||
"Videos/servo"
|
||||
];
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
# for `watch_later`
|
||||
".local/state/mpv"
|
||||
];
|
||||
fs.".config/mpv/input.conf".symlink.text = let
|
||||
execInTerm = "${pkgs.xdg-terminal-exec}/bin/xdg-terminal-exec";
|
||||
in ''
|
||||
# docs:
|
||||
# - <https://mpv.io/manual/master/#list-of-input-commands>
|
||||
# - script-binding: <https://mpv.io/manual/master/#command-interface-script-binding>
|
||||
# - properties: <https://mpv.io/manual/master/#property-list>
|
||||
|
||||
# let volume/power keys be interpreted by the system.
|
||||
# this is important for sxmo.
|
||||
# mpv defaults is POWER = close, VOLUME_{UP,DOWN} = adjust application-level volume
|
||||
POWER ignore
|
||||
VOLUME_UP ignore
|
||||
VOLUME_DOWN ignore
|
||||
|
||||
# uosc menu
|
||||
# text after the shebang is parsed by uosc to construct the menu and names
|
||||
menu script-binding uosc/menu
|
||||
s script-binding uosc/subtitles #! Subtitles
|
||||
a script-binding uosc/audio #! Audio tracks
|
||||
q script-binding uosc/stream-quality #! Stream quality
|
||||
p script-binding uosc/items #! Playlist
|
||||
c script-binding uosc/chapters #! Chapters
|
||||
> script-binding uosc/next #! Navigation > Next
|
||||
< script-binding uosc/prev #! Navigation > Prev
|
||||
o script-binding uosc/open-file #! Navigation > Open file
|
||||
# set video-aspect-override "-1" #! Utils > Aspect ratio > Default
|
||||
# set video-aspect-override "16:9" #! Utils > Aspect ratio > 16:9
|
||||
# set video-aspect-override "4:3" #! Utils > Aspect ratio > 4:3
|
||||
# set video-aspect-override "2.35:1" #! Utils > Aspect ratio > 2.35:1
|
||||
# script-binding uosc/audio-device #! Utils > Audio devices
|
||||
# script-binding uosc/editions #! Utils > Editions
|
||||
ctrl+s async screenshot #! Utils > Screenshot
|
||||
alt+i script-binding uosc/keybinds #! Utils > Key bindings
|
||||
O script-binding uosc/show-in-directory #! Utils > Show in directory
|
||||
# script-binding uosc/open-config-directory #! Utils > Open config directory
|
||||
# set pause yes; run ${execInTerm} go2tv -v "''${stream-open-filename}" #! Cast
|
||||
# set pause yes; run ${execInTerm} go2tv -u "''${stream-open-filename}" #! Cast (...) > Stream
|
||||
# set pause yes; run go2tv #! Cast (...) > GUI
|
||||
# TODO: unify "Cast" and "Cast (stream)" options above.
|
||||
'';
|
||||
fs.".config/mpv/mpv.conf".symlink.text = ''
|
||||
save-position-on-quit=yes
|
||||
keep-open=yes
|
||||
|
||||
# force GUI, even for tracks w/o album art
|
||||
# see: <https://www.reddit.com/r/mpv/comments/rvrrpt/oscosdgui_and_arch_linux/>
|
||||
player-operation-mode=pseudo-gui
|
||||
|
||||
# use uosc instead (for On Screen Controls)
|
||||
osc=no
|
||||
# uosc provides its own seeking/volume indicators, so you also don't need this
|
||||
osd-bar=no
|
||||
# uosc will draw its own window controls if you disable window border
|
||||
border=no
|
||||
'';
|
||||
fs.".config/mpv/script-opts/osc.conf".symlink.text = ''
|
||||
# make the on-screen controls *always* visible
|
||||
# unfortunately, this applies to full-screen as well
|
||||
# - docs: <https://mpv.io/manual/master/#on-screen-controller-visibility>
|
||||
# if uosc is installed, this file is unused
|
||||
visibility=always
|
||||
'';
|
||||
fs.".config/mpv/script-opts/uosc.conf".symlink.text = let
|
||||
play_pause_btn = "cycle:play_arrow:pause:no=pause/yes=play_arrow";
|
||||
rev_btn = "command:replay_10:seek -10";
|
||||
fwd_btn = "command:forward_30:seek 30";
|
||||
in ''
|
||||
# docs:
|
||||
# - <https://github.com/tomasklaen/uosc>
|
||||
# - <https://github.com/tomasklaen/uosc/blob/main/src/uosc.conf>
|
||||
# - <https://superuser.com/questions/1775550/add-new-buttons-to-mpv-uosc-ui>
|
||||
timeline_style=bar
|
||||
timeline_persistency=paused,audio
|
||||
controls_persistency=paused,audio
|
||||
volume_persistency=audio
|
||||
volume_opacity=0.75
|
||||
|
||||
# speed_persistency=paused,audio
|
||||
# vvv want a close button?
|
||||
top_bar=always
|
||||
top_bar_persistency=paused
|
||||
|
||||
controls=menu,<video>subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,space,${rev_btn},${play_pause_btn},${fwd_btn},space,speed:1.0,gap,<video>fullscreen
|
||||
|
||||
text_border=6.0
|
||||
font_bold=yes
|
||||
color=foreground=ff8080,background_text=ff8080
|
||||
|
||||
ui_scale=1.0
|
||||
'';
|
||||
|
||||
# mime.priority = 200; # default = 100; 200 means to yield to other apps
|
||||
mime.priority = 50; # default = 100; 50 in order to take precedence over vlc.
|
||||
mime.associations."audio/flac" = "mpv.desktop";
|
||||
mime.associations."audio/mpeg" = "mpv.desktop";
|
||||
mime.associations."audio/x-opus+ogg" = "mpv.desktop";
|
||||
mime.associations."audio/x-vorbis+ogg" = "mpv.desktop";
|
||||
mime.associations."video/mp4" = "mpv.desktop";
|
||||
mime.associations."video/quicktime" = "mpv.desktop";
|
||||
mime.associations."video/webm" = "mpv.desktop";
|
||||
mime.associations."video/x-flv" = "mpv.desktop";
|
||||
mime.associations."video/x-matroska" = "mpv.desktop";
|
||||
mime.urlAssociations."^https?://(www.)?youtube.com/watch\?.*v=" = "mpv.desktop";
|
||||
mime.urlAssociations."^https?://(www.)?youtube.com/v/" = "mpv.desktop";
|
||||
mime.urlAssociations."^https?://(www.)?youtu.be/.+" = "mpv.desktop";
|
||||
};
|
||||
}
|
||||
|
3
hosts/common/programs/mpv/console.conf
Normal file
3
hosts/common/programs/mpv/console.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
# font size used by mpv's console (`); default 16
|
||||
# font_size=28
|
||||
scale=2
|
166
hosts/common/programs/mpv/default.nix
Normal file
166
hosts/common/programs/mpv/default.nix
Normal file
@@ -0,0 +1,166 @@
|
||||
# curated mpv mods/scripts/users:
|
||||
# - <https://github.com/stax76/awesome-mpv>
|
||||
# mpv docs:
|
||||
# - <https://mpv.io/manual/master>
|
||||
# - <https://github.com/mpv-player/mpv/wiki>
|
||||
# extensions i use:
|
||||
# - <https://github.com/jonniek/mpv-playlistmanager>
|
||||
# other extensions that could be useful:
|
||||
# - list: <https://github.com/stax76/awesome-mpv>
|
||||
# - list: <https://nudin.github.io/mpv-script-directory/>
|
||||
# - browse DLNA shares: <https://github.com/chachmu/mpvDLNA>
|
||||
# - act as a DLNS renderer (sink): <https://github.com/xfangfang/Macast>
|
||||
# debugging:
|
||||
# - enter console by pressing backtick.
|
||||
# > `set volume 50` -> sets application volume to 50%
|
||||
# > `set ao-volume 50` -> sets system-wide volume to 50%
|
||||
# > `show-text "vol: ${volume}"` -> get the volume
|
||||
# - show script output by running mpv with `--msg-level=all=trace`
|
||||
# - and then just `print(...)` from lua & it'll show in terminal
|
||||
# - invoke mpv with `--no-config` to have it not read ~/.config/mpv/*
|
||||
# - press `i` to show decoder info
|
||||
#
|
||||
# usage tips:
|
||||
# - `<` or `>` to navigate prev/next-file-in-folder (uosc)
|
||||
# - shift+enter to view the playlist, then arrow-keys to navigate (mpv-playlistmanager)
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.sane.programs.mpv;
|
||||
uosc = pkgs.mpvScripts.uosc.overrideAttrs (upstream: {
|
||||
# patch so that the volume control corresponds to `ao-volume`, i.e. the system-wide volume.
|
||||
# this is particularly nice for moby, because it avoids the awkwardness that system volume
|
||||
# is hard to adjust while screen is on.
|
||||
# note that only under alsa (`-ao=alsa`) does `ao-volume` actually correspond to system volume.
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
substituteInPlace src/uosc/main.lua \
|
||||
--replace-fail "mp.observe_property('volume'" "mp.observe_property('ao-volume'"
|
||||
substituteInPlace src/uosc/elements/Volume.lua \
|
||||
--replace-fail "mp.commandv('set', 'volume'" "mp.commandv('set', 'ao-volume'" \
|
||||
--replace-fail "mp.set_property_native('volume'" "mp.set_property('ao-volume'"
|
||||
|
||||
# `ao-volume` isn't actually an observable property.
|
||||
# as of 2024/03/02, they *may* be working on that:
|
||||
# - <https://github.com/mpv-player/mpv/pull/13604#issuecomment-1971665736>
|
||||
# in the meantime, just query the volume every tick (i.e. frame).
|
||||
# alternative is mpv's JSON IPC feature, where i could notify its socket whenever pipewire volume changes.
|
||||
cat <<EOF >> src/uosc/main.lua
|
||||
function update_ao_volume()
|
||||
local vol = mp.get_property('ao-volume')
|
||||
if vol ~= nil then
|
||||
vol = tonumber(vol)
|
||||
if vol ~= state.volume then
|
||||
set_state('volume', vol)
|
||||
request_render()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- tick seems to occur on every redraw (even when volume is hidden).
|
||||
-- in practice: for every new frame of the source, or whenever the cursor is moved.
|
||||
mp.register_event('tick', update_ao_volume)
|
||||
-- if paused and cursor isn't moving, then `tick` isn't called. fallback to a timer.
|
||||
mp.add_periodic_timer(2, update_ao_volume)
|
||||
-- invoke immediately to ensure state.volume is non-nil
|
||||
update_ao_volume()
|
||||
if state.volume == nil then
|
||||
state.volume = 0
|
||||
end
|
||||
EOF
|
||||
'';
|
||||
});
|
||||
in
|
||||
{
|
||||
sane.programs.mpv = {
|
||||
packageUnwrapped = with pkgs; wrapMpv mpv-unwrapped {
|
||||
scripts = [
|
||||
mpvScripts.mpris
|
||||
mpvScripts.mpv-playlistmanager
|
||||
uosc
|
||||
# pkgs.mpv-uosc-latest
|
||||
];
|
||||
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
||||
# # 2023/08/29: fixes an error where mpv on moby launches with the message
|
||||
# # "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
|
||||
# # audio still works, and controls, screenshotting, etc -- just not the actual rendering
|
||||
# #
|
||||
# # this is likely a regression for mpv 0.36.0.
|
||||
# # the actual error message *appears* to come from the mesa library, but it's tough to trace.
|
||||
# #
|
||||
# # 2024/03/02: no longer necessary, with mesa 23.3.1: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||
# #
|
||||
# # backend compatibility (2023/10/22):
|
||||
# # run with `--vo=help` to see a list of all output options.
|
||||
# # non-exhaustive (W=works, F=fails, A=audio-only, U=audio+ui only (no video))
|
||||
# # ? null Null video output
|
||||
# # A (default)
|
||||
# # A dmabuf-wayland Wayland dmabuf video output
|
||||
# # A libmpv render API for libmpv (mpv plays the audio, but doesn't even render a window)
|
||||
# # A vdpau VDPAU with X11
|
||||
# # F drm Direct Rendering Manager (software scaling)
|
||||
# # F gpu-next Video output based on libplacebo
|
||||
# # F vaapi VA API with X11
|
||||
# # F x11 X11 (software scaling)
|
||||
# # F xv X11/Xv
|
||||
# # U gpu Shader-based GPU Renderer
|
||||
# # W caca libcaca (terminal rendering)
|
||||
# # W sdl SDL 2.0 Renderer
|
||||
# # W wlshm Wayland SHM video output (software scaling)
|
||||
# "--add-flags" "--vo=${cfg.config.vo}"
|
||||
# ];
|
||||
};
|
||||
|
||||
suggestedPrograms = [
|
||||
"blast-to-default"
|
||||
"go2tv"
|
||||
"xdg-terminal-exec"
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< mpris
|
||||
sandbox.whitelistDri = true; #< mpv has excellent fallbacks to non-DRI, but DRI offers a good 30%-50% reduced CPU
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".config/mpv" #< else mpris plugin crashes on launch
|
||||
".local/share/applications" #< for xdg-terminal-exec (go2tv)
|
||||
# it's common for album (or audiobook, podcast) images/lyrics/metadata to live adjacent to the primary file.
|
||||
# CLI detection is too poor to pick those up, so expose the common media dirs to the sandbox to make that *mostly* work.
|
||||
"Books/local"
|
||||
"Books/servo"
|
||||
"Music"
|
||||
"Videos/gPodder"
|
||||
"Videos/local"
|
||||
"Videos/servo"
|
||||
];
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
# for `watch_later`
|
||||
".local/state/mpv"
|
||||
];
|
||||
fs.".config/mpv/scripts/sane/main.lua".symlink.target = ./sane-main.lua;
|
||||
fs.".config/mpv/input.conf".symlink.target = ./input.conf;
|
||||
fs.".config/mpv/mpv.conf".symlink.target = ./mpv.conf;
|
||||
fs.".config/mpv/script-opts/osc.conf".symlink.target = ./osc.conf;
|
||||
fs.".config/mpv/script-opts/console.conf".symlink.target = ./console.conf;
|
||||
fs.".config/mpv/script-opts/uosc.conf".symlink.target = ./uosc.conf;
|
||||
fs.".config/mpv/script-opts/playlistmanager.conf".symlink.target = ./playlistmanager.conf;
|
||||
|
||||
# mime.priority = 200; # default = 100; 200 means to yield to other apps
|
||||
mime.priority = 50; # default = 100; 50 in order to take precedence over vlc.
|
||||
mime.associations."audio/flac" = "mpv.desktop";
|
||||
mime.associations."audio/mpeg" = "mpv.desktop";
|
||||
mime.associations."audio/x-opus+ogg" = "mpv.desktop";
|
||||
mime.associations."audio/x-vorbis+ogg" = "mpv.desktop";
|
||||
mime.associations."video/mp4" = "mpv.desktop";
|
||||
mime.associations."video/quicktime" = "mpv.desktop";
|
||||
mime.associations."video/webm" = "mpv.desktop";
|
||||
mime.associations."video/x-flv" = "mpv.desktop";
|
||||
mime.associations."video/x-matroska" = "mpv.desktop";
|
||||
mime.urlAssociations."^https?://(www.)?youtube.com/watch\?.*v=" = "mpv.desktop";
|
||||
mime.urlAssociations."^https?://(www.)?youtube.com/v/" = "mpv.desktop";
|
||||
mime.urlAssociations."^https?://(www.)?youtu.be/.+" = "mpv.desktop";
|
||||
};
|
||||
}
|
||||
|
37
hosts/common/programs/mpv/input.conf
Normal file
37
hosts/common/programs/mpv/input.conf
Normal file
@@ -0,0 +1,37 @@
|
||||
# docs:
|
||||
# - <https://mpv.io/manual/master/#list-of-input-commands>
|
||||
# - script-binding: <https://mpv.io/manual/master/#command-interface-script-binding>
|
||||
# - properties: <https://mpv.io/manual/master/#property-list>
|
||||
|
||||
# let volume/power keys be interpreted by the system.
|
||||
# this is important for sxmo.
|
||||
# mpv defaults is POWER = close, VOLUME_{UP,DOWN} = adjust application-level volume
|
||||
POWER ignore
|
||||
VOLUME_UP ignore
|
||||
VOLUME_DOWN ignore
|
||||
|
||||
# uosc menu
|
||||
# text after the shebang is parsed by uosc to construct the menu and names
|
||||
menu script-binding uosc/menu
|
||||
s script-binding uosc/subtitles #! Subtitles
|
||||
a script-binding uosc/audio #! Audio tracks
|
||||
q script-binding uosc/stream-quality #! Stream quality
|
||||
p script-binding uosc/items #! Playlist
|
||||
c script-binding uosc/chapters #! Chapters
|
||||
> script-binding uosc/next #! Navigation > Next
|
||||
< script-binding uosc/prev #! Navigation > Prev
|
||||
o script-binding uosc/open-file #! Navigation > Open file
|
||||
# set video-aspect-override "-1" #! Utils > Aspect ratio > Default
|
||||
# set video-aspect-override "16:9" #! Utils > Aspect ratio > 16:9
|
||||
# set video-aspect-override "4:3" #! Utils > Aspect ratio > 4:3
|
||||
# set video-aspect-override "2.35:1" #! Utils > Aspect ratio > 2.35:1
|
||||
# script-binding uosc/audio-device #! Utils > Audio devices
|
||||
# script-binding uosc/editions #! Utils > Editions
|
||||
ctrl+s async screenshot #! Utils > Screenshot
|
||||
alt+i script-binding uosc/keybinds #! Utils > Key bindings
|
||||
O script-binding uosc/show-in-directory #! Utils > Show in directory
|
||||
# script-binding uosc/open-config-directory #! Utils > Open config directory
|
||||
ctrl+r script-binding sane/blast #! Audiocast
|
||||
ctrl+t script-binding sane/go2tv-video #! Cast
|
||||
# script-binding sane/go2tv-stream #! Cast (...) > Stream
|
||||
# script-binding sane/go2tv-gui #! Cast (...) > GUI
|
26
hosts/common/programs/mpv/mpv.conf
Normal file
26
hosts/common/programs/mpv/mpv.conf
Normal file
@@ -0,0 +1,26 @@
|
||||
# write ~/.local/state/mpv/watch_later on exit, to allow resume
|
||||
save-position-on-quit=yes
|
||||
# identify resumed files by filename only, since i use so many symlinks and doubt mpv does well with that.
|
||||
ignore-path-in-watch-later-config
|
||||
|
||||
# keep-open: don't exit on completion of last file in playlist
|
||||
keep-open=yes
|
||||
# seeking once at the end of the file causes auto-resume
|
||||
keep-open-pause=no
|
||||
|
||||
# force GUI, even for tracks w/o album art
|
||||
# see: <https://www.reddit.com/r/mpv/comments/rvrrpt/oscosdgui_and_arch_linux/>
|
||||
player-operation-mode=pseudo-gui
|
||||
|
||||
# use uosc instead (for On Screen Controls)
|
||||
osc=no
|
||||
# uosc provides its own seeking/volume indicators, so you also don't need this
|
||||
osd-bar=no
|
||||
# uosc will draw its own window controls if you disable window border
|
||||
border=no
|
||||
|
||||
# ao=alsa so that uosc can work with ao-volume (see my uosc patch)
|
||||
ao=alsa
|
||||
# with `ao-volume`, the max actually is 100.
|
||||
# to go higher you'll have to use the system's native controls.
|
||||
volume-max=100
|
5
hosts/common/programs/mpv/osc.conf
Normal file
5
hosts/common/programs/mpv/osc.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
# make the on-screen controls *always* visible
|
||||
# unfortunately, this applies to full-screen as well
|
||||
# - docs: <https://mpv.io/manual/master/#on-screen-controller-visibility>
|
||||
# if uosc is installed, this file is unused
|
||||
visibility=always
|
4
hosts/common/programs/mpv/playlistmanager.conf
Normal file
4
hosts/common/programs/mpv/playlistmanager.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
# script docs: <https://github.com/jonniek/mpv-playlistmanager>
|
||||
|
||||
# auto-populate playlist with other files in the same directory, on launch.
|
||||
loadfiles_on_start=yes
|
34
hosts/common/programs/mpv/sane-main.lua
Normal file
34
hosts/common/programs/mpv/sane-main.lua
Normal file
@@ -0,0 +1,34 @@
|
||||
function subprocess(in_terminal, args)
|
||||
if in_terminal then
|
||||
args = { "xdg-terminal-exec", table.unpack(args) }
|
||||
end
|
||||
mp.command_native({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
detach = false,
|
||||
capture_stdout = false,
|
||||
capture_stderr = false,
|
||||
-- capture_size=0,
|
||||
passthrough_stdin = false,
|
||||
playback_only = false,
|
||||
})
|
||||
end
|
||||
|
||||
function invoke_go2tv(in_terminal, args)
|
||||
mp.commandv("set", "pause", "yes")
|
||||
subprocess(in_terminal, { "go2tv", table.unpack(args) })
|
||||
end
|
||||
|
||||
function invoke_go2tv_on_open_file(mode)
|
||||
local path = mp.get_property("stream-open-filename");
|
||||
return invoke_go2tv(true, { mode, path })
|
||||
end
|
||||
|
||||
mp.add_key_binding(nil, "blast", function() subprocess(false, { "blast-to-default" }) end)
|
||||
mp.add_key_binding(nil, 'go2tv-gui', function() invoke_go2tv(false, {}) end)
|
||||
mp.add_key_binding(nil, 'go2tv-video', function() invoke_go2tv_on_open_file("-v") end)
|
||||
mp.add_key_binding(nil, 'go2tv-stream', function() invoke_go2tv_on_open_file("-s") end)
|
||||
|
||||
-- uncomment for debugging:
|
||||
-- if mpv fails to eval this script (e.g. syntax error), then it will fail to quit on launch
|
||||
-- mp.command('quit')
|
32
hosts/common/programs/mpv/uosc.conf
Normal file
32
hosts/common/programs/mpv/uosc.conf
Normal file
@@ -0,0 +1,32 @@
|
||||
# docs:
|
||||
# - <https://github.com/tomasklaen/uosc>
|
||||
# - <https://github.com/tomasklaen/uosc/blob/main/src/uosc.conf>
|
||||
# - <https://superuser.com/questions/1775550/add-new-buttons-to-mpv-uosc-ui>
|
||||
timeline_style=bar
|
||||
timeline_line_width=4
|
||||
timeline_size=36
|
||||
timeline_persistency=paused,audio
|
||||
controls_persistency=paused,audio
|
||||
volume_persistency=audio
|
||||
|
||||
# speed_persistency=paused,audio
|
||||
# vvv want a close button?
|
||||
top_bar=always
|
||||
top_bar_persistency=paused,audio
|
||||
|
||||
controls=menu,<video>subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,space,command:replay_10:seek -10,cycle:play_arrow:pause:no=pause/yes=play_arrow,command:forward_30:seek 30,space,speed:1.0,gap,<video>fullscreen
|
||||
|
||||
# text_border: shadow to place around icons/text which is rendered over the video
|
||||
text_border=5.0
|
||||
# border_radius: rounding of volume slider, etc.
|
||||
border_radius=5.0
|
||||
font_scale=1.5
|
||||
font_bold=yes
|
||||
# refine=text_width: slightly better text rendering
|
||||
refine=text_width
|
||||
color=foreground=ff8080,background_text=ff8080
|
||||
# N.B.: if `opacity=` is set non-empty, then ALL items must be specified (else they get 0 opacity).
|
||||
# opacity values *must* be a multiple of 0.1
|
||||
opacity=timeline=0.8,position=1,chapters=0.8,slider=0.8,slider_gauge=0.8,controls=0,speed=0.8,menu=1,submenu=0.4,border=1,title=0.8,tooltip=1,thumbnail=1,curtain=0.8,idle_indicator=0.8,audio_indicator=0.5,buffering_indicator=0.3,playlist_position=0.8
|
||||
|
||||
stream_quality_options=1440,1080,720,480,360,240,144
|
@@ -1,16 +1,16 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs."gnome.nautilus" = {
|
||||
packageUnwrapped = pkgs.gnome.nautilus.overrideAttrs (orig: {
|
||||
# some of its dbus services don't even refer to real paths
|
||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.gnome.nautilus.overrideAttrs (orig: {
|
||||
# enable the "Audio and Video Properties" pane. see: <https://nixos.wiki/wiki/Nautilus>
|
||||
buildInputs = orig.buildInputs ++ (with pkgs.gst_all_1; [
|
||||
gst-plugins-good
|
||||
gst-plugins-bad
|
||||
]);
|
||||
});
|
||||
}));
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for portals launching apps
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
|
@@ -88,7 +88,6 @@ in
|
||||
{
|
||||
sane.programs.neovim = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.autodetectCliPaths = "existingOrParent";
|
||||
sandbox.whitelistWayland = true; # for system clipboard integration
|
||||
# sandbox.whitelistPwd = true;
|
||||
|
@@ -11,7 +11,6 @@
|
||||
});
|
||||
|
||||
sandbox.method = "firejail";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "vpn";
|
||||
|
||||
|
@@ -3,7 +3,6 @@
|
||||
# provides `nix-locate`, backed by the manually run `nix-index`
|
||||
sane.programs.nix-index = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.extraPaths = [
|
||||
"/nix"
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
sane.programs.notejot = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistWayland = true;
|
||||
suggestedPrograms = [ "dconf" ]; #< else it can't persist notes
|
||||
|
||||
|
@@ -21,7 +21,6 @@ in
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.net = "clearnet";
|
||||
|
||||
secrets.".config/ntfy-sh/topic" = ../../../secrets/common/ntfy-sh-topic.bin;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
{
|
||||
sane.programs.open-in-mpv = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for xdg-open/portals
|
||||
|
||||
# taken from <https://github.com/Baldomo/open-in-mpv>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# administer with pw-cli, pw-mon, pw-top commands
|
||||
{ config, lib, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.pipewire;
|
||||
in
|
||||
@@ -18,6 +18,10 @@ in
|
||||
sandbox.extraRuntimePaths = [ "/" ];
|
||||
sandbox.extraPaths = [
|
||||
"/dev/snd"
|
||||
# desko/lappy don't need these, but moby complains if not present
|
||||
"/dev/video0"
|
||||
"/dev/video1"
|
||||
"/dev/video2"
|
||||
];
|
||||
sandbox.extraHomePaths = [
|
||||
# pulseaudio cookie
|
||||
@@ -30,10 +34,23 @@ in
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/pipewire";
|
||||
ExecStartPost = pkgs.writeShellScript "pipewire-wait-started" ''
|
||||
waitFor() {
|
||||
while [ ! -e "$1" ]; do
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
waitFor "$XDG_RUNTIME_DIR/pipewire-0"
|
||||
waitFor "$XDG_RUNTIME_DIR/pipewire-0-manager"
|
||||
'';
|
||||
ExecStopPost = ''rm -f "$XDG_RUNTIME_DIR/{pipewire-0,pipewire-0.lock,pipewire-0-manager,pipewire-0-manager.lock}"'';
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
};
|
||||
|
||||
# environment.PIPEWIRE_LOG_SYSTEMD = "false";
|
||||
# environment.PIPEWIRE_DEBUG = "*:3,mod.raop*:5,pw.rtsp-client*:5";
|
||||
};
|
||||
services.pipewire-pulse = {
|
||||
description = "pipewire-pulse: Pipewire compatibility layer for PulseAudio clients";
|
||||
@@ -41,6 +58,16 @@ in
|
||||
wantedBy = [ "pipewire.service" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/pipewire-pulse";
|
||||
ExecStartPost = pkgs.writeShellScript "pipewire-pulse-wait-started" ''
|
||||
waitFor() {
|
||||
while [ ! -e "$1" ]; do
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
waitFor "$XDG_RUNTIME_DIR/pulse/native"
|
||||
waitFor "$XDG_RUNTIME_DIR/pulse/pid"
|
||||
'';
|
||||
ExecStopPost = ''rm -f "$XDG_RUNTIME_DIR/pulse/{native,pid}"'';
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
sane.programs.planify = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for dconf? else it can't persist any tasks/notes
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
{
|
||||
sane.programs.playerctl = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace";
|
||||
sandbox.wrapperType = "inplace"; #< /lib/pkgconfig/playerctl.pc refers to $out by full path
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
|
||||
services.playerctld = {
|
||||
|
@@ -3,7 +3,6 @@
|
||||
sane.programs.portfolio-filemanager = {
|
||||
# this is all taken pretty directly from nautilus config
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for portals launching apps
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
|
@@ -2,7 +2,6 @@
|
||||
{
|
||||
sane.programs.ripgrep = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.extraHomePaths = [
|
||||
|
@@ -6,33 +6,112 @@
|
||||
|
||||
configuration {
|
||||
modes: "combi";
|
||||
font: "mono 20";
|
||||
show-icons: true;
|
||||
combi-modes: "filebrowser,drun,run";
|
||||
kb-accept-entry: "Return,KP_Enter,XF86PowerOff";
|
||||
kb-row-up: "Up,XF86AudioRaiseVolume";
|
||||
kb-row-down: "Down,XF86AudioLowerVolume";
|
||||
filebrowser {
|
||||
/* filebrowser starting directory */
|
||||
directory: "/home";
|
||||
/* display-name: text to prepend in combi mode */
|
||||
display-name: "/";
|
||||
/* `command` is the prefix to prepend (along with a space) *before* passing it off to `run-command` */
|
||||
command: "xdg-open";
|
||||
}
|
||||
drun {
|
||||
display-name: " ";
|
||||
}
|
||||
run {
|
||||
display-name: "run ";
|
||||
cache-dir: "~/.cache/rofi";
|
||||
|
||||
/* to position rofi to the top of the screen: */
|
||||
/* location: 2; */
|
||||
|
||||
combi {
|
||||
/* this is rendered in the filter box, here we disable it */
|
||||
display-name: "";
|
||||
}
|
||||
/* combi-display-format: "{mode} {text}"; */
|
||||
/* combi-display-format: "{text}"; */
|
||||
combi-display-format: "{mode}{text}";
|
||||
combi-modes: "filebrowser,drun";
|
||||
|
||||
drun {
|
||||
display-name: " ";
|
||||
}
|
||||
drun-use-desktop-cache: true;
|
||||
|
||||
filebrowser {
|
||||
/* directory: filebrowser starting directory. leave unset to start at the last directory. */
|
||||
/* directory: "/home"; */
|
||||
|
||||
/* display-name: text to prepend in combi mode */
|
||||
display-name: "/";
|
||||
/* `command` is the prefix to prepend (along with a space) *before* passing it off to `run-command` */
|
||||
command: "xdg-open";
|
||||
directories-first: true;
|
||||
/* sorting-method: name/atime/ctime/mtime */
|
||||
sorting-method: "name";
|
||||
show-hidden: false;
|
||||
}
|
||||
|
||||
run {
|
||||
display-name: "run ";
|
||||
}
|
||||
/* launch applications via my own launcher, which directs them through to xdg-desktop-portal */
|
||||
run-command: "rofi-run-command '{app_id}.desktop' {cmd}";
|
||||
|
||||
drun-use-desktop-cache: true;
|
||||
}
|
||||
|
||||
@theme "gruvbox-light"
|
||||
/* theme */
|
||||
* {
|
||||
/* my own variables */
|
||||
bg: #1d1721; /* slight purple */
|
||||
fg0: #d8d8d8; /* inactive text (light grey) */
|
||||
fg1: #ffffff; /* active text (white) */
|
||||
accent0: #1f5e54; /* darker but saturated teal */
|
||||
accent1: #418379; /* teal (matches nixos-bg) */
|
||||
accent2: #5b938a; /* brighter but muted teal */
|
||||
|
||||
/* map my variables to variables rofi uses internally */
|
||||
background-color: var(accent0);
|
||||
background: var(accent0);
|
||||
/* foreground: non-alternating text, scrollbar, borders, separators */
|
||||
foreground: var(fg0);
|
||||
|
||||
/* override derived styles */
|
||||
alternate-active-background: var(accent0);
|
||||
alternate-normal-background: var(accent0);
|
||||
alternate-active-foreground: var(fg0);
|
||||
alternate-normal-foreground: var(fg0);
|
||||
border-color: var(accent0);
|
||||
text-color: var(fg0);
|
||||
selected-active-background: var(accent1);
|
||||
selected-normal-background: var(accent1);
|
||||
selected-active-foreground: var(fg1);
|
||||
selected-normal-foreground: var(fg1);
|
||||
separatorcolor: var(accent1);
|
||||
}
|
||||
entry {
|
||||
placeholder: "";
|
||||
text-color: var(fg1);
|
||||
}
|
||||
num-rows, num-filtered-rows {
|
||||
text-color: var(fg0);
|
||||
}
|
||||
prompt, textbox-prompt-colon {
|
||||
/* hide */
|
||||
text-color: var(accent0);
|
||||
}
|
||||
scrollbar {
|
||||
handle-color: var(accent2);
|
||||
}
|
||||
window {
|
||||
/* rofi supports very complex calculations here */
|
||||
/* one may even read environment variables (useful for knowing if screen is rotated?) */
|
||||
/* `calc(... min 100%)` ensures it never overflows */
|
||||
/* rofi is aware of the top bar (waybar) and any virtual keyboards,
|
||||
* so e.g. height: 100% will occupy 100% of the height *not* allocated to bars/kbds.
|
||||
* however with y-offset, it becomes possible to overflow */
|
||||
|
||||
width: calc(960 min 100%);
|
||||
/* 520px @ font size 20 gives 13 rows + filter */
|
||||
/* 482px @ font size 20 gives 12 rows + filter */
|
||||
/* 446px @ font size 20 gives 11 rows + filter */
|
||||
/* 90.5% @ font size 20, sway scale 2.0, moby in landscape mode: gives 7 rows + filter */
|
||||
height: calc(446 min 90.5%);
|
||||
|
||||
/* anchor the *north* edge of the window at the *north* location of the screen */
|
||||
anchor: north;
|
||||
location: north;
|
||||
/* 11.2% lines up nicely with Firefox */
|
||||
y-offset: 11.2%;
|
||||
}
|
||||
|
@@ -25,28 +25,27 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
rofi-unwrapped = pkgs.rofi-wayland-unwrapped.overrideAttrs (upstream: {
|
||||
# my patches made for tip don't cleanly apply to stable, so advance the entire src
|
||||
src = pkgs.fetchFromGitea {
|
||||
domain = "git.uninsane.org";
|
||||
owner = "colin";
|
||||
repo = "rofi";
|
||||
fetchSubmodules = true;
|
||||
# rev = "dev-sane"; #< fetchFromGitea doesn't support tags (?)
|
||||
rev = "1edfceaeefa2cae971ae90dc55811f3b7592a1b4";
|
||||
hash = "sha256-oIWLwec1LRsss12S92ebBWQk14FBJWc6QcYxzOU3eFI=";
|
||||
};
|
||||
# patches = (upstream.patches or []) ++ [
|
||||
# (pkgs.fetchpatch {
|
||||
# url = "https://git.uninsane.org/colin/rofi/commit/d8bb0b9944ec1f3bf7479c9f127ec09d4198e87f.patch";
|
||||
# name = "run-{shell-,}command: expand `{app_id}` inside the template string";
|
||||
# hash = "sha256-XiZRvr+BARU7h3OPU0NUUEem3isnUVER69zucSqvNNk=";
|
||||
# })
|
||||
# ];
|
||||
patches = (upstream.patches or []) ++ [
|
||||
(pkgs.fetchpatch {
|
||||
url = "https://git.uninsane.org/colin/rofi/commit/8e01fcd16f97f4c2a5bc63ade58c894a938f89d9.patch";
|
||||
name = "run-{shell-,}command: expand `{app_id}` inside the template string";
|
||||
hash = "sha256-DXafvvKrNyDOH11lpRdC2ljydb422ttY68oY5K3fKWo=";
|
||||
})
|
||||
(pkgs.fetchpatch {
|
||||
url = "https://git.uninsane.org/colin/rofi/commit/249450a2b58c3cf7ced911cadb8c4c60d3315dd0.patch";
|
||||
name = "filebrowser: include entries of d_type DT_UNKNOWN";
|
||||
hash = "sha256-gz3N4uo7IWzzqaPHHVhby/e9NbtzcFJRQwgdNYxO/Yw=";
|
||||
})
|
||||
];
|
||||
});
|
||||
# rofi-emoji = pkgs.rofi-emoji.override {
|
||||
# # plugins must be compiled against the same rofi they're loaded by
|
||||
# inherit rofi-unwrapped;
|
||||
# };
|
||||
# rofi-file-browser = pkgs.rofi-file-browser.override {
|
||||
# # plugins must be compiled against the same rofi they're loaded by
|
||||
# rofi = rofi-unwrapped;
|
||||
# };
|
||||
in
|
||||
{
|
||||
sane.programs.rofi = {
|
||||
@@ -54,8 +53,15 @@ in
|
||||
# it's actively maintained though, and more of an overlay than a true fork.
|
||||
packageUnwrapped = pkgs.rofi-wayland.override {
|
||||
inherit rofi-unwrapped;
|
||||
# rofi-emoji: "insert" mode doesn't work; use a wrapper like `splatmoji` instead.
|
||||
# plugins = [ rofi-emoji ];
|
||||
plugins = [
|
||||
# rofi-[extended-]-file-browser: <https://github.com/marvinkreis/rofi-file-browser-extended>
|
||||
# because the builtin rofi filebrowser only partially lists ~/Videos/servo/Shows, seemingly at random.
|
||||
# but rofi-file-browser doesn't compile against my patched rofi (oops)
|
||||
# rofi-file-browser
|
||||
|
||||
# rofi-emoji: "insert" mode doesn't work; use a wrapper like `splatmoji` instead.
|
||||
# rofi-emoji
|
||||
];
|
||||
};
|
||||
|
||||
suggestedPrograms = [
|
||||
@@ -63,11 +69,12 @@ in
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "wrappedDerivation";
|
||||
sandbox.whitelistDbus = [ "user" ]; #< to launch apps via the portal
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".local/share/applications" #< to locate .desktop files
|
||||
"Books/local"
|
||||
"Books/servo"
|
||||
"Music"
|
||||
"Pictures/albums"
|
||||
"Pictures/cat"
|
||||
@@ -75,18 +82,22 @@ in
|
||||
"Pictures/Photos"
|
||||
"Pictures/Screenshots"
|
||||
"Pictures/servo-macros"
|
||||
"Videos/gPodder"
|
||||
"Videos/local"
|
||||
"Videos/servo"
|
||||
"knowledge"
|
||||
"tmp"
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
"/mnt/servo/media"
|
||||
"/mnt/servo/playground"
|
||||
];
|
||||
|
||||
fs.".config/rofi/config.rasi".symlink.target = ./config.rasi;
|
||||
# redirect its default drun cache location
|
||||
fs.".cache/rofi3.druncache".symlink.target = "rofi/rofi3.druncache";
|
||||
fs.".cache/rofi-drun-desktop.cache".symlink.target = "rofi/rofi-drun-desktop.cache";
|
||||
persist.byStore.cryptClearOnBoot = [
|
||||
# optional, for caching .desktop files rofi finds on disk (perf)
|
||||
# this gets us a few things:
|
||||
# - file browser remembers its last directory
|
||||
# - caching of .desktop files (perf)
|
||||
".cache/rofi"
|
||||
];
|
||||
};
|
||||
@@ -95,13 +106,47 @@ in
|
||||
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||
pname = "rofi-run-command";
|
||||
srcRoot = ./.;
|
||||
pkgs = [ "glib" "xdg-utils" ];
|
||||
pkgs = [ "sane-open-desktop" "xdg-utils" ];
|
||||
};
|
||||
sandbox.enable = false; #< trivial script, and all our deps are sandboxed
|
||||
|
||||
suggestedPrograms = [
|
||||
"gdbus"
|
||||
"sane-open-desktop"
|
||||
"xdg-utils"
|
||||
];
|
||||
};
|
||||
|
||||
sane.programs.rofi-snippets = {
|
||||
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||
pname = "rofi-snippets";
|
||||
srcRoot = ./.;
|
||||
pkgs = [
|
||||
"gnused"
|
||||
"rofi"
|
||||
"wtype"
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
pkgs.copyDesktopItems
|
||||
];
|
||||
desktopItems = [
|
||||
(pkgs.makeDesktopItem {
|
||||
name = "rofi-snippets";
|
||||
exec = "rofi-snippets";
|
||||
desktopName = "rofi macro to insert common texts";
|
||||
})
|
||||
];
|
||||
};
|
||||
# if i could remove the sed, then maybe possible to not sandbox.
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".cache/rofi"
|
||||
".config/rofi/config.rasi"
|
||||
];
|
||||
|
||||
suggestedPrograms = [ "rofi" ];
|
||||
|
||||
fs.".config/rofi-snippets/public.txt".symlink.target = ./snippets.txt;
|
||||
secrets.".config/rofi-snippets/private.txt" = ../../../../secrets/common/snippets.txt.bin;
|
||||
};
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p glib -p xdg-utils
|
||||
#!nix-shell -i bash -p sane-open-desktop -p xdg-utils
|
||||
|
||||
# use:
|
||||
# rofi-run-command <handler>.desktop [cmd [args ...]]
|
||||
@@ -14,11 +14,13 @@ shift
|
||||
binArgs=("$@")
|
||||
|
||||
if [ "$desktop" != .desktop ]; then
|
||||
exec gdbus call --session --timeout 10 \
|
||||
--dest org.freedesktop.portal.Desktop \
|
||||
--object-path /org/freedesktop/portal/desktop \
|
||||
--method org.freedesktop.portal.DynamicLauncher.Launch \
|
||||
"$desktop" {}
|
||||
# launching an app; the file browser position is no longer interesting: clear it so it opens in ~ next time.
|
||||
# better UX would be to manage this in the other branch:
|
||||
# - open in ~ by default, regardless of last directory
|
||||
# - after launching a *file*, when that file is closed, re-open rofi in that file's directory.
|
||||
# however, `xdg-open` and the `OpenFile` xdg-desktop-portal API don't give any obvious way to block for the app to close.
|
||||
rm -f ~/.cache/rofi/rofi3.filebrowsercache
|
||||
exec sane-open-desktop "$desktop"
|
||||
elif [ "$binary" = "xdg-open" ]; then
|
||||
exec xdg-open "$@"
|
||||
fi
|
||||
|
10
hosts/common/programs/rofi/rofi-snippets
Executable file
10
hosts/common/programs/rofi/rofi-snippets
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gnused -p rofi -p wtype
|
||||
|
||||
# "bookmarking"/snippets inspired by Luke Smith:
|
||||
# - <https://www.youtube.com/watch?v=d_11QaTlf1I>
|
||||
|
||||
snippet=$(cat ~/.config/rofi-snippets/public.txt ~/.config/rofi-snippets/private.txt | \
|
||||
rofi -dmenu | \
|
||||
sed 's/ #.*$//')
|
||||
wtype "$snippet"
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user