summaryrefslogtreecommitdiff
path: root/users/kassouni
diff options
context:
space:
mode:
Diffstat (limited to 'users/kassouni')
-rw-r--r--users/kassouni/firefox.nix2
-rw-r--r--users/kassouni/home.nix2
-rw-r--r--users/kassouni/palette/bluetooth.nix80
-rw-r--r--users/kassouni/palette/default.nix54
-rw-r--r--users/kassouni/palette/kbd-backlight.nix20
-rw-r--r--users/kassouni/palette/reboot.nix18
-rw-r--r--users/kassouni/palette/rebuild.nix40
-rw-r--r--users/kassouni/palette/screenshot.nix18
-rw-r--r--users/kassouni/palette/shutdown.nix18
-rw-r--r--users/kassouni/wayland/default.nix8
-rw-r--r--users/kassouni/wayland/fuzzel.nix (renamed from users/kassouni/fuzzel.nix)0
-rw-r--r--users/kassouni/wayland/sway.nix39
-rw-r--r--users/kassouni/wayland/waybar.nix115
-rw-r--r--users/kassouni/xbindkeys.nix32
14 files changed, 398 insertions, 48 deletions
diff --git a/users/kassouni/firefox.nix b/users/kassouni/firefox.nix
index e1cee19..9bf130c 100644
--- a/users/kassouni/firefox.nix
+++ b/users/kassouni/firefox.nix
@@ -61,6 +61,7 @@
};
settings = {
"browser.startup.homepage" = "about:blank";
+ "browser.compactmode.show" = true;
"startup.homepage_welcome_url" = "about:blank";
"extensions.autoDisableScopes" = 0;
"browser.newtabpage.enabled" = false;
@@ -71,6 +72,7 @@
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
"browser.newtabpage.activity-stream.widgets.enabled" = false;
"browser.newtabpage.activity-stream.discoverystream.sections.enabled" = false;
+
};
search = {
force = true;
diff --git a/users/kassouni/home.nix b/users/kassouni/home.nix
index 1b9fe48..6242863 100644
--- a/users/kassouni/home.nix
+++ b/users/kassouni/home.nix
@@ -8,7 +8,6 @@
imports = [
./neovim.nix
./claude.nix
- ./fuzzel.nix
./rofi.nix
./music.nix
./fonts.nix
@@ -22,6 +21,7 @@
./firefox.nix
./cursor.nix
./bash.nix
+ ./xbindkeys.nix
./scripts
./palette
];
diff --git a/users/kassouni/palette/bluetooth.nix b/users/kassouni/palette/bluetooth.nix
new file mode 100644
index 0000000..58cdf2f
--- /dev/null
+++ b/users/kassouni/palette/bluetooth.nix
@@ -0,0 +1,80 @@
+{ pkgs, config, ...}:
+{
+
+ kassouni.palette.commands = [
+ {
+ name = "toggle bluetooth device";
+ icon = "󰂯";
+ # `jc --bluetoothctl` turns `bluetoothctl devices` into JSON, so the menu is
+ # built from parsed records rather than by splitting "Device <addr> <name>"
+ # lines. That subcommand leaves every status field empty, so connectedness
+ # comes from a second `devices Connected` call intersected on address.
+ exe = pkgs.writers.writePython3 "bluetooth-toggle" {
+ # The interpolated store paths below are longer than 79 columns.
+ flakeIgnore = [ "E501" ];
+ } ''
+ import html
+ import json
+ import subprocess
+ import sys
+
+ BT = "${pkgs.bluez}/bin/bluetoothctl"
+ JC = "${pkgs.jc}/bin/jc"
+ ROFI = "${pkgs.rofi}/bin/rofi"
+
+
+ def devices(*args):
+ """Parse `bluetoothctl devices [args]` into a list of records."""
+ listed = subprocess.run(
+ [BT, "devices", *args], capture_output=True, text=True
+ )
+ parsed = subprocess.run(
+ [JC, "--bluetoothctl"],
+ input=listed.stdout,
+ capture_output=True,
+ text=True,
+ )
+ return json.loads(parsed.stdout or "[]")
+
+
+ def label(device, connected):
+ """Pango markup row. Names are escaped, they are not our text."""
+ name = html.escape(device["name"])
+ if device["address"] in connected:
+ name += ' <span alpha="45%">connected</span>'
+ return name
+
+
+ def main():
+ known = devices()
+ if not known:
+ return 0
+
+ # Older bluez has no `devices Connected`; that call just comes back
+ # empty there, which degrades to "nothing is connected".
+ connected = {d["address"] for d in devices("Connected")}
+
+ rows = [label(d, connected) for d in known]
+ choice = subprocess.run(
+ [ROFI, "-dmenu", "-i", "-markup-rows", "-format", "i",
+ "-p", "bluetooth"],
+ input="\n".join(rows),
+ capture_output=True,
+ text=True,
+ )
+ if choice.returncode != 0:
+ return 1
+
+ device = known[int(choice.stdout.strip())]
+ action = (
+ "disconnect" if device["address"] in connected else "connect"
+ )
+ return subprocess.run([BT, action, device["address"]]).returncode
+
+
+ if __name__ == "__main__":
+ sys.exit(main())
+ '';
+ }
+ ];
+}
diff --git a/users/kassouni/palette/default.nix b/users/kassouni/palette/default.nix
index 235f774..7e9eec4 100644
--- a/users/kassouni/palette/default.nix
+++ b/users/kassouni/palette/default.nix
@@ -1,18 +1,56 @@
-{ pkgs, lib, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
let
- commandFiles = lib.attrNames (
- lib.filterAttrs (name: type: type == "regular" && name != "default.nix" && lib.hasSuffix ".nix" name)
- (builtins.readDir ./.)
+ cfg = config.kassouni.palette;
+
+ # Every sibling .nix file is an ordinary home-manager module that appends to
+ # kassouni.palette.commands, so dropping a file in here adds an entry.
+ commandModules = map (file: ./. + "/${file}") (
+ lib.attrNames (
+ lib.filterAttrs (name: type: type == "regular" && name != "default.nix" && lib.hasSuffix ".nix" name)
+ (builtins.readDir ./.)
+ )
);
- commands = map (file: pkgs.callPackage (./. + "/${file}") { }) commandFiles;
in
{
- home.packages = [
+ imports = commandModules;
+
+ options.kassouni.palette.commands = lib.mkOption {
+ type = lib.types.listOf (
+ lib.types.submodule {
+ options = {
+ name = lib.mkOption {
+ type = lib.types.str;
+ description = "Label shown in the palette menu.";
+ };
+ icon = lib.mkOption {
+ type = lib.types.str;
+ description = "Nerd Font glyph shown before the label.";
+ };
+ exe = lib.mkOption {
+ type = lib.types.package;
+ description = "Executable to run when the entry is selected.";
+ };
+ };
+ }
+ );
+ default = [ ];
+ description = ''
+ Entries shown in the rofi command palette. Menu order follows module
+ import order, which is alphabetical by filename.
+ '';
+ };
+
+ config.home.packages = [
(pkgs.writers.writeBashBin "open-palette" ''
set -eu
- exes=(${lib.concatMapStringsSep " " (c: c.exe) commands})
+ exes=(${lib.concatMapStringsSep " " (c: "${c.exe}") cfg.commands})
idx=$(${pkgs.rofi}/bin/rofi -dmenu -i -format i -p palette <<EOF
-${lib.concatMapStrings (c: "${c.icon} ${c.name}\n") commands}EOF
+${lib.concatMapStrings (c: "${c.icon} ${c.name}\n") cfg.commands}EOF
)
exec "''${exes[$idx]}"
'')
diff --git a/users/kassouni/palette/kbd-backlight.nix b/users/kassouni/palette/kbd-backlight.nix
new file mode 100644
index 0000000..9da0fb9
--- /dev/null
+++ b/users/kassouni/palette/kbd-backlight.nix
@@ -0,0 +1,20 @@
+{ pkgs, ... }:
+{
+ kassouni.palette.commands = [
+ {
+ name = "toggle keyboard backlight";
+ icon = "󰌌";
+ # The leds sysfs node is group-writable by `video`, which kassouni is in, so
+ # this needs no root. Toggle between off and full rather than cycling levels.
+ exe = pkgs.writers.writeBash "kbd-backlight" ''
+ set -eu
+ dev=framework_laptop::kbd_backlight
+ if [ "$(${pkgs.brightnessctl}/bin/brightnessctl -d "$dev" get)" -gt 0 ]; then
+ ${pkgs.brightnessctl}/bin/brightnessctl -d "$dev" set 0
+ else
+ ${pkgs.brightnessctl}/bin/brightnessctl -d "$dev" set 100%
+ fi
+ '';
+ }
+ ];
+}
diff --git a/users/kassouni/palette/reboot.nix b/users/kassouni/palette/reboot.nix
index bc25ef4..09b2efe 100644
--- a/users/kassouni/palette/reboot.nix
+++ b/users/kassouni/palette/reboot.nix
@@ -1,9 +1,13 @@
-{ writers, systemd }:
+{ pkgs, ... }:
{
- name = "reboot";
- icon = "󰑐";
- exe = writers.writeBash "reboot" ''
- set -eu
- exec ${systemd}/bin/systemctl reboot
- '';
+ kassouni.palette.commands = [
+ {
+ name = "reboot";
+ icon = "󰑐";
+ exe = pkgs.writers.writeBash "reboot" ''
+ set -eu
+ exec ${pkgs.systemd}/bin/systemctl reboot
+ '';
+ }
+ ];
}
diff --git a/users/kassouni/palette/rebuild.nix b/users/kassouni/palette/rebuild.nix
index e42a7c5..edffa6b 100644
--- a/users/kassouni/palette/rebuild.nix
+++ b/users/kassouni/palette/rebuild.nix
@@ -1,20 +1,24 @@
-{ writers, ghostty }:
+{ pkgs, ... }:
{
- name = "rebuild";
- icon = "󱄅";
- # Rebuilds need a terminal: sudo prompts for a password and nixos-rebuild
- # streams a lot of output. Spawn ghostty with a login shell so it inherits
- # the system sudo (setuid) and the user's nix from PATH. Mirrors `make rebuild`.
- exe = writers.writeBash "rebuild" ''
- set -eu
- exec ${ghostty}/bin/ghostty -e bash -lc '
- set -eu
- cd /home/kassouni/Developer/nixos-config
- nix flake update xmonad-config
- sudo nixos-rebuild switch --flake .
- echo
- echo "Rebuild finished. Press enter to close."
- read -r _
- '
- '';
+ kassouni.palette.commands = [
+ {
+ name = "rebuild";
+ icon = "󱄅";
+ # Rebuilds need a terminal: sudo prompts for a password and nixos-rebuild
+ # streams a lot of output. Spawn ghostty with a login shell so it inherits
+ # the system sudo (setuid) and the user's nix from PATH. Mirrors `make rebuild`.
+ exe = pkgs.writers.writeBash "rebuild" ''
+ set -eu
+ exec ${pkgs.ghostty}/bin/ghostty -e bash -lc '
+ set -eu
+ cd /home/kassouni/Developer/nixos-config
+ nix flake update xmonad-config
+ sudo nixos-rebuild switch --flake .
+ echo
+ echo "Rebuild finished. Press enter to close."
+ read -r _
+ '
+ '';
+ }
+ ];
}
diff --git a/users/kassouni/palette/screenshot.nix b/users/kassouni/palette/screenshot.nix
index 6f2beea..00d11d1 100644
--- a/users/kassouni/palette/screenshot.nix
+++ b/users/kassouni/palette/screenshot.nix
@@ -1,9 +1,13 @@
-{ writers, maim, xclip }:
+{ pkgs, ... }:
{
- name = "screenshot";
- icon = "󰹑";
- exe = writers.writeBash "screenshot" ''
- set -eu
- ${maim}/bin/maim -s | ${xclip}/bin/xclip -selection clipboard -t image/png
- '';
+ kassouni.palette.commands = [
+ {
+ name = "screenshot";
+ icon = "󰹑";
+ exe = pkgs.writers.writeBash "screenshot" ''
+ set -eu
+ ${pkgs.maim}/bin/maim -s | ${pkgs.xclip}/bin/xclip -selection clipboard -t image/png
+ '';
+ }
+ ];
}
diff --git a/users/kassouni/palette/shutdown.nix b/users/kassouni/palette/shutdown.nix
index 2db9425..28f8d8f 100644
--- a/users/kassouni/palette/shutdown.nix
+++ b/users/kassouni/palette/shutdown.nix
@@ -1,9 +1,13 @@
-{ writers, systemd }:
+{ pkgs, ... }:
{
- name = "shutdown";
- icon = "󰐥";
- exe = writers.writeBash "shutdown" ''
- set -eu
- exec ${systemd}/bin/systemctl poweroff
- '';
+ kassouni.palette.commands = [
+ {
+ name = "shutdown";
+ icon = "󰐥";
+ exe = pkgs.writers.writeBash "shutdown" ''
+ set -eu
+ exec ${pkgs.systemd}/bin/systemctl poweroff
+ '';
+ }
+ ];
}
diff --git a/users/kassouni/wayland/default.nix b/users/kassouni/wayland/default.nix
new file mode 100644
index 0000000..947924a
--- /dev/null
+++ b/users/kassouni/wayland/default.nix
@@ -0,0 +1,8 @@
+{...}: {
+ imports = [
+ ./waybar.nix
+ ./sway.nix
+ ./fuzzel.nix
+ ];
+}
+
diff --git a/users/kassouni/fuzzel.nix b/users/kassouni/wayland/fuzzel.nix
index a716b2b..a716b2b 100644
--- a/users/kassouni/fuzzel.nix
+++ b/users/kassouni/wayland/fuzzel.nix
diff --git a/users/kassouni/wayland/sway.nix b/users/kassouni/wayland/sway.nix
new file mode 100644
index 0000000..0cf97f7
--- /dev/null
+++ b/users/kassouni/wayland/sway.nix
@@ -0,0 +1,39 @@
+{
+ pkgs,
+ config,
+ ...
+}:
+{
+ programs.swaylock.enable = true;
+ wayland.windowManager.sway = {
+ enable = true;
+ wrapperFeatures.gtk = true; # Fixes common issues with GTK 3 apps
+
+ config = {
+ window.titlebar = false;
+ menu = "fuzzel";
+ gaps = {
+ };
+ modifier = "Mod4";
+ # Use kitty as default terminal
+ terminal = "foot";
+ };
+ extraConfig = let incr = "5"; in ''
+ output * scale 2
+ bindsym XF86MonBrightnessDown exec brightnessctl set -e 5%-
+ bindsym XF86MonBrightnessUp exec brightnessctl set -e +5%
+ bindsym XF86AudioRaiseVolume exec wpctl set-volume @DEFAULT_SINK@ ${incr}%+
+ bindsym XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_SINK@ ${incr}%-
+ input "type:keyboard" {
+ xkb_options caps:escape
+ }
+
+ input "type:touchpad" {
+ natural_scroll enabled
+ dwt disabled
+ }
+ '';
+
+ };
+}
+
diff --git a/users/kassouni/wayland/waybar.nix b/users/kassouni/wayland/waybar.nix
new file mode 100644
index 0000000..3026c2f
--- /dev/null
+++ b/users/kassouni/wayland/waybar.nix
@@ -0,0 +1,115 @@
+{ pkgs, inputs, config, ... }:
+{
+ programs.waybar = {
+ enable = true;
+ settings = {
+ mainBar =
+ let
+ gap = 0;
+ in
+ {
+ layer = "top";
+ position = "top";
+
+ margin-top = gap;
+ margin-left = gap;
+ margin-right = gap;
+
+ modules-left = [ "sway/workspaces" ];
+ modules-center = [ ];
+ modules-right = [
+ "cpu"
+ "wireplumber"
+ "battery"
+ "clock"
+ ];
+
+ clock = {
+ format = "{:%a %b %d %I:%M:%S}";
+ interval = 1;
+ tooltip-format = "<tt>{calendar}</tt>";
+ };
+
+ cpu = {
+ format = " {usage}%";
+ };
+
+ battery = {
+ format = "{icon} {capacity}%";
+ format-icons = {
+ default = [
+ "󰂎"
+ "󰁺"
+ "󰁻"
+ "󰁼"
+ "󰁽"
+ "󰁾"
+ "󰁿"
+ "󰂀"
+ "󰂁"
+ "󰂂"
+ "󰁹"
+ ];
+
+ charging = [
+ "󰢜"
+ "󰂆"
+ "󰂇"
+ "󰂈"
+ "󰢝"
+ "󰂉"
+ "󰢞"
+ "󰂊"
+ "󰂋"
+ "󰂅"
+ ];
+ };
+
+
+ states = {
+ low = 20;
+ };
+ };
+
+ wireplumber = {
+ format = "󰋋 {volume}%";
+ format-muted = "󰟎 {volume}%";
+ on-click = "wpctl set-mute @DEFAULT_SINK@ toggle";
+ max-volume = 150;
+ scroll-step = 1;
+ };
+
+ };
+ };
+ style = ''
+ .module {
+ padding: 0px 15px 0px;
+ }
+
+ #workspaces button {
+ font-family: ${config.theme.font.family};
+ font-size: ${builtins.toString config.theme.font.size}px;
+ font-weight: normal;
+ }
+
+ #workspaces button.focused {
+ }
+
+ #workspaces button:hover {
+ font-weight: bold;
+ box-shadow: none;
+ text-shadow: inherit;
+ background: none;
+ transition: none;
+ }
+
+ '';
+ };
+
+ wayland.windowManager.sway.config.bars = [
+ {
+ command = "waybar";
+ }
+ ];
+}
+
diff --git a/users/kassouni/xbindkeys.nix b/users/kassouni/xbindkeys.nix
new file mode 100644
index 0000000..41ef7ed
--- /dev/null
+++ b/users/kassouni/xbindkeys.nix
@@ -0,0 +1,32 @@
+{ pkgs, ... }:
+let
+ wpctl = "${pkgs.wireplumber}/bin/wpctl";
+
+ xbindkeysrc = pkgs.writeText "xbindkeysrc" ''
+ "${wpctl} set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+"
+ XF86AudioRaiseVolume
+
+ "${wpctl} set-volume @DEFAULT_AUDIO_SINK@ 5%-"
+ XF86AudioLowerVolume
+
+ "${wpctl} set-mute @DEFAULT_AUDIO_SINK@ toggle"
+ XF86AudioMute
+ '';
+in
+{
+ systemd.user.services.xbindkeys = {
+ Unit = {
+ Description = "xbindkeys";
+ PartOf = [ "graphical-session.target" ];
+ After = [ "graphical-session.target" ];
+ };
+
+ Service = {
+ # -n keeps it in the foreground so systemd can supervise it
+ ExecStart = "${pkgs.xbindkeys}/bin/xbindkeys -n -f ${xbindkeysrc}";
+ Restart = "on-failure";
+ };
+
+ Install.WantedBy = [ "graphical-session.target" ];
+ };
+}