diff options
Diffstat (limited to 'users')
| -rw-r--r-- | users/kassouni/firefox.nix | 2 | ||||
| -rw-r--r-- | users/kassouni/home.nix | 2 | ||||
| -rw-r--r-- | users/kassouni/palette/bluetooth.nix | 80 | ||||
| -rw-r--r-- | users/kassouni/palette/default.nix | 54 | ||||
| -rw-r--r-- | users/kassouni/palette/kbd-backlight.nix | 20 | ||||
| -rw-r--r-- | users/kassouni/palette/reboot.nix | 18 | ||||
| -rw-r--r-- | users/kassouni/palette/rebuild.nix | 40 | ||||
| -rw-r--r-- | users/kassouni/palette/screenshot.nix | 18 | ||||
| -rw-r--r-- | users/kassouni/palette/shutdown.nix | 18 | ||||
| -rw-r--r-- | users/kassouni/wayland/default.nix | 8 | ||||
| -rw-r--r-- | users/kassouni/wayland/fuzzel.nix (renamed from users/kassouni/fuzzel.nix) | 0 | ||||
| -rw-r--r-- | users/kassouni/wayland/sway.nix | 39 | ||||
| -rw-r--r-- | users/kassouni/wayland/waybar.nix | 115 | ||||
| -rw-r--r-- | users/kassouni/xbindkeys.nix | 32 |
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" ]; + }; +} |
