From c37f3fc5e4c0d7616eef5608660a7f30d90a31f4 Mon Sep 17 00:00:00 2001 From: Hadi Date: Wed, 29 Jul 2026 10:32:10 +0200 Subject: [PATCH] ok Signed-off-by: Hadi --- home/programs/ghostty/default.nix | 11 +- home/programs/nvf/languages.nix | 3 +- home/system/clipboard/default.nix | 10 + home/system/hypridle/default.nix | 31 +++ home/system/hyprland/bindings.nix | 2 +- home/system/hyprland/default.nix | 6 + home/system/swaync/default.nix | 10 +- home/system/tofi/desktop-actions.nix | 185 +++++++++++++++++ home/system/waybar/default.nix | 2 +- home/system/waybar/scripts.nix | 287 ++++++++++++++++++++++++--- home/system/waybar/settings.nix | 3 +- hosts/laptop/home.nix | 4 +- hosts/work/configuration.nix | 3 +- hosts/work/home.nix | 2 + nixos/tuigreet.nix | 4 + todo | 9 - 16 files changed, 517 insertions(+), 55 deletions(-) create mode 100644 home/system/clipboard/default.nix create mode 100644 home/system/hypridle/default.nix diff --git a/home/programs/ghostty/default.nix b/home/programs/ghostty/default.nix index 292d0b2a..3196fda2 100644 --- a/home/programs/ghostty/default.nix +++ b/home/programs/ghostty/default.nix @@ -24,6 +24,9 @@ in { window-padding-x = 10; confirm-close-surface = false; window-padding-y = 10; + # Reuse a single background daemon (started at login, see hyprland exec-once) + # so every window opens instantly instead of cold-starting a new process. + gtk-single-instance = true; clipboard-read = "allow"; clipboard-write = "allow"; copy-on-select = "clipboard"; @@ -31,14 +34,6 @@ in { custom-shader = "${cursorShaders}/cursor_warp.glsl"; custom-shader-animation = "always"; keybind = [ - # "ctrl+j=goto_split:left" - # "ctrl+i=goto_split:up" - # "ctrl+k=goto_split:down" - # "ctrl+l=goto_split:right" - # "shift+ctrl+h=new_split:left" - # "shift+ctrl+j=new_split:down" - # "shift+ctrl+k=new_split:up" - # "shift+ctrl+l=new_split:right" "shift+ctrl+tab=new_tab" ]; }; diff --git a/home/programs/nvf/languages.nix b/home/programs/nvf/languages.nix index efc96f32..3a9b3f20 100644 --- a/home/programs/nvf/languages.nix +++ b/home/programs/nvf/languages.nix @@ -1,4 +1,4 @@ -{...}: { +{pkgs, ...}: { vim = { diagnostics = { enable = true; @@ -25,6 +25,7 @@ context.enable = true; highlight.enable = true; textobjects.enable = true; + grammars = [pkgs.vimPlugins.nvim-treesitter.grammarPlugins.http]; }; lsp = { enable = true; diff --git a/home/system/clipboard/default.nix b/home/system/clipboard/default.nix new file mode 100644 index 00000000..67a3a3af --- /dev/null +++ b/home/system/clipboard/default.nix @@ -0,0 +1,10 @@ +# Clipboard history: cliphist watches the Wayland clipboard and stores every +# entry (text + images) so it can be recalled later via the `clipboard-menu` +# script (tofi). Uses the home-manager module so the watcher services are +# managed the same way as swaync/hypridle. +{...}: { + services.cliphist = { + enable = true; + allowImages = true; + }; +} diff --git a/home/system/hypridle/default.nix b/home/system/hypridle/default.nix new file mode 100644 index 00000000..2de6d479 --- /dev/null +++ b/home/system/hypridle/default.nix @@ -0,0 +1,31 @@ +# hypridle handles idle management: lock the screen, turn the display off, and +# suspend after periods of inactivity. The `caffeine-toggle` script pauses it. +{...}: { + services.hypridle = { + enable = true; + settings = { + general = { + # Avoid starting multiple hyprlock instances. + lock_cmd = "pidof hyprlock || hyprlock"; + before_sleep_cmd = "loginctl lock-session"; + after_sleep_cmd = "hyprctl dispatch dpms on"; + }; + + listener = [ + { + timeout = 300; # 5 min → lock + on-timeout = "loginctl lock-session"; + } + { + timeout = 360; # 6 min → screen off + on-timeout = "hyprctl dispatch dpms off"; + on-resume = "hyprctl dispatch dpms on"; + } + { + timeout = 1800; # 30 min → suspend + on-timeout = "systemctl suspend"; + } + ]; + }; + }; +} diff --git a/home/system/hyprland/bindings.nix b/home/system/hyprland/bindings.nix index 067c50d7..a80c3433 100644 --- a/home/system/hyprland/bindings.nix +++ b/home/system/hyprland/bindings.nix @@ -124,7 +124,7 @@ in { ) # Quick launch - "$mod,RETURN, exec, uwsm app -- ${pkgs.ghostty}/bin/ghostty" # Ghostty (terminal) + "$mod,RETURN, exec, ${pkgs.ghostty}/bin/ghostty +new-window" # Ghostty (terminal, via daemon D-Bus) "$mod,E, exec, uwsm app -- ${pkgs-stable.thunar}/bin/thunar" # Thunar "$mod, SPACE, exec, tofi-drun" # Launcher "$mod, N, exec, swaync-client -t" # Notification center diff --git a/home/system/hyprland/default.nix b/home/system/hyprland/default.nix index 357ccafe..e8b2e634 100644 --- a/home/system/hyprland/default.nix +++ b/home/system/hyprland/default.nix @@ -38,6 +38,7 @@ in { hyprshot hyprpicker swappy + satty imv wf-recorder wlr-randr @@ -61,6 +62,10 @@ in { ",prefered,auto,1" # default ]; + exec-once = [ + "systemctl --user start app-com.mitchellh.ghostty.service" + ]; + env = [ "XDG_CURRENT_DESKTOP,Hyprland" "XDG_SESSION_TYPE,wayland" @@ -118,6 +123,7 @@ in { layerrule = [ "match:namespace launcher, animation popin 70%" + "match:namespace swaync-control-center, animation slide right" ]; windowrule = [ diff --git a/home/system/swaync/default.nix b/home/system/swaync/default.nix index aa7321e6..c4bd77ec 100644 --- a/home/system/swaync/default.nix +++ b/home/system/swaync/default.nix @@ -76,8 +76,8 @@ in { { label = "󰍭"; type = "toggle"; - command = "swayosd-client --input-volume mute-toggle"; - "update-command" = "wpctl get-volume @DEFAULT_SOURCE@ | grep -q MUTED && echo true || echo false"; + command = "mic-mute"; + "update-command" = "mic-status"; } { label = "󰌾"; @@ -111,7 +111,6 @@ in { --border-radius: ${toString rounding}px; --border-radius-s: ${toString gaps-in}px; --border-radius-xl: ${toString (rounding - 2)}px; - --shadow: 2px 4px 10px rgba(0,0,0,0.15); } .notification { padding: 5px; } @@ -210,7 +209,6 @@ in { .control-center .notification-background { background: @center-notification-bg; - box-shadow: var(--shadow); } .control-center .notification-background .close-button, @@ -272,7 +270,6 @@ in { .widget-mpris { border-radius: var(--border-radius); - box-shadow: var(--shadow); } .mpris-overlay { @@ -302,7 +299,6 @@ in { border-radius: var(--border-radius); padding: 10px 15px; background: @background-alt; - box-shadow: var(--shadow); color: @text; } @@ -343,7 +339,6 @@ in { padding: 10px 15px; border-radius: var(--border-radius); background: @background-alt; - box-shadow: var(--shadow); color: @text; } @@ -375,7 +370,6 @@ in { padding: 5px 15px; margin-bottom: 5px; background: @background-alt; - box-shadow: var(--shadow); } .widget-buttons-grid button { diff --git a/home/system/tofi/desktop-actions.nix b/home/system/tofi/desktop-actions.nix index e12c7f28..3e6791a5 100644 --- a/home/system/tofi/desktop-actions.nix +++ b/home/system/tofi/desktop-actions.nix @@ -90,6 +90,116 @@ terminal = false; }; + color-pick = { + name = "Pick Color"; + exec = "color-pick"; + icon = "color-select-symbolic"; + comment = "Pick a screen color to the clipboard"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "color;picker;hex;eyedropper;"; + }; + + screenshot-region = { + name = "Screenshot Region"; + exec = "hyprshot -m region"; + icon = "screenshot-recorded-symbolic"; + comment = "Capture a selected region"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "screenshot;capture;region;"; + }; + + screenshot-window = { + name = "Screenshot Window"; + exec = "hyprshot -m window"; + icon = "screenshot-recorded-symbolic"; + comment = "Capture the active window"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "screenshot;capture;window;"; + }; + + screenshot-screen = { + name = "Screenshot Screen"; + exec = "hyprshot -m output"; + icon = "screenshot-recorded-symbolic"; + comment = "Capture the whole screen"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "screenshot;capture;screen;monitor;"; + }; + + screenshot-edit = { + name = "Screenshot & Annotate"; + exec = "screenshot-edit"; + icon = "edit-symbolic"; + comment = "Capture a region and open it in Satty"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "screenshot;annotate;satty;edit;"; + }; + + record-toggle = { + name = "Screen Recording"; + exec = "record-toggle"; + icon = "media-record-symbolic"; + comment = "Start or stop screen recording"; + categories = ["Utility" "AudioVideo"]; + terminal = false; + settings.Keywords = "record;recording;screencast;video;"; + }; + + power-cycle = { + name = "Power Profile"; + exec = "power-cycle"; + icon = "power-profile-balanced-symbolic"; + comment = "Cycle power-saver / balanced / performance"; + categories = ["System"]; + terminal = false; + settings.Keywords = "power;profile;performance;battery;"; + }; + + airplane-toggle = { + name = "Airplane Mode"; + exec = "airplane-toggle"; + icon = "airplane-mode-symbolic"; + comment = "Toggle Wi-Fi and Bluetooth together"; + categories = ["System"]; + terminal = false; + settings.Keywords = "airplane;flight;wifi;bluetooth;offline;"; + }; + + clipboard-menu = { + name = "Clipboard History"; + exec = "clipboard-menu"; + icon = "edit-paste-symbolic"; + comment = "Pick a past clipboard entry"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "clipboard;history;paste;cliphist;"; + }; + + emoji-picker = { + name = "Emoji Picker"; + exec = "emoji-picker"; + icon = "face-smile-symbolic"; + comment = "Pick an emoji and type it"; + categories = ["Utility"]; + terminal = false; + settings.Keywords = "emoji;emoticon;smiley;symbol;"; + }; + + caffeine-toggle = { + name = "Keep Awake"; + exec = "caffeine-toggle"; + icon = "my-caffeine-on-symbolic"; + comment = "Pause or resume idle locking and suspend"; + categories = ["System"]; + terminal = false; + settings.Keywords = "caffeine;idle;awake;inhibit;suspend;"; + }; + logout = { name = "Logout"; exec = "hyprctl dispatch exit"; @@ -99,6 +209,81 @@ terminal = false; }; + dnd-toggle = { + name = "Do Not Disturb"; + exec = "dnd-toggle"; + icon = "notifications-disabled-symbolic"; + comment = "Toggle Do Not Disturb"; + categories = ["System"]; + terminal = false; + settings.Keywords = "dnd;notifications;disturb;swaync;silence;"; + }; + + vol-mute = { + name = "Mute Volume"; + exec = "vol-mute"; + icon = "audio-volume-muted-symbolic"; + comment = "Toggle output mute"; + categories = ["System"]; + terminal = false; + }; + + vol-up = { + name = "Volume Up"; + exec = "vol-up"; + icon = "audio-volume-high-symbolic"; + comment = "Raise the volume by 5%"; + categories = ["System"]; + terminal = false; + }; + + vol-down = { + name = "Volume Down"; + exec = "vol-down"; + icon = "audio-volume-low-symbolic"; + comment = "Lower the volume by 5%"; + categories = ["System"]; + terminal = false; + }; + + bright-up = { + name = "Brightness Up"; + exec = "bright-up"; + icon = "display-brightness-high-symbolic"; + comment = "Raise the brightness by 5%"; + categories = ["System"]; + terminal = false; + }; + + bright-down = { + name = "Brightness Down"; + exec = "bright-down"; + icon = "display-brightness-low-symbolic"; + comment = "Lower the brightness by 5%"; + categories = ["System"]; + terminal = false; + }; + + output-cycle = { + name = "Cycle Audio Output"; + exec = "output-cycle"; + icon = "audio-speakers-symbolic"; + comment = "Switch to the next audio output"; + categories = ["System"]; + terminal = false; + settings.Keywords = "audio;output;sink;speaker;headphones;"; + }; + + input-cycle = { + name = "Cycle Audio Input"; + exec = "input-cycle"; + icon = "audio-input-microphone-symbolic"; + comment = "Switch to the next audio input"; + categories = ["System"]; + terminal = false; + settings.Keywords = "audio;input;source;microphone;mic;"; + }; + spotatui = { name = "Spotify"; exec = "ghostty -e spotatui"; diff --git a/home/system/waybar/default.nix b/home/system/waybar/default.nix index 357e4c83..27bb342e 100644 --- a/home/system/waybar/default.nix +++ b/home/system/waybar/default.nix @@ -20,7 +20,7 @@ in { iw hyprsunset ] - ++ (with scripts; [vol-up vol-down vol-mute mic-mute bright-up bright-down nightshift-toggle focus-toggle waybar-toggle wifi-toggle bluetooth-toggle]); + ++ (with scripts; [vol-up vol-down vol-mute mic-mute bright-up bright-down nightshift-toggle focus-toggle waybar-toggle wifi-toggle bluetooth-toggle dnd-toggle output-cycle input-cycle color-pick screenshot-edit record-toggle power-cycle airplane-toggle clipboard-menu emoji-picker caffeine-toggle mic-status]); wayland.windowManager.hyprland.settings.exec-once = [ "waybar" diff --git a/home/system/waybar/scripts.nix b/home/system/waybar/scripts.nix index d239ba92..f1928a62 100644 --- a/home/system/waybar/scripts.nix +++ b/home/system/waybar/scripts.nix @@ -31,35 +31,111 @@ OSD_TEXT="󰃠 $BRIGHT%" fi ''; + + # Résout $src : source par défaut, sinon première source disponible. + # Certaines machines n'ont pas de source audio par défaut (@DEFAULT_AUDIO_SOURCE@ non résolu). + micSource = '' + src=$(${pkgs.wireplumber}/bin/wpctl inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') + if [ -z "$src" ]; then + src=$(${pkgs.pipewire}/bin/pw-dump | ${pkgs.jq}/bin/jq -r \ + '[.[] | select(.info.props."media.class"=="Audio/Source") | .id] | .[0] // empty') + fi + ''; + + # tofi en mode dmenu vertical : la config globale est un lanceur horizontal de + # 36px de haut, inutilisable pour une liste. On surcharge la géométrie. + tofiMenu = "${pkgs.tofi}/bin/tofi --horizontal false --anchor center --width 700 --height 500 --margin-top 0 --margin-left 0 --margin-right 0 --num-results 10"; in { bluetoothScript = pkgs.writeShellScript "waybar-bluetooth" '' - if bluetoothctl show 2>/dev/null | grep -q "Powered: yes"; then - device=$(bluetoothctl devices Connected 2>/dev/null | head -1 | cut -d' ' -f3-) - if [ -n "$device" ]; then - printf '{"text": "%s", "class": "connected", "tooltip": "Bluetooth\\n %s"}\n' "$device" "$device" - else - printf '{"text": "󰂰", "class": "on", "tooltip": "Bluetooth on"}\n' - fi + jq=${pkgs.jq}/bin/jq + nl=$'\n' + # bluetoothctl bloque sans contrôleur par défaut → toujours borné par timeout. + bt() { timeout 3 ${pkgs.bluez}/bin/bluetoothctl "$@" 2>/dev/null; } + + powered=$(bt show | awk '/Powered:/ { print $2; exit }') + if [ "$powered" != "yes" ]; then + "$jq" -cn '{ text: "󰂲", class: "off", tooltip: "Bluetooth off" }' + exit 0 + fi + + tip="" + add_tip() { tip="''${tip:+$tip$nl}$1"; } + + count=0 + for mac in $(bt devices Connected | awk '{ print $2 }'); do + count=$((count + 1)) + info=$(bt info "$mac") + name=$(printf '%s' "$info" | sed -n 's/^[[:space:]]*Name: //p' | head -1) + [ -z "$name" ] && name="$mac" + batt=$(printf '%s' "$info" | sed -n 's/.*Battery Percentage:.*(\([0-9][0-9]*\)).*/\1/p' | head -1) + add_tip "󰂱 $name''${batt:+ · $batt%}" + done + + if [ "$count" -gt 0 ]; then + "$jq" -cn --arg tooltip "$tip" '{ text: "󰂰", class: "connected", tooltip: $tooltip }' else - printf '{"text": "󰂲", "class": "off", "tooltip": "Bluetooth off"}\n' + "$jq" -cn '{ text: "󰂰", class: "on", tooltip: "Bluetooth on" }' fi ''; networkScript = pkgs.writeShellScript "waybar-network" '' - for iface in $(${pkgs.iproute2}/bin/ip -br link show | awk '$2 == "UP" {print $1}' | grep -vE '^(lo|tun|proton|wg[0-9]|ppp|vpn|docker|br-|veth|virbr)'); do - ip=$(${pkgs.iproute2}/bin/ip addr show "$iface" 2>/dev/null | grep 'inet ' | awk '{print $2}' | cut -d/ -f1 | head -1) - if [ -n "$ip" ]; then - if [[ "$iface" == wl* ]]; then - ssid=$(${pkgs.iw}/bin/iw dev "$iface" link 2>/dev/null | grep SSID | sed 's/.*SSID: //') - signal=$(${pkgs.iw}/bin/iw dev "$iface" link 2>/dev/null | grep signal | awk '{print $2}') - printf '{"text": "󰤨", "class": "wifi", "tooltip": " %s\\n %s dBm"}\n' "$ssid" "$signal" - else - printf '{"text": "󰛳", "class": "ethernet", "tooltip": " %s\\n %s"}\n' "$iface" "$ip" - fi - exit 0 + nmcli=${pkgs.networkmanager}/bin/nmcli + ip=${pkgs.iproute2}/bin/ip + jq=${pkgs.jq}/bin/jq + nl=$'\n' + + text="" + tip="" + class="disconnected" + add_seg() { text="''${text:+$text }$1"; } + add_tip() { tip="''${tip:+$tip$nl}$1"; } + + # ── Ethernet ──────────────────────────────────────────────── + eth=$("$nmcli" -t -f DEVICE,TYPE,STATE device status 2>/dev/null \ + | awk -F: '$2 == "ethernet" && $3 == "connected" { print $1; exit }') + if [ -n "$eth" ]; then + eth_ip=$("$ip" -4 -br addr show "$eth" 2>/dev/null | awk '{ print $3 }' | cut -d/ -f1) + add_seg "󰛳" + class="ethernet" + add_tip "󰛳 Ethernet''${eth_ip:+ · $eth_ip}" + fi + + # ── Wi-Fi ─────────────────────────────────────────────────── + wifi=$("$nmcli" -t -f ACTIVE,SSID,SIGNAL device wifi 2>/dev/null | grep -m1 '^yes:') + if [ -n "$wifi" ]; then + ssid=$(printf '%s' "$wifi" | cut -d: -f2) + signal=$(printf '%s' "$wifi" | cut -d: -f3) + if [ "''${signal:-0}" -ge 80 ]; then icon="󰤨" + elif [ "''${signal:-0}" -ge 60 ]; then icon="󰤥" + elif [ "''${signal:-0}" -ge 40 ]; then icon="󰤢" + elif [ "''${signal:-0}" -ge 20 ]; then icon="󰤟" + else icon="󰤯" fi - done - printf '{"text": "󰤭", "class": "disconnected", "tooltip": "Disconnected"}\n' + add_seg "$icon" + [ "$class" = "disconnected" ] && class="wifi" + add_tip "$icon ''${ssid:-Wi-Fi}''${signal:+ · $signal%}" + fi + + # ── VPN (nmcli, fallback interfaces) ──────────────────────── + vpn=$("$nmcli" -t -f TYPE,NAME connection show --active 2>/dev/null \ + | awk -F: '$1 == "vpn" || $1 == "wireguard" { print $2; exit }') + if [ -z "$vpn" ]; then + vpn=$("$ip" -br link show 2>/dev/null \ + | awk '($2 == "UP" || $2 == "UNKNOWN") && $1 ~ /^(tun|wg|proton|ppp)/ { sub(/@.*/, "", $1); print $1; exit }') + fi + if [ -n "$vpn" ]; then + add_seg "󰦝" + add_tip "󰦝 VPN · $vpn" + fi + + # ── Rien ──────────────────────────────────────────────────── + if [ -z "$text" ]; then + text="󰤭" + tip="Disconnected" + fi + + "$jq" -cn --arg text "$text" --arg class "$class" --arg tooltip "$tip" \ + '{ text: $text, class: $class, tooltip: $tooltip }' ''; vol-up = pkgs.writeShellScriptBin "vol-up" '' @@ -81,8 +157,12 @@ in { ''; mic-mute = pkgs.writeShellScriptBin "mic-mute" '' - ${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_SOURCE@ toggle - if ${pkgs.wireplumber}/bin/wpctl get-volume @DEFAULT_SOURCE@ | grep -q MUTED; then + wpctl=${pkgs.wireplumber}/bin/wpctl + ${micSource} + [ -z "$src" ] && exit 0 + + "$wpctl" set-mute "$src" toggle + if "$wpctl" get-volume "$src" | grep -q MUTED; then OSD_TEXT="󰍭 Muted" else OSD_TEXT="󰍬 Live" @@ -90,6 +170,15 @@ in { ${updateOsd} ''; + mic-status = pkgs.writeShellScriptBin "mic-status" '' + ${micSource} + if [ -n "$src" ] && ${pkgs.wireplumber}/bin/wpctl get-volume "$src" | grep -q MUTED; then + echo true + else + echo false + fi + ''; + bright-up = pkgs.writeShellScriptBin "bright-up" '' ${pkgs.brightnessctl}/bin/brightnessctl set 5%+ ${brightGetText} @@ -160,5 +249,157 @@ in { fi ''; + dnd-toggle = pkgs.writeShellScriptBin "dnd-toggle" '' + state=$(${pkgs.swaynotificationcenter}/bin/swaync-client -d) + if [ "$state" = "true" ]; then + OSD_TEXT="󰂛 Do Not Disturb On" + else + OSD_TEXT="󰂚 Do Not Disturb Off" + fi + ${updateOsd} + ''; + + output-cycle = pkgs.writeShellScriptBin "output-cycle" '' + wpctl=${pkgs.wireplumber}/bin/wpctl + jq=${pkgs.jq}/bin/jq + pwdump=${pkgs.pipewire}/bin/pw-dump + + # IDs des sinks dans l'ordre de pw-dump. + ids=($("$pwdump" | "$jq" -r '.[] | select(.info.props."media.class"=="Audio/Sink") | .id')) + n=''${#ids[@]} + [ "$n" -eq 0 ] && exit 0 + + cur=$("$wpctl" inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') + + next_index=0 + for i in "''${!ids[@]}"; do + if [ "''${ids[$i]}" = "$cur" ]; then + next_index=$(( (i + 1) % n )) + break + fi + done + next=''${ids[$next_index]} + + "$wpctl" set-default "$next" + desc=$("$pwdump" | "$jq" -r --argjson id "$next" '.[] | select(.id==$id) | .info.props."node.description"') + OSD_TEXT="󰓃 ''${desc:-Output}" + ${updateOsd} + ''; + + input-cycle = pkgs.writeShellScriptBin "input-cycle" '' + wpctl=${pkgs.wireplumber}/bin/wpctl + jq=${pkgs.jq}/bin/jq + pwdump=${pkgs.pipewire}/bin/pw-dump + + # IDs des sources dans l'ordre de pw-dump. + ids=($("$pwdump" | "$jq" -r '.[] | select(.info.props."media.class"=="Audio/Source") | .id')) + n=''${#ids[@]} + [ "$n" -eq 0 ] && exit 0 + + cur=$("$wpctl" inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') + + next_index=0 + for i in "''${!ids[@]}"; do + if [ "''${ids[$i]}" = "$cur" ]; then + next_index=$(( (i + 1) % n )) + break + fi + done + next=''${ids[$next_index]} + + "$wpctl" set-default "$next" + desc=$("$pwdump" | "$jq" -r --argjson id "$next" '.[] | select(.id==$id) | .info.props."node.description"') + OSD_TEXT="󰍬 ''${desc:-Input}" + ${updateOsd} + ''; + + color-pick = pkgs.writeShellScriptBin "color-pick" '' + # hyprpicker -a copie déjà la couleur dans le presse-papier. + color=$(${pkgs.hyprpicker}/bin/hyprpicker -a 2>/dev/null) + if [ -n "$color" ]; then + OSD_TEXT="󰈊 $color" + else + OSD_TEXT="󰈊 Cancelled" + fi + ${updateOsd} + ''; + + screenshot-edit = pkgs.writeShellScriptBin "screenshot-edit" '' + ${pkgs.hyprshot}/bin/hyprshot -m region --raw 2>/dev/null \ + | ${pkgs.satty}/bin/satty --filename - + ''; + + record-toggle = pkgs.writeShellScriptBin "record-toggle" '' + if pgrep -x wf-recorder >/dev/null; then + # -INT laisse wf-recorder finaliser le fichier proprement. + pkill -INT -x wf-recorder + OSD_TEXT="󰕧 Recording saved" + else + dir="$HOME/Videos" + mkdir -p "$dir" + file="$dir/rec-$(date +%Y%m%d-%H%M%S).mp4" + ${pkgs.wf-recorder}/bin/wf-recorder -f "$file" >/dev/null 2>&1 & + OSD_TEXT="󰑊 Recording…" + fi + ${updateOsd} + ''; + + power-cycle = pkgs.writeShellScriptBin "power-cycle" '' + ppd=${pkgs.power-profiles-daemon}/bin/powerprofilesctl + cur=$("$ppd" get) + case "$cur" in + power-saver) next=balanced; icon="󰾅" ;; + balanced) next=performance; icon="󰓅" ;; + performance) next=power-saver; icon="󰌪" ;; + *) next=balanced; icon="󰾅" ;; + esac + "$ppd" set "$next" + OSD_TEXT="$icon ''${next^}" + ${updateOsd} + ''; + + airplane-toggle = pkgs.writeShellScriptBin "airplane-toggle" '' + # Réutilise nmcli + bluetoothctl (sans privilège) plutôt que rfkill. + on=false + nmcli radio wifi 2>/dev/null | grep -q enabled && on=true + bluetoothctl show 2>/dev/null | grep -q "Powered: yes" && on=true + if $on; then + nmcli radio wifi off 2>/dev/null + bluetoothctl power off >/dev/null 2>&1 || true + OSD_TEXT="󰀝 Airplane On" + else + nmcli radio wifi on 2>/dev/null + bluetoothctl power on >/dev/null 2>&1 || true + OSD_TEXT="󰀞 Airplane Off" + fi + ${updateOsd} + ''; + + clipboard-menu = pkgs.writeShellScriptBin "clipboard-menu" '' + ${pkgs.cliphist}/bin/cliphist list \ + | ${tofiMenu} --prompt-text "Clipboard: " \ + | ${pkgs.cliphist}/bin/cliphist decode \ + | ${pkgs.wl-clipboard}/bin/wl-copy + ''; + + emoji-picker = pkgs.writeShellScriptBin "emoji-picker" '' + export PATH="${pkgs.wtype}/bin:${pkgs.wl-clipboard}/bin:$PATH" + export BEMOJI_PICKER_CMD="${tofiMenu} --prompt-text 'emoji: '" + # -t tape l'emoji (wtype), -c le copie aussi. + exec ${pkgs.bemoji}/bin/bemoji -t -c + ''; + + caffeine-toggle = pkgs.writeShellScriptBin "caffeine-toggle" '' + # Met hypridle en pause (reste éveillé) ou le réactive. + if systemctl --user is-active --quiet hypridle; then + systemctl --user stop hypridle + OSD_TEXT="󰅶 Keep Awake On" + else + systemctl --user start hypridle + OSD_TEXT="󰾫 Keep Awake Off" + fi + ${updateOsd} + ''; + # TODO: Run in background } diff --git a/home/system/waybar/settings.nix b/home/system/waybar/settings.nix index be284c8e..0ad43121 100644 --- a/home/system/waybar/settings.nix +++ b/home/system/waybar/settings.nix @@ -1,5 +1,6 @@ { config, + pkgs, networkScript, bluetoothScript, ... @@ -48,7 +49,7 @@ in { "custom/bluetooth" = { exec = "${bluetoothScript}"; - exec-if = "bluetoothctl show 2>/dev/null | grep -q Controller"; + exec-if = "${pkgs.bluez}/bin/bluetoothctl list 2>/dev/null | grep -q Controller"; return-type = "json"; interval = 5; on-click-right = "blueman-manager &"; diff --git a/hosts/laptop/home.nix b/hosts/laptop/home.nix index 474e3203..e3a54763 100644 --- a/hosts/laptop/home.nix +++ b/hosts/laptop/home.nix @@ -15,7 +15,6 @@ ../../home/programs/nix-utils ../../home/programs/spotatui ../../home/programs/yazi - ../../home/programs/desktop-actions # TODO: ../../home/programs/group/basic-apps.nix ../../home/programs/group/cybersecurity.nix @@ -27,10 +26,11 @@ ../../home/system/hyprland ../../home/system/waybar ../../home/system/swaync - ../../home/system/swayosd ../../home/system/tofi ../../home/system/mime ../../home/system/udiskie + ../../home/system/clipboard + ../../home/system/hypridle ./variables.nix # Mostly user-specific configuration ./secrets # CHANGEME: You should probably remove this line, this is where I store my secrets diff --git a/hosts/work/configuration.nix b/hosts/work/configuration.nix index 438e88f2..3c984518 100644 --- a/hosts/work/configuration.nix +++ b/hosts/work/configuration.nix @@ -11,6 +11,7 @@ ../../nixos/users.nix ../../nixos/utils.nix ../../nixos/hyprland.nix + ../../nixos/docker.nix ../../home/programs/helium/system.nix # I hate browser's configuration.. # You should let those lines as is @@ -28,9 +29,9 @@ services.usbguard.rules = '' allow id 1d6b:0002 serial "0000:00:14.0" name "xHCI Host Controller" hash "jEP/6WzviqdJ5VSeTUY8PatCNBKeaREvo2OqdplND/o=" parent-hash "rV9bfLq7c2eA4tYjVjwO4bxhm+y6GgZpl9J60L0fBkY=" with-interface 09:00:00 with-connect-type "" allow id 1d6b:0003 serial "0000:00:14.0" name "xHCI Host Controller" hash "prM+Jby/bFHCn2lNjQdAMbgc6tse3xVx+hZwjOPHSdQ=" parent-hash "rV9bfLq7c2eA4tYjVjwO4bxhm+y6GgZpl9J60L0fBkY=" with-interface 09:00:00 with-connect-type "" - allow id 17ef:608d serial "" name "Lenovo USB Optical Mouse" hash "klpDZuv1jhWGNqZLOl+KXF+75Ir3PfBm6D6ncjoLRBU=" parent-hash "jEP/6WzviqdJ5VSeTUY8PatCNBKeaREvo2OqdplND/o=" via-port "1-7" with-interface 03:01:02 with-connect-type "hotplug" allow id 17ef:6190 serial "" name "Lenovo Calliope USB Keyboard G2" hash "CfZ9R/aoXGm7BN/ojVEzKQwVoxCUtRWMuACrE7BL/5Y=" parent-hash "jEP/6WzviqdJ5VSeTUY8PatCNBKeaREvo2OqdplND/o=" via-port "1-10" with-interface { 03:01:01 03:00:00 } with-connect-type "hotplug" allow id 0781:5581 name " SanDisk 3.2Gen1" + allow id 17ef:608d name "Lenovo USB Optical Mouse" ''; networking.firewall.allowedTCPPorts = [9001]; diff --git a/hosts/work/home.nix b/hosts/work/home.nix index 875904e7..72c3ab39 100644 --- a/hosts/work/home.nix +++ b/hosts/work/home.nix @@ -27,6 +27,8 @@ ../../home/system/tofi ../../home/system/mime ../../home/system/udiskie + ../../home/system/clipboard + ../../home/system/hypridle ./variables.nix # Mostly user-specific configuration ./secrets # CHANGEME: You should probably remove this line, this is where I store my secrets diff --git a/nixos/tuigreet.nix b/nixos/tuigreet.nix index 126b02b9..23197276 100644 --- a/nixos/tuigreet.nix +++ b/nixos/tuigreet.nix @@ -47,6 +47,10 @@ in { # literally no documentation about this anywhere. # might be good to write about this... # https://www.reddit.com/r/NixOS/comments/u0cdpi/tuigreet_with_xmonad_how/ + # Unlock the gnome-keyring with the login password so apps (browser + # secrets via libsecret, ProtonVPN credentials, …) don't reprompt. + security.pam.services.greetd.enableGnomeKeyring = true; + systemd.services.greetd.serviceConfig = { Type = "idle"; StandardInput = "tty"; diff --git a/todo b/todo index 057aaa95..9f50e7fe 100644 --- a/todo +++ b/todo @@ -1,12 +1,3 @@ -- [ ] Configuration waybar -- [ ] Configuration sway-nc -- [ ] Configuration sway-osd -- [ ] Configuration hyprlock -- [x] Gaming/Focus mode -- [ ] Configuration Rofi/Drun -- [ ] Helium plus rapide ? service/deamon ? -- [ ] Ghostty service/deamon ? -- [ ] Tofi service/deamon ? - [ ] Clean files - [ ] NVF dans Nur - [ ] Check claude: Sécu, mots en français, faute, ...