From 7daca57714e1a4e613833b7e28c3abf18ab8f7c0 Mon Sep 17 00:00:00 2001 From: nocode Date: Wed, 24 Jun 2026 17:58:52 +0200 Subject: [PATCH 001/136] feat(anaconda): add desktop environment selection spoke for FWS Implement a new Anaconda spoke that allows users to select their preferred desktop environment (CLI, GNOME, KDE Plasma, Hyprland, or XFCE) during installation. The spoke: - Displays radio buttons for five desktop choices with CLI as the default - Persists the selection to /tmp/fws-desktop for the kickstart %post script - Supports revisiting the spoke and resuming previous selections - Includes a GTK UI definition file (glade) with translatable labels - Integrates as a SoftwareCategory spoke in the Anaconda installer The implementation leverages Anaconda's runtime spoke discovery mechanism via the airootfs overlay, avoiding the need to rebuild the anaconda package. --- .../__pycache__/fws_desktop.cpython-314.pyc | Bin 0 -> 4538 bytes .../pyanaconda/ui/gui/spokes/fws_desktop.py | 105 ++++++++++++ .../anaconda/ui/spokes/fws_desktop.glade | 153 ++++++++++++++++++ .../share/anaconda/interactive-defaults.ks | 2 + 4 files changed, 260 insertions(+) create mode 100644 configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/__pycache__/fws_desktop.cpython-314.pyc create mode 100644 configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_desktop.py create mode 100644 configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_desktop.glade diff --git a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/__pycache__/fws_desktop.cpython-314.pyc b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/__pycache__/fws_desktop.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c8dabfc81f29a11f55176b6acc950c0785ff6e8 GIT binary patch literal 4538 zcma)AU2GHC6}~f`vB&oKFC=kD9AZeCV6w4cpO=KP?1=puh{EG;4B#&-Aw-Xy@XfKjS^% zakR{U;O|DM@V`hgMO&W1anYj06lFyx^*M81!t$VG%6T0xKwWTL#|259Eb13!D>6Ja zd0aLwntIWx@MKlx)s8{EP>{4-QdKlLscY&&a<`@@bB? z6B2xJbif_b43oW^5y1~KDg;2rgdoVKnQa1Jr`HVSP+hqN%Hg_lE0iO3<+uve7W9 zv=s$Axh9@cw46S_*k%yh8^nO3Yru3~m2&c8PZ7&=GM2ThT(j*!PBDtAv@l>S6lQf* z$u9a&{ABd9?XJaU(H%NDrlrYbv^S2jLKO-+&*oX0y6Br{s;ytON=Gmy85P(#<&| zQ!;QyRc15A1@nTg?N9GJkTDcf9wo4O3vzRz-;=p<}|FzAnq%pXI>QT!*D=R);&*g+V(qOMvd z-<{|zN>gX4)71C9JE1F_RH)Hvni*1Z&mnTHi#g~xo?8d(%QXFU_Ks@~?eN+uJ;#to_3R%8T<{8cHo3!P)OUgHm8gdFTNfu@dXwLOqy zMt(`ukNVs>@?fh3Qs5Hk1Q?OOll_N0ok*dQXu7q!5HHHX6_S9~PJ09eIXZw9uZUH%|WLKqY*Kc{~9_@a~LKF1-?gfXU@fV2l$1Fa& z?t$+sV-GCuZfksyMt29gj%C<;d>7>JWrD|!`0xFQgZzCuI2iNXk5V9CV-#}!?F02^ zdxHQJ_%@~qqScTHa`gHFPM#M_T7pz0_^U@sXQn}FjqL5_Yy66mTXaGML; zl*i$)GeBZCbUc712OR+eP$j`da7j+l4nSx;>u{HY1RGFVxS~)lmOhXm}+weB1o}Zzqu%RP_zF7PYg{y!-0r#8jCz1^w=0Q8os(HlJnzDuC7AW#xLQH}8G>{#tp z^OvLFjnGtd^LFS$r)ZbRYScJgM;XkV=o2(8$xVzE-Os4iG7jX1Ka$B6zV5P+h1$BoO^FR#T@58|oE@&2U~z$lT} zr$4{B>(;=R1Gh52%K!^}#y^R+JoBNpch)(^<&m3{Yq8X$Sn9S=i8kHfu5-)HUnD+H zJc{-b9@ztp@b6(P_1!-rtqp{+7pA`JZ#&k3?(R$+^Rah7;2?j`7d+PHzt_Z&e4B^J zj^MF9o_i?@)fg4Fa)&x&N11mhdw~W~ z>2;Rm&+3JuDw}f7+TOUTS`#s8T^QK>R+FZvVS7^iKIvUQC3y`=COn|toU+!GC7p=% z%jj>Bx0?_j0`;w@WXZj}1@!IeeEn40?7aaQliS-qiQ}nu5_W1*L58q1Ac_S&S5iry z7sZcDlIpfZL~%~RhDqXfO}8UdF{fuC6Ly1$({}h^SmA=CXj4iKu7PnF)$*2VJ zKmmV1#8Dy!L0B!K=nNxDCd4VTB~vzFkug!ss*+*kl&qPRRaGQU-cVg7bR$kY>Vzod z?z10uJ&-YOf%x|?z*kS0v8S!OS6Wi#@k&b{h)`d7xDx3qk5q#D%EzDZk!!(~&i$+W zf%4E(Huj9B*}e@A@;0rL+;h&uwm%O9+1T@ThD|=_18i))4SB=QXolTS^up^Tx6a#j zG~4XfL2jM1>nOIxt%KaU*R6B(zNIPFfzmhxfNWmV!T9Wn@zbY<$V2}kycq*y$A^*= zV26SPRosPzB31#d7B}MNpqBY$4xSy%x#7W~RM2YPe0Zg^I+oMQzJrd}FauVxcGk6* zl(g$zMK;og``-zU-`if-g9lvNdB8d0sZSIo;uME+k}$GueFyI3YH^M;_r8P9!}w=V zNBm`w@Cl+aih9|LsNLV7!{4C2PlJh-Kxf%Uj22w_a3!2x + + + + + + False + True + True + DESKTOP ENVIRONMENT + + + + False + vertical + 6 + + + False + + + False + 6 + 6 + 6 + + + + + False + False + 0 + + + + + False + 12 + 0 + 0 + 0 + 48 + 24 + 24 + + + False + vertical + 8 + + + True + False + 0 + 12 + True + 60 + Choose the desktop environment to install. A web browser (Firefox) is installed automatically with any desktop. + + + False + True + 0 + + + + + Command line only (no desktop) + True + True + False + True + True + + + False + True + 1 + + + + + GNOME + True + True + False + True + radio_cli + + + False + True + 2 + + + + + KDE Plasma + True + True + False + True + radio_cli + + + False + True + 3 + + + + + Hyprland + True + True + False + True + radio_cli + + + False + True + 4 + + + + + XFCE + True + True + False + True + radio_cli + + + False + True + 5 + + + + + + + + + + + DESKTOP ENVIRONMENT + + + + diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index 91a1e5e..34e01cd 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -216,6 +216,8 @@ case "$DESK" in hyprland) PKGS="hyprland kitty wofi waybar sddm"; DM="sddm" ;; cli|*) PKGS="" ;; esac +# Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI). +[ -n "$PKGS" ] && PKGS="$PKGS firefox" if [ -n "$PKGS" ]; then pacman-key --init &>/dev/null || true pacman-key --populate archlinux &>/dev/null || true From ff98a1e1863c460c07ada2a83d0d054bd58ede18 Mon Sep 17 00:00:00 2001 From: nocode Date: Wed, 24 Jun 2026 19:02:31 +0200 Subject: [PATCH 002/136] fix(anaconda): improve desktop environment setup and system configuration - Fix XFCE display manager: replace lightdm-gtk-greeter with sddm for consistency - Add SDDM numlock initialization for KDE, XFCE, and Hyprland - Configure X11 keyboard layout from kickstart or locale via langtable to ensure correct SDDM login keyboard - Enable wheel group sudo access and add all human users to wheel group - Apply FWS branding to os-release, lsb-release, and GRUB configuration - Remove inappropriate live system motd file - Fix DNS resolution: configure systemd-resolved stub resolver with NetworkManager integration to prevent "Limited Connectivity" on first boot - Reformat case statement for better readability --- .../share/anaconda/interactive-defaults.ks | 95 +++++++++++++++++-- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index 34e01cd..54f2b19 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -210,10 +210,10 @@ DESK="cli" [ -f /tmp/fws-desktop ] && DESK="$(tr -d '[:space:]' < /tmp/fws-desktop)" DM="" case "$DESK" in - kde) PKGS="plasma-meta sddm konsole dolphin"; DM="sddm" ;; - gnome) PKGS="gnome gdm"; DM="gdm" ;; - xfce) PKGS="xfce4 xfce4-goodies lightdm lightdm-gtk-greeter"; DM="lightdm" ;; - hyprland) PKGS="hyprland kitty wofi waybar sddm"; DM="sddm" ;; + kde) PKGS="plasma-meta sddm konsole dolphin"; DM="sddm" ;; + gnome) PKGS="gnome gdm"; DM="gdm" ;; + xfce) PKGS="xfce4 xfce4-goodies sddm"; DM="sddm" ;; + hyprland) PKGS="hyprland kitty wofi waybar sddm"; DM="sddm" ;; cli|*) PKGS="" ;; esac # Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI). @@ -224,11 +224,80 @@ if [ -n "$PKGS" ]; then if pacman -Sy --noconfirm $PKGS; then [ -n "$DM" ] && systemctl enable "$DM" || true systemctl set-default graphical.target || true + # SDDM (KDE / XFCE / Hyprland) : pavé numérique allumé au login. + if [ "$DM" = "sddm" ]; then + install -d /etc/sddm.conf.d + printf '[General]\nNumlock=on\n' > /etc/sddm.conf.d/10-fws.conf + fi else echo "[FWS] Bureau '$DESK' non installé (réseau ?) — à refaire après le 1er boot." fi fi +# --- Clavier X11 (SDDM + sessions graphiques) -------------------------------- +# SDDM et les sessions X/Wayland (kwin lit aussi ce fichier) prennent leur +# disposition de /etc/X11/xorg.conf.d/00-keyboard.conf. Anaconda passe par localed +# qui ne l'écrit pas fiablement sur la CIBLE → écran SDDM en QWERTY US → le mot de +# passe (tapé sur le clavier choisi, ex. suisse QWERTZ) ne correspond pas. On +# l'écrit donc nous-mêmes, depuis la disposition X CHOISIE (kickstart généré), +# sinon dérivée de la locale via langtable. Cohérent avec le clavier du GUI. +XKB="$(sed -n "s/.*--xlayouts=//p" /root/anaconda-ks.cfg 2>/dev/null | head -1)" +XKB="${XKB#[\'\"]}"; XKB="${XKB%%[\'\"]*}"; XKB="${XKB%%,*}" # 1re dispo, ex. « ch (fr) » +if [ -z "$XKB" ]; then + _loc="$(. /etc/locale.conf 2>/dev/null; printf '%s' "${LANG%%.*}")" # fr_CH + _lng="${_loc%%_*}"; _terr="${_loc#*_}"; [ "$_terr" = "$_loc" ] && _terr="" + [ -n "$_terr" ] && XKB="$(python3 -c "import langtable; k=langtable.list_keyboards(languageId='$_lng', territoryId='$_terr'); print(k[0] if k else '')" 2>/dev/null)" +fi +if [ -n "$XKB" ]; then + XL="${XKB%%(*}"; XL="${XL%% *}" # ch + case "$XKB" in *'('*')') XV="${XKB#*(}"; XV="${XV%)}" ;; *) XV="" ;; esac # fr + install -d /etc/X11/xorg.conf.d + cat > /etc/X11/xorg.conf.d/00-keyboard.conf < /etc/sudoers.d/10-fws-wheel +chmod 440 /etc/sudoers.d/10-fws-wheel +while IFS=: read -r _u _x _uid _rest; do + if [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ]; then + usermod -aG wheel "$_u" 2>/dev/null || true + fi +done < /etc/passwd + +# --- 4ter) Branding FWS sur le système installé ------------------------------- +# Le hook os-release du build n'est PAS sur la cible et « pacman -S » a pu +# remettre l'os-release d'Arch → d'où « Arch Linux » au menu GRUB, le logo Arch +# sur l'écran de connexion (GDM lit os-release LOGO) et le nom « Arch ». On FORCE +# donc l'os-release FWS (+ lsb-release + GRUB_DISTRIBUTOR), on RÉGÉNÈRE le menu +# GRUB (10_linux lit le NAME d'os-release), et on retire le motd « live ». +if [ -f /usr/local/share/fws/os-release ]; then + cp -f /usr/local/share/fws/os-release /usr/lib/os-release + ln -sf ../usr/lib/os-release /etc/os-release +fi +if [ -f /etc/lsb-release ]; then + sed -i 's/^DISTRIB_ID=.*/DISTRIB_ID=FWS/; s/^DISTRIB_DESCRIPTION=.*/DISTRIB_DESCRIPTION="FWS Linux"/' \ + /etc/lsb-release +fi +if grep -q '^GRUB_DISTRIBUTOR=' /etc/default/grub 2>/dev/null; then + sed -i 's/^GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR="FWS"/' /etc/default/grub +else + echo 'GRUB_DISTRIBUTOR="FWS"' >> /etc/default/grub +fi +grub-mkconfig -o /boot/grub/grub.cfg 2>/dev/null || true +# motd « live » (texte inadapté + codes ANSI bruts affichés crus par GDM). +rm -f /etc/motd + # --- 5) Sécurité : verrouiller root s'il est resté SANS mot de passe ---------- # L'airootfs live a souvent un root sans mot de passe ; si l'utilisateur n'en a # pas défini dans le GUI, on verrouille plutôt que de laisser le compte ouvert. @@ -236,9 +305,21 @@ if passwd -S root 2>/dev/null | grep -qE '\bNP\b'; then passwd -l root || true fi -# --- 6) Le resolv.conf du live ne doit pas rester figé ----------------------- -# NetworkManager (activé sur le système installé) régénère /etc/resolv.conf. -rm -f /tmp/fws-desktop /etc/resolv.conf 2>/dev/null || true +# --- 6) DNS du système installé : NetworkManager + systemd-resolved ---------- +# Le live utilise systemd-resolved (/etc/resolv.conf → stub 127.0.0.53). L'ANCIEN +# « rm /etc/resolv.conf » comptait sur NM pour recréer le fichier — MAIS avec +# systemd-resolved actif, NM ne réécrit PAS resolv.conf (il pousse les DNS vers +# resolved). Sans le lien, la résolution est MORTE → « Limited Connectivity » / +# Firefox « Server Not Found » (le réseau marche, le DNS non). Fix robuste : +# - resolv.conf → stub systemd-resolved, +# - service systemd-resolved activé, +# - on FORCE NM à utiliser resolved (dns=systemd-resolved) → il lui fournit les +# DNS DHCP, la résolution marche dès le 1er boot. +rm -f /tmp/fws-desktop 2>/dev/null || true +ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf +systemctl enable systemd-resolved.service 2>/dev/null || true +install -d /etc/NetworkManager/conf.d +printf '[main]\ndns=systemd-resolved\n' > /etc/NetworkManager/conf.d/dns.conf %end From 99006b9eded7997a450159cd11d3093c0beff1ab Mon Sep 17 00:00:00 2001 From: nocode Date: Wed, 24 Jun 2026 23:06:20 +0200 Subject: [PATCH 003/136] feat(hyprland): add hyprland configuration with keyboard layout injection and vm compatibility Add Hyprland desktop environment support with: - New hyprland.conf template with keyboard layout placeholders (__KB_LAYOUT__ and __KB_VARIANT__) that get injected during installation - Hyprland wrapper script (/usr/local/bin/fws-hyprland) that detects virtual machines and forces software rendering to prevent compositor crashes on virtual GPUs (VMware vmwgfx, VirtualBox) - Automatic configuration deployment to /etc/skel and existing user home directories - Refactored keyboard layout detection logic (moved to section 3bis) to support both X11/SDDM and Hyprland configurations - Added locale generation during installation to ensure proper language support Keyboard layout is now derived from either kickstart configuration or system locale using langtable, providing consistent keyboard behavior across all desktop environments. --- .../usr/local/share/fws/hyprland.conf.tmpl | 61 ++++++++++ .../share/anaconda/interactive-defaults.ks | 107 +++++++++++++----- 2 files changed, 142 insertions(+), 26 deletions(-) create mode 100644 configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl new file mode 100644 index 0000000..8316f4e --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -0,0 +1,61 @@ +# FWS — configuration Hyprland par défaut. +# Le clavier (__KB_LAYOUT__ / __KB_VARIANT__) est injecté à l'installation, +# depuis le choix fait dans Anaconda. Édite ce fichier librement. + +monitor = , preferred, auto, 1 + +input { + kb_layout = __KB_LAYOUT__ + kb_variant = __KB_VARIANT__ + follow_mouse = 1 + numlock_by_default = true +} + +general { + gaps_in = 4 + gaps_out = 8 + border_size = 2 + layout = dwindle +} + +decoration { + rounding = 6 +} + +# Barre d'état au démarrage. +exec-once = waybar + +$mod = SUPER + +# Applications +bind = $mod, Return, exec, kitty +bind = $mod, E, exec, firefox +bind = $mod, R, exec, wofi --show drun +bind = $mod, Q, killactive, +bind = $mod SHIFT, Q, exit, +bind = $mod, V, togglefloating, +bind = $mod, F, fullscreen, + +# Focus +bind = $mod, left, movefocus, l +bind = $mod, right, movefocus, r +bind = $mod, up, movefocus, u +bind = $mod, down, movefocus, d + +# Espaces de travail 1-6 +bind = $mod, 1, workspace, 1 +bind = $mod, 2, workspace, 2 +bind = $mod, 3, workspace, 3 +bind = $mod, 4, workspace, 4 +bind = $mod, 5, workspace, 5 +bind = $mod, 6, workspace, 6 +bind = $mod SHIFT, 1, movetoworkspace, 1 +bind = $mod SHIFT, 2, movetoworkspace, 2 +bind = $mod SHIFT, 3, movetoworkspace, 3 +bind = $mod SHIFT, 4, movetoworkspace, 4 +bind = $mod SHIFT, 5, movetoworkspace, 5 +bind = $mod SHIFT, 6, movetoworkspace, 6 + +# Souris : déplacer / redimensionner les fenêtres +bindm = $mod, mouse:272, movewindow +bindm = $mod, mouse:273, resizewindow diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index 54f2b19..faeb1ef 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -205,6 +205,44 @@ else echo "[FWS] AVERTISSEMENT : grub-install a échoué — bootloader à refaire à la main" fi +# --- 3bis) Clavier (X11) + LOCALE -------------------------------------------- +# CLAVIER : Anaconda passe par localed et n'écrit pas fiablement la disposition X +# sur la CIBLE → SDDM / sessions X en QWERTY US. On CALCULE la disposition CHOISIE +# (kickstart généré, sinon dérivée de la locale via langtable) en XL/XV, réutilisés +# plus bas (00-keyboard.conf pour SDDM/X ET la config Hyprland qui a son propre +# kb_layout). LOCALE : le locale choisi (ex. fr_CH.UTF-8) doit être GÉNÉRÉ — +# Anaconda vient de Fedora (locales pré-générées) et ne lance pas locale-gen → +# sans ça LANG casse et tout retombe en C. +XL=""; XV="" +XKB="$(sed -n "s/.*--xlayouts=//p" /root/anaconda-ks.cfg 2>/dev/null | head -1)" +XKB="${XKB#[\'\"]}"; XKB="${XKB%%[\'\"]*}"; XKB="${XKB%%,*}" # 1re dispo, ex. « ch (fr) » +if [ -z "$XKB" ]; then + _loc="$(. /etc/locale.conf 2>/dev/null; printf '%s' "${LANG%%.*}")" # fr_CH + _lng="${_loc%%_*}"; _terr="${_loc#*_}"; [ "$_terr" = "$_loc" ] && _terr="" + [ -n "$_terr" ] && XKB="$(python3 -c "import langtable; k=langtable.list_keyboards(languageId='$_lng', territoryId='$_terr'); print(k[0] if k else '')" 2>/dev/null)" +fi +if [ -n "$XKB" ]; then + XL="${XKB%%(*}"; XL="${XL%% *}" # ch + case "$XKB" in *'('*')') XV="${XKB#*(}"; XV="${XV%)}" ;; *) XV="" ;; esac # fr + install -d /etc/X11/xorg.conf.d + cat > /etc/X11/xorg.conf.d/00-keyboard.conf </dev/null \ + || printf '%s %s\n' "$FWSLANG" "$_cs" >> /etc/locale.gen + locale-gen || echo "[FWS] locale-gen a échoué pour $FWSLANG" +fi + # --- 4) Bureau choisi : pacman -S du DE (non bloquant si pas de réseau) ------- DESK="cli" [ -f /tmp/fws-desktop ] && DESK="$(tr -d '[:space:]' < /tmp/fws-desktop)" @@ -229,37 +267,54 @@ if [ -n "$PKGS" ]; then install -d /etc/sddm.conf.d printf '[General]\nNumlock=on\n' > /etc/sddm.conf.d/10-fws.conf fi + # Hyprland en VM : sur GPU virtuel (VMware/VirtualBox) le compositeur + # crashe au lancement → SDDM « remet au login ». On le lance via un + # wrapper qui force le rendu LOGICIEL UNIQUEMENT en VM (systemd-detect-virt) + # ; sur un vrai GPU le rendu matériel est conservé. + if [ "$DESK" = "hyprland" ]; then + cat > /usr/local/bin/fws-hyprland <<'HYEOF' +#!/bin/sh +if systemd-detect-virt --quiet 2>/dev/null; then + # GPU virtuel (VMware vmwgfx…) : on FORCE le chemin d'affichage 100% logiciel. + # La PIÈCE MAÎTRESSE est MESA_LOADER_DRIVER_OVERRIDE=kms_swrast : elle force + # Mesa à allouer le GBM/EGL via kms_swrast (rendu logiciel dans les « dumb + # buffers » KMS) AU LIEU du pilote vmwgfx (qui ne fournit pas le GBM dont + # aquamarine a besoin → « CBackend::create() failed »). + llvmpipe pour le GL. + export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast + export GALLIUM_DRIVER=llvmpipe LIBGL_ALWAYS_SOFTWARE=1 + export WLR_RENDERER_ALLOW_SOFTWARE=1 WLR_NO_HARDWARE_CURSORS=1 + export AQ_NO_ATOMIC=1 +fi +exec Hyprland "$@" +HYEOF + chmod 755 /usr/local/bin/fws-hyprland + if [ -f /usr/share/wayland-sessions/hyprland.desktop ]; then + sed -i 's|^Exec=.*|Exec=/usr/local/bin/fws-hyprland|' \ + /usr/share/wayland-sessions/hyprland.desktop + fi + fi else echo "[FWS] Bureau '$DESK' non installé (réseau ?) — à refaire après le 1er boot." fi fi -# --- Clavier X11 (SDDM + sessions graphiques) -------------------------------- -# SDDM et les sessions X/Wayland (kwin lit aussi ce fichier) prennent leur -# disposition de /etc/X11/xorg.conf.d/00-keyboard.conf. Anaconda passe par localed -# qui ne l'écrit pas fiablement sur la CIBLE → écran SDDM en QWERTY US → le mot de -# passe (tapé sur le clavier choisi, ex. suisse QWERTZ) ne correspond pas. On -# l'écrit donc nous-mêmes, depuis la disposition X CHOISIE (kickstart généré), -# sinon dérivée de la locale via langtable. Cohérent avec le clavier du GUI. -XKB="$(sed -n "s/.*--xlayouts=//p" /root/anaconda-ks.cfg 2>/dev/null | head -1)" -XKB="${XKB#[\'\"]}"; XKB="${XKB%%[\'\"]*}"; XKB="${XKB%%,*}" # 1re dispo, ex. « ch (fr) » -if [ -z "$XKB" ]; then - _loc="$(. /etc/locale.conf 2>/dev/null; printf '%s' "${LANG%%.*}")" # fr_CH - _lng="${_loc%%_*}"; _terr="${_loc#*_}"; [ "$_terr" = "$_loc" ] && _terr="" - [ -n "$_terr" ] && XKB="$(python3 -c "import langtable; k=langtable.list_keyboards(languageId='$_lng', territoryId='$_terr'); print(k[0] if k else '')" 2>/dev/null)" -fi -if [ -n "$XKB" ]; then - XL="${XKB%%(*}"; XL="${XL%% *}" # ch - case "$XKB" in *'('*')') XV="${XKB#*(}"; XV="${XV%)}" ;; *) XV="" ;; esac # fr - install -d /etc/X11/xorg.conf.d - cat > /etc/X11/xorg.conf.d/00-keyboard.conf < /tmp/fws-hyprland.conf + install -Dm644 /tmp/fws-hyprland.conf /etc/skel/.config/hypr/hyprland.conf + while IFS=: read -r _u _x _uid _g _gec _home _sh; do + [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ] && [ -d "$_home" ] || continue + install -Dm644 /tmp/fws-hyprland.conf "$_home/.config/hypr/hyprland.conf" + chown "$_u": "$_home/.config" 2>/dev/null || true + chown -R "$_u": "$_home/.config/hypr" 2>/dev/null || true + done < /etc/passwd + rm -f /tmp/fws-hyprland.conf fi # --- 4bis) Sudo : l'utilisateur créé doit pouvoir administrer ----------------- From 0b0fcd8ce48a19251f58ef776c6d35634ef4292b Mon Sep 17 00:00:00 2001 From: nocode Date: Wed, 24 Jun 2026 23:32:37 +0200 Subject: [PATCH 004/136] feat(releng): add hardware detection and driver setup script Add fws-setup-hardware script that automatically detects and installs: - GPU drivers (NVIDIA, AMD, Intel) based on lspci output - Hypervisor guest tools (VMware, VirtualBox, QEMU, Hyper-V) - Audio/mic/headset stack (PipeWire), Bluetooth (BlueZ), containers (Podman) - Optional desktop stack when non-CLI desktop is selected: Steam, Wine, VR support (Monado/OpenXR), and winboat-bin The script is integrated into the Anaconda kickstart post-installation phase and is non-blocking to prevent installation failures from missing packages or network issues. Also update profiledef.sh to set correct permissions (755) for the new script. --- .../airootfs/usr/local/bin/fws-setup-hardware | 75 +++++++++++++++++++ .../share/anaconda/interactive-defaults.ks | 9 +++ configs/releng/profiledef.sh | 1 + 3 files changed, 85 insertions(+) create mode 100755 configs/releng/airootfs/usr/local/bin/fws-setup-hardware diff --git a/configs/releng/airootfs/usr/local/bin/fws-setup-hardware b/configs/releng/airootfs/usr/local/bin/fws-setup-hardware new file mode 100755 index 0000000..07a2fa5 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-setup-hardware @@ -0,0 +1,75 @@ +#!/bin/bash +# ============================================================================ +# FWS — détection matérielle + drivers + stack « remplacement de Windows ». +# +# Appelé par le %post du kickstart : fws-setup-hardware +# ( = cli|gnome|kde|xfce|hyprland). Réseau requis ; CHAQUE étape est +# NON bloquante (pas de set -e) : un paquet manquant ou pas de réseau ne casse +# pas l'installation. +# +# Installe : +# - les drivers GPU détectés via lspci (Intel / AMD / NVIDIA) + Mesa/Vulkan, +# - les outils invité selon l'hyperviseur (VMware/VirtualBox/QEMU/Hyper-V), +# - le son/micro/casque (PipeWire), le Bluetooth (BlueZ), les conteneurs +# (Podman), +# - et — si un bureau est choisi — la stack « comme Windows » : Steam, Wine, +# VR (Monado/OpenXR → SteamVR pour HTC Vive / Valve Index ; Oculus n'a pas +# de support Linux officiel), winboat-bin (apps Windows). +# ============================================================================ +DESK="${1:-cli}" +log() { echo "[FWS-hw] $*"; } + +# ── 1) Drivers GPU (détection lspci) ───────────────────────────────────────── +DRIVERS="mesa" +GPU="$(lspci 2>/dev/null | grep -iE 'VGA compatible controller|3D controller|Display controller')" +case "$GPU" in + *NVIDIA*|*GeForce*) DRIVERS="$DRIVERS nvidia-dkms nvidia-utils linux-headers dkms" ;; + *AMD*|*ATI*|*Radeon*) DRIVERS="$DRIVERS vulkan-radeon libva-mesa-driver" ;; + *Intel*) DRIVERS="$DRIVERS vulkan-intel intel-media-driver" ;; +esac + +# ── 2) Outils invité selon l'hyperviseur ───────────────────────────────────── +VMSVC="" +case "$(systemd-detect-virt 2>/dev/null)" in + vmware) DRIVERS="$DRIVERS open-vm-tools"; VMSVC="vmtoolsd vmware-vmblock-fuse" ;; + oracle) DRIVERS="$DRIVERS virtualbox-guest-utils"; VMSVC="vboxservice" ;; + qemu|kvm) DRIVERS="$DRIVERS qemu-guest-agent spice-vdagent"; VMSVC="qemu-guest-agent spice-vdagentd" ;; + microsoft) DRIVERS="$DRIVERS hyperv"; VMSVC="hv_fcopy_daemon hv_kvp_daemon hv_vss_daemon" ;; +esac + +# ── 3) Stack de base : son / micro / casque, Bluetooth, conteneurs ─────────── +BASE="pipewire pipewire-alsa pipewire-pulse pipewire-jack wireplumber \ + pavucontrol bluez bluez-utils podman" + +# ── 4) Stack desktop : jeux, Windows-compat, VR (si un bureau est choisi) ──── +DESKTOP="" +if [ "$DESK" != "cli" ]; then + # multilib requis (Steam / Wine 32 bits). + grep -qE '^\[multilib\]' /etc/pacman.conf \ + || printf '\n[multilib]\nInclude = /etc/pacman.d/mirrorlist\n' >> /etc/pacman.conf + DESKTOP="steam wine winetricks wine-mono wine-gecko \ + lib32-mesa lib32-pipewire monado gamemode \ + noto-fonts ttf-liberation" +fi + +# ── Sync + filtre aux paquets RÉELLEMENT existants ─────────────────────────── +# (un nom de paquet manquant/renommé ne doit pas faire échouer tout le reste). +pacman -Sy --noconfirm || log "synchro pacman échouée (réseau ?)" +VALID="" +for p in $DRIVERS $BASE $DESKTOP; do + pacman -Si "$p" >/dev/null 2>&1 && VALID="$VALID $p" +done +if [ -n "$VALID" ]; then + log "installation :$VALID" + pacman -S --noconfirm --needed $VALID || log "certains paquets non installés" +fi + +# NB : winboat-bin (AUR) n'est PAS installé ici (fws-local n'existe pas sur la +# cible) : il est intégré à l'image FWS via packages.x86_64 et recopié par le +# payload LiveOS d'Anaconda → déjà présent sur le système installé. + +# ── Services matériels ─────────────────────────────────────────────────────── +[ -n "$VMSVC" ] && systemctl enable $VMSVC 2>/dev/null +systemctl enable bluetooth.service 2>/dev/null +systemctl enable podman.socket 2>/dev/null +exit 0 diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index faeb1ef..e973570 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -298,6 +298,15 @@ HYEOF fi fi +# --- 4quater) ADN FWS : détection matériel + drivers + stack « Windows » ------ +# Script dédié (NON bloquant ; réseau requis) : drivers GPU détectés via lspci + +# outils invité VM, son/micro/casque (PipeWire), Bluetooth, Podman, et — si un +# bureau est choisi — Steam, Wine, VR (Monado/SteamVR), winboat-bin (apps +# Windows). C'est le cœur « remplacement de Windows » de FWS. +if [ -x /usr/local/bin/fws-setup-hardware ]; then + /usr/local/bin/fws-setup-hardware "$DESK" || true +fi + # --- Config Hyprland (si choisi) : clavier + apps + waybar ------------------- # Hyprland (Wayland) NE lit PAS /etc/X11/xorg.conf.d/00-keyboard.conf : sa # disposition est dans SA config (input { kb_layout }). Sans config il démarre nu diff --git a/configs/releng/profiledef.sh b/configs/releng/profiledef.sh index b9d8a31..f3869a9 100644 --- a/configs/releng/profiledef.sh +++ b/configs/releng/profiledef.sh @@ -24,4 +24,5 @@ file_permissions=( ["/usr/local/bin/livecd-sound"]="0:0:755" ["/usr/bin/load_policy"]="0:0:755" ["/usr/bin/setstatus"]="0:0:755" + ["/usr/local/bin/fws-setup-hardware"]="0:0:755" ) From ee0082baa1c685c582c1d6f0fe37c26bc5996486 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:58:28 +0200 Subject: [PATCH 005/136] feat(xinitrc): add anaconda installer improvements and splash screen Add several improvements to the liveinst installer workflow: - Expose archiso squashfs at /run/rootfsbase where Anaconda expects to find the Live OS image, fixing SourceSetupError crashes - Display immediate splash screen with zenity during Anaconda startup (2-4 min wait time) to provide user feedback and prevent perceived hangs - Wrap liveinst with dbus-run-session to provide D-Bus session bus, fixing GLib.GError crashes from missing ScreenSaver service - Add hardware summary log output to debug information collection These changes address three crash scenarios identified during testing and improve user experience during installer initialization. --- configs/baseline/airootfs/root/.xinitrc | 56 ++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/configs/baseline/airootfs/root/.xinitrc b/configs/baseline/airootfs/root/.xinitrc index b7b050e..c05ca75 100644 --- a/configs/baseline/airootfs/root/.xinitrc +++ b/configs/baseline/airootfs/root/.xinitrc @@ -20,10 +20,61 @@ _OB_PID=$! # boucle (symptôme « fond bleu qui clignote/reboote »). On NE rend jamais la main # à startx : on reste sur Openbox pour lire les logs / rebooter proprement. if command -v liveinst >/dev/null 2>&1; then + # Payload LiveOS : avec --liveinst (passé par liveinst), Anaconda IGNORE le + # payload du kickstart (anaconda.py teste opts.liveinst AVANT le type du + # payload DBus — un « liveimg » dans le ks serait du code mort) et détecte + # l'image live sur des chemins Fedora/dracut : /dev/mapper/live-base, + # /dev/mapper/live-osimg-min ou /run/rootfsbase — tous ABSENTS d'archiso → + # « SourceSetupError: No Live OS image found! » = crash au démarrage + # (reproduit hors VM dans un chroot de l'airootfs). On expose donc le + # squashfs archiso (monté ro sur /run/archiso/airootfs) là où Anaconda le + # cherche : findmnt y résout le loop device → montage → rsync vers la cible. + if [ -d /run/archiso/airootfs ] && [ ! -e /run/rootfsbase ]; then + mkdir -p /run/rootfsbase + mount --bind /run/archiso/airootfs /run/rootfsbase || rmdir /run/rootfsbase + fi + + # ÉCRAN D'ATTENTE immédiat : le démarrage d'anaconda peut prendre 2 à + # 4 minutes (observé en VM VMware : un worker udev se bloque au boot et + # n'est tué par udevd qu'après 180 s → le « udevadm settle » d'anaconda + # attend tout ce temps). Sans feedback, l'écran reste bleu et muet et + # l'utilisateur croit à une panne (« l'installateur ne se lance pas ») + # alors que TOUT va bien. Le splash pulse pendant la préparation ; + # anaconda s'ouvre PAR-DESSUS quand il est prêt (openbox donne le focus + # aux nouvelles fenêtres) et on tue le splash à la sortie de liveinst. + # tail -f /dev/null : zenity --progress lit stdin — un stdin qui ne se + # ferme jamais garde la fenêtre ouverte sans consommer de CPU. + _SPLASH_PID="" + if command -v zenity >/dev/null 2>&1; then + tail -f /dev/null | zenity --progress --pulsate --no-cancel \ + --title="FWS" \ + --text="Préparation de l'installateur FWS…\n\nAnalyse du matériel et des disques en cours.\nCela peut prendre 2 à 4 minutes, c'est normal." \ + --width=420 2>/dev/null & + _SPLASH_PID=$! + fi + LIVEINST_LOG=/tmp/fws-liveinst.log - liveinst >"$LIVEINST_LOG" 2>&1 + # Bus D-Bus de SESSION : au démarrage (--liveinst), inhibit_screensaver() + # de pyanaconda se connecte au bus de session. S'il n'y en a AUCUN (notre + # startx root minimal n'en garantit pas), Gio lève une GLib.GError que + # pyanaconda n'attrape PAS (il n'attrape que DBusError) → crash immédiat + # (2e crash reproduit hors VM). dbus-run-session fournit un bus de session + # pour toute la durée de l'installateur ; avec un bus présent, l'absence du + # service ScreenSaver est attrapée (simple warning dans anaconda.log). + if command -v dbus-run-session >/dev/null 2>&1 && [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then + dbus-run-session -- liveinst >"$LIVEINST_LOG" 2>&1 + else + liveinst >"$LIVEINST_LOG" 2>&1 + fi rc=$? + # liveinst terminé (install finie ou échec) : le splash n'a plus de raison + # d'être — kill du pipeline tail|zenity (pkill -P attrape les deux). + if [ -n "$_SPLASH_PID" ]; then + pkill -P "$_SPLASH_PID" 2>/dev/null + kill "$_SPLASH_PID" 2>/dev/null + fi + # ATTENTION : liveinst NE propage PAS le code de sortie d'anaconda — il # enchaîne son propre nettoyage et sort souvent 0 même quand anaconda a # planté. On ne se fie donc PAS à $rc : en phase debug on regroupe TOUS les @@ -66,6 +117,9 @@ if command -v liveinst >/dev/null 2>&1; then echo echo "########## %post --nochroot (/tmp/fws-post-nochroot.log) ##########" cat /tmp/fws-post-nochroot.log 2>/dev/null || echo "(absent)" + echo + echo "########## Récapitulatif (page GUI fws_recap, avant install) ##########" + cat /tmp/fws-hw-summary.txt 2>/dev/null || echo "(absent — page récap pas atteinte)" for f in /tmp/anaconda.log /tmp/syslog /tmp/program.log \ /tmp/storage.log /tmp/dbus.log /tmp/packaging.log /tmp/X.log; do echo From 8b7af602392ffc6ef7aba13a507301bbfc06adc7 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:58:48 +0200 Subject: [PATCH 006/136] chore: remove pycache file --- .../__pycache__/fws_desktop.cpython-314.pyc | Bin 4538 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/__pycache__/fws_desktop.cpython-314.pyc diff --git a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/__pycache__/fws_desktop.cpython-314.pyc b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/__pycache__/fws_desktop.cpython-314.pyc deleted file mode 100644 index 5c8dabfc81f29a11f55176b6acc950c0785ff6e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4538 zcma)AU2GHC6}~f`vB&oKFC=kD9AZeCV6w4cpO=KP?1=puh{EG;4B#&-Aw-Xy@XfKjS^% zakR{U;O|DM@V`hgMO&W1anYj06lFyx^*M81!t$VG%6T0xKwWTL#|259Eb13!D>6Ja zd0aLwntIWx@MKlx)s8{EP>{4-QdKlLscY&&a<`@@bB? z6B2xJbif_b43oW^5y1~KDg;2rgdoVKnQa1Jr`HVSP+hqN%Hg_lE0iO3<+uve7W9 zv=s$Axh9@cw46S_*k%yh8^nO3Yru3~m2&c8PZ7&=GM2ThT(j*!PBDtAv@l>S6lQf* z$u9a&{ABd9?XJaU(H%NDrlrYbv^S2jLKO-+&*oX0y6Br{s;ytON=Gmy85P(#<&| zQ!;QyRc15A1@nTg?N9GJkTDcf9wo4O3vzRz-;=p<}|FzAnq%pXI>QT!*D=R);&*g+V(qOMvd z-<{|zN>gX4)71C9JE1F_RH)Hvni*1Z&mnTHi#g~xo?8d(%QXFU_Ks@~?eN+uJ;#to_3R%8T<{8cHo3!P)OUgHm8gdFTNfu@dXwLOqy zMt(`ukNVs>@?fh3Qs5Hk1Q?OOll_N0ok*dQXu7q!5HHHX6_S9~PJ09eIXZw9uZUH%|WLKqY*Kc{~9_@a~LKF1-?gfXU@fV2l$1Fa& z?t$+sV-GCuZfksyMt29gj%C<;d>7>JWrD|!`0xFQgZzCuI2iNXk5V9CV-#}!?F02^ zdxHQJ_%@~qqScTHa`gHFPM#M_T7pz0_^U@sXQn}FjqL5_Yy66mTXaGML; zl*i$)GeBZCbUc712OR+eP$j`da7j+l4nSx;>u{HY1RGFVxS~)lmOhXm}+weB1o}Zzqu%RP_zF7PYg{y!-0r#8jCz1^w=0Q8os(HlJnzDuC7AW#xLQH}8G>{#tp z^OvLFjnGtd^LFS$r)ZbRYScJgM;XkV=o2(8$xVzE-Os4iG7jX1Ka$B6zV5P+h1$BoO^FR#T@58|oE@&2U~z$lT} zr$4{B>(;=R1Gh52%K!^}#y^R+JoBNpch)(^<&m3{Yq8X$Sn9S=i8kHfu5-)HUnD+H zJc{-b9@ztp@b6(P_1!-rtqp{+7pA`JZ#&k3?(R$+^Rah7;2?j`7d+PHzt_Z&e4B^J zj^MF9o_i?@)fg4Fa)&x&N11mhdw~W~ z>2;Rm&+3JuDw}f7+TOUTS`#s8T^QK>R+FZvVS7^iKIvUQC3y`=COn|toU+!GC7p=% z%jj>Bx0?_j0`;w@WXZj}1@!IeeEn40?7aaQliS-qiQ}nu5_W1*L58q1Ac_S&S5iry z7sZcDlIpfZL~%~RhDqXfO}8UdF{fuC6Ly1$({}h^SmA=CXj4iKu7PnF)$*2VJ zKmmV1#8Dy!L0B!K=nNxDCd4VTB~vzFkug!ss*+*kl&qPRRaGQU-cVg7bR$kY>Vzod z?z10uJ&-YOf%x|?z*kS0v8S!OS6Wi#@k&b{h)`d7xDx3qk5q#D%EzDZk!!(~&i$+W zf%4E(Huj9B*}e@A@;0rL+;h&uwm%O9+1T@ThD|=_18i))4SB=QXolTS^up^Tx6a#j zG~4XfL2jM1>nOIxt%KaU*R6B(zNIPFfzmhxfNWmV!T9Wn@zbY<$V2}kycq*y$A^*= zV26SPRosPzB31#d7B}MNpqBY$4xSy%x#7W~RM2YPe0Zg^I+oMQzJrd}FauVxcGk6* zl(g$zMK;og``-zU-`if-g9lvNdB8d0sZSIo;uME+k}$GueFyI3YH^M;_r8P9!}w=V zNBm`w@Cl+aih9|LsNLV7!{4C2PlJh-Kxf%Uj22w_a3!2x Date: Fri, 3 Jul 2026 23:58:53 +0200 Subject: [PATCH 007/136] chore(baseline): add file permissions for selinux and hardware setup scripts Add executable permissions for load_policy, setstatus, fws-setup-hardware, and fws-hypr-keys scripts in the baseline profile configuration. --- configs/baseline/profiledef.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index f0ba624..8f51919 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -26,4 +26,8 @@ file_permissions=( ["/usr/local/bin/choose-mirror"]="0:0:755" ["/usr/local/bin/Installation_guide"]="0:0:755" ["/usr/local/bin/livecd-sound"]="0:0:755" + ["/usr/bin/load_policy"]="0:0:755" + ["/usr/bin/setstatus"]="0:0:755" + ["/usr/local/bin/fws-setup-hardware"]="0:0:755" + ["/usr/local/bin/fws-hypr-keys"]="0:0:755" ) From 68850f0ed200e88f22236a89df18542460787489 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:00 +0200 Subject: [PATCH 008/136] feat(hyprland): expand hyprland config with keybindings, animations, and window rules Add comprehensive keybinding descriptions using bindd/binde for keyboard shortcut display, implement Catppuccin Mocha color scheme with blue gradient borders, enable animations with custom bezier curve, configure touchpad settings, add blur/shadow configuration for VM compatibility, implement scratchpad support, add screenshot and multimedia key bindings with PipeWire/playerctl integration, and define window floating rules. Keybindings now match i3/sway FWS configuration with French descriptions that automatically appear in fws-hypr-keys shortcut viewer. Configuration includes multi-screen support, workspace navigation (1-10), window resizing, and various utility bindings. --- .../usr/local/share/fws/hyprland.conf.tmpl | 157 ++++++++++++++---- 1 file changed, 129 insertions(+), 28 deletions(-) diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl index 8316f4e..8888d0b 100644 --- a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -1,6 +1,15 @@ # FWS — configuration Hyprland par défaut. # Le clavier (__KB_LAYOUT__ / __KB_VARIANT__) est injecté à l'installation, # depuis le choix fait dans Anaconda. Édite ce fichier librement. +# +# Raccourcis : transposition de la config i3/sway FWS (mêmes touches). +# Couleurs : nuances de bleu (palette Catppuccin Mocha). +# +# Les raccourcis sont déclarés avec « bindd » (bind + description) : la +# description alimente l'écran « Raccourcis clavier » (bouton ⌨ de la barre +# ou SUPER+K → fws-hypr-keys, qui lit les binds RÉELS via hyprctl). Ajoute +# tes propres bindd : ils apparaîtront automatiquement dans la liste. +# ⚠ Pas de virgule dans les descriptions (séparateur de champs Hyprland). monitor = , preferred, auto, 1 @@ -9,17 +18,47 @@ input { kb_variant = __KB_VARIANT__ follow_mouse = 1 numlock_by_default = true + touchpad { + natural_scroll = true + tap-to-click = true + } } general { gaps_in = 4 gaps_out = 8 border_size = 2 + # Nuances de bleu : bleu → sapphire en dégradé sur la fenêtre active. + col.active_border = rgb(89b4fa) rgb(74c7ec) 45deg + col.inactive_border = rgb(313244) layout = dwindle } decoration { - rounding = 6 + rounding = 8 + # Flou et ombres COUPÉS : rendu logiciel (llvmpipe) en VM — cf. le + # wrapper fws-hyprland écrit par l'installateur. Sur un vrai GPU tu + # peux les réactiver (enabled = true). + blur { + enabled = false + } + shadow { + enabled = false + } +} + +animations { + enabled = true + bezier = fws, 0.22, 1.0, 0.36, 1.0 + animation = windows, 1, 3, fws + animation = workspaces, 1, 3, fws + animation = fade, 1, 2, default +} + +misc { + disable_hyprland_logo = true + force_default_wallpaper = 0 + background_color = 0x1a1a2e # bleu nuit FWS (aucun fond requis) } # Barre d'état au démarrage. @@ -27,35 +66,97 @@ exec-once = waybar $mod = SUPER -# Applications -bind = $mod, Return, exec, kitty -bind = $mod, E, exec, firefox -bind = $mod, R, exec, wofi --show drun -bind = $mod, Q, killactive, -bind = $mod SHIFT, Q, exit, -bind = $mod, V, togglefloating, -bind = $mod, F, fullscreen, +# --- Applications --------------------------------------------------------- +bindd = $mod, Return, Ouvrir un terminal (kitty), exec, kitty +bindd = $mod SHIFT, Return, Terminal flottant, exec, kitty --class floating-term +bindd = $mod, R, Menu des applications, exec, wofi --show drun +bindd = $mod, E, Gestionnaire de fichiers, exec, thunar +bindd = $mod, B, Ouvrir Firefox, exec, firefox +bindd = $mod, KP_Multiply, Lancer Steam, exec, steam +bindd = $mod, K, Afficher les raccourcis clavier, exec, fws-hypr-keys -# Focus -bind = $mod, left, movefocus, l -bind = $mod, right, movefocus, r -bind = $mod, up, movefocus, u -bind = $mod, down, movefocus, d +# --- Fenêtres --------------------------------------------------------------- +bindd = $mod, Q, Fermer la fenêtre, killactive, +bindd = $mod, V, Fenêtre flottante ou ancrée, togglefloating, +bindd = $mod, F, Plein écran, fullscreen, +bindd = $mod, J, Basculer la découpe horizontale/verticale, layoutmsg, togglesplit +bindd = $mod, L, Verrouiller l'écran, exec, hyprlock +bindd = $mod SHIFT, E, Quitter la session (retour à SDDM), exit, +bindd = $mod SHIFT, C, Recharger la configuration Hyprland, exec, hyprctl reload -# Espaces de travail 1-6 -bind = $mod, 1, workspace, 1 -bind = $mod, 2, workspace, 2 -bind = $mod, 3, workspace, 3 -bind = $mod, 4, workspace, 4 -bind = $mod, 5, workspace, 5 -bind = $mod, 6, workspace, 6 -bind = $mod SHIFT, 1, movetoworkspace, 1 -bind = $mod SHIFT, 2, movetoworkspace, 2 -bind = $mod SHIFT, 3, movetoworkspace, 3 -bind = $mod SHIFT, 4, movetoworkspace, 4 -bind = $mod SHIFT, 5, movetoworkspace, 5 -bind = $mod SHIFT, 6, movetoworkspace, 6 +# --- Focus (flèches) --------------------------------------------------------- +bindd = $mod, left, Focus à gauche, movefocus, l +bindd = $mod, right, Focus à droite, movefocus, r +bindd = $mod, up, Focus en haut, movefocus, u +bindd = $mod, down, Focus en bas, movefocus, d -# Souris : déplacer / redimensionner les fenêtres +# --- Déplacer la fenêtre (Maj + flèches) --------------------------------------- +bindd = $mod SHIFT, left, Déplacer la fenêtre à gauche, movewindow, l +bindd = $mod SHIFT, right, Déplacer la fenêtre à droite, movewindow, r +bindd = $mod SHIFT, up, Déplacer la fenêtre en haut, movewindow, u +bindd = $mod SHIFT, down, Déplacer la fenêtre en bas, movewindow, d + +# --- Redimensionner (Ctrl + flèches, maintien possible) ------------------------ +binde = $mod CTRL, left, resizeactive, -30 0 +binde = $mod CTRL, right, resizeactive, 30 0 +binde = $mod CTRL, up, resizeactive, 0 -30 +binde = $mod CTRL, down, resizeactive, 0 30 + +# --- Espaces de travail 1-10 (0 = espace 10, comme i3) -------------------------- +bindd = $mod, 1, Aller à l'espace 1, workspace, 1 +bindd = $mod, 2, Aller à l'espace 2, workspace, 2 +bindd = $mod, 3, Aller à l'espace 3, workspace, 3 +bindd = $mod, 4, Aller à l'espace 4, workspace, 4 +bindd = $mod, 5, Aller à l'espace 5, workspace, 5 +bindd = $mod, 6, Aller à l'espace 6, workspace, 6 +bindd = $mod, 7, Aller à l'espace 7, workspace, 7 +bindd = $mod, 8, Aller à l'espace 8, workspace, 8 +bindd = $mod, 9, Aller à l'espace 9, workspace, 9 +bindd = $mod, 0, Aller à l'espace 10, workspace, 10 +bindd = $mod SHIFT, 1, Envoyer la fenêtre vers l'espace 1, movetoworkspace, 1 +bindd = $mod SHIFT, 2, Envoyer la fenêtre vers l'espace 2, movetoworkspace, 2 +bindd = $mod SHIFT, 3, Envoyer la fenêtre vers l'espace 3, movetoworkspace, 3 +bindd = $mod SHIFT, 4, Envoyer la fenêtre vers l'espace 4, movetoworkspace, 4 +bindd = $mod SHIFT, 5, Envoyer la fenêtre vers l'espace 5, movetoworkspace, 5 +bindd = $mod SHIFT, 6, Envoyer la fenêtre vers l'espace 6, movetoworkspace, 6 +bindd = $mod SHIFT, 7, Envoyer la fenêtre vers l'espace 7, movetoworkspace, 7 +bindd = $mod SHIFT, 8, Envoyer la fenêtre vers l'espace 8, movetoworkspace, 8 +bindd = $mod SHIFT, 9, Envoyer la fenêtre vers l'espace 9, movetoworkspace, 9 +bindd = $mod SHIFT, 0, Envoyer la fenêtre vers l'espace 10, movetoworkspace, 10 + +# --- Multi-écrans (comme i3 : Super+Ctrl+1/2 = écran gauche/droit) ------------- +bindd = $mod CTRL, 1, Envoyer la fenêtre vers l'écran de gauche, movewindow, mon:l +bindd = $mod CTRL, 2, Envoyer la fenêtre vers l'écran de droite, movewindow, mon:r + +# --- Molette = changer d'espace de travail -------------------------------------- +bindd = $mod, mouse_up, Espace de travail précédent, workspace, e-1 +bindd = $mod, mouse_down, Espace de travail suivant, workspace, e+1 + +# --- Scratchpad (espace spécial) ------------------------------------------------- +bindd = $mod, S, Afficher le scratchpad, togglespecialworkspace, magic +bindd = $mod SHIFT, S, Envoyer la fenêtre au scratchpad, movetoworkspace, special:magic + +# --- Captures d'écran (grim/slurp → presse-papier ou ~/Images) ------------------- +bindd = , Print, Capture plein écran vers le presse-papier, exec, grim - | wl-copy +bindd = $mod, Print, Capture d'une zone vers le presse-papier, exec, grim -g "$(slurp)" - | wl-copy +bindd = $mod SHIFT, Print, Capture d'une zone vers ~/Images, exec, sh -c 'mkdir -p ~/Images && grim -g "$(slurp)" ~/Images/capture_$(date +%Y-%m-%d_%H-%M-%S).png' + +# --- Multimédia (touches XF86 : volume via PipeWire, lecture via playerctl) ------ +bindel = , XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ +bindel = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindl = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPrev, exec, playerctl previous + +# --- Souris : déplacer / redimensionner les fenêtres ----------------------------- bindm = $mod, mouse:272, movewindow bindm = $mod, mouse:273, resizewindow + +# --- Règles de fenêtres (comme i3) ------------------------------------------------ +# Syntaxe Hyprland ≥ 0.55 : champs « » + cibles « match:… » +# (validé contre le binaire avec --verify-config). +windowrule = float on, match:class ^(floating-term)$ +windowrule = size 900 550, match:class ^(floating-term)$ +windowrule = float on, match:class ^([Pp]avucontrol|org.pulseaudio.pavucontrol)$ +windowrule = float on, match:title ^(Picture-in-Picture)$ From d8e67fe861fd358db72d3ed51b519774230c1ac3 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:09 +0200 Subject: [PATCH 009/136] refactor(anaconda): clarify payload mechanism and enhance desktop environment configurations Update interactive-defaults.ks kickstart file with: - Clarified documentation on LiveOS payload detection and mounting via /run/rootfsbase bind-mount instead of direct liveimg directive - Added comprehensive comments explaining why liveimg directive is intentionally omitted and how anaconda --liveinst handles payload creation - Enhanced XFCE and Hyprland package sets with noto-fonts for proper TTF rendering and additional tools (thunar, hyprlock, grim, slurp, wl-clipboard, playerctl) - Implemented SDDM theme configuration with FWS theme support and accent colors per desktop environment (teal for XFCE, Catppuccin blue for Hyprland, Breeze blue for KDE) - Added GDM (GNOME) configuration via dconf with welcome banner, clock enhancements, and numlock settings - Expanded Waybar configuration installation for Hyprland with config and style files - Added comprehensive documentation for greeter customization and Hyprland VM compatibility - Included details about FWS recap spoke (standalone GUI summary screen) replacing zenity-based pre-install approach --- .../share/anaconda/interactive-defaults.ks | 127 ++++++++++++++---- 1 file changed, 102 insertions(+), 25 deletions(-) diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index e973570..5ad44c3 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -5,33 +5,36 @@ # lancée en mode interactif (chemin fixe codé en dur dans Anaconda : # /usr/share/anaconda/interactive-defaults.ks). Aucun inst.ks= n'est requis. # -# RÔLE : empêcher Anaconda d'installer Fedora. +# RÔLE : finaliser une install « copie du live » (surtout pas Fedora). # ---------------------------------------------------------------------------- -# Sans payload défini, Anaconda utilise DNF → des RPM depuis les dépôts -# Fedora = il installe Fedora. Anaconda n'a AUCUN backend pacman. La seule -# façon de poser FWS/Arch est le payload « liveimg » : il recopie une image -# de système de fichiers (ici le squashfs du live = FWS) sur le disque, puis -# on finalise nous-mêmes (grub, mkinitcpio, bureau) en %post. C'est le modèle -# « Sabayon » : le système installé EST une copie du live. +# Anaconda n'a AUCUN backend pacman ; son payload par défaut (DNF) poserait +# des RPM Fedora. Ici le payload est LiveOS, imposé par « anaconda --liveinst » +# (cf. bloc « Source d'installation » ci-dessous) : il recopie le squashfs du +# live (= FWS) sur le disque, puis on finalise nous-mêmes (grub, mkinitcpio, +# bureau) en %post. C'est le modèle « Sabayon » : le système installé EST une +# copie du live. # # L'utilisateur garde la main dans le GUI sur tout ce qui N'EST PAS fixé ici : # partitionnement, fuseau, clavier, langue, création d'utilisateur, mot de # passe root, etc. # ============================================================================ -# --- Source d'installation : l'image du live (FWS), surtout pas Fedora ------- -# Squashfs archiso sur le média booté : -# /run/archiso/bootmnt///airootfs.sfs -# install_dir=fws, arch=x86_64, airootfs_image_type=squashfs (cf. profiledef.sh). -# Anaconda loop-monte ce .sfs et rsync son contenu vers la cible. +# --- Source d'installation : le payload LiveOS (surtout pas Fedora/DNF) ------ +# AUCUNE directive de payload ici, et c'est VOULU. liveinst lance +# « anaconda --liveinst » et anaconda.py teste opts.liveinst AVANT le type du +# payload DBus → il crée TOUJOURS un payload LiveOS et IGNORE tout payload du +# kickstart (un « liveimg » ici serait du code mort — vérifié dans +# pyanaconda/anaconda.py, propriété payload, et reproduit hors VM). # -# ⚠ À VALIDER sur ISO réelle : certaines versions d'Anaconda attendent une -# structure « LiveOS/rootfs.img » à l'intérieur du squashfs (format Fedora -# Live) et non un squashfs « plat » comme celui d'archiso. Si l'install -# échoue à monter la source, basculer sur un tarball de rootfs dédié : -# liveimg --url=file:///run/archiso/bootmnt/fws/x86_64/fws-rootfs.tar.gz -# (un build-rootfs.sh produirait alors ce tar via pacstrap). -liveimg --url=file:///run/archiso/bootmnt/fws/x86_64/airootfs.sfs +# Le payload LiveOS détecte l'image live via /dev/mapper/live-base ou +# /run/rootfsbase (chemins Fedora/dracut, absents d'archiso → c'était le crash +# « SourceSetupError: No Live OS image found! » au démarrage). Le .xinitrc du +# live bind-monte donc /run/archiso/airootfs (squashfs FWS, ro) sur +# /run/rootfsbase AVANT de lancer liveinst : Anaconda monte le loop device et +# rsync son contenu vers la cible = le système installé EST une copie du live, +# puis on finalise en %post (grub, mkinitcpio, bureau, matériel). +# DNF/libdnf5 n'est jamais importé : le module DNF n'est chargé QUE si le +# payload actif est DNF (import lazy dans modules/payloads/payload/factory.py). # --- Disque : repartir d'un disque PROPRE, même s'il a déjà servi ------------ # Sans ça, une réinstallation sur un disque déjà partitionné (typiquement une @@ -69,9 +72,21 @@ clearpart --all --initlabel --disklabel=msdos # partitionnement (auto ou manuel) car la plateforme l'impose. bootloader --disabled -# Pas de section %packages : le payload liveimg n'installe aucun paquet +# Pas de section %packages : le payload LiveOS n'installe aucun paquet # (il copie une image). Toute installation de paquets se fait en %post. +# --- Récapitulatif avant installation : PAGE GUI dédiée (pas de %pre-install) - +# L'écran « RÉCAPITULATIF AVANT INSTALLATION » est une standalone spoke +# Anaconda (overlay airootfs : pyanaconda/ui/gui/spokes/fws_recap.py, +# postForHub=SummaryHub, priority -10) intercalée ENTRE le hub et l'écran de +# progression : l'utilisateur clique « Commencer l'installation », voit le +# récap (bureau choisi, hostname, disques, GPU, réseau — AUCUNE écriture +# disque à ce stade), et l'installation ne démarre qu'à son clic « Lancer +# l'installation ». L'ancien récap zenity en %pre-install a été abandonné : +# le module scripts tourne avec LC_ALL=C et un env X incertain (zenity 4 +# refuse les libellés UTF-8 en locale C → rc=255 pris pour « Annuler » → +# poweroff en plein install au 1er test réel). + # ============================================================================ # %post --nochroot — s'exécute dans le LIVE, la cible montée sous /mnt/sysroot @@ -250,8 +265,13 @@ DM="" case "$DESK" in kde) PKGS="plasma-meta sddm konsole dolphin"; DM="sddm" ;; gnome) PKGS="gnome gdm"; DM="gdm" ;; - xfce) PKGS="xfce4 xfce4-goodies sddm"; DM="sddm" ;; - hyprland) PKGS="hyprland kitty wofi waybar sddm"; DM="sddm" ;; + # noto-fonts : KDE l'a via plasma-meta et GNOME a cantarell, mais XFCE et + # Hyprland ne garantissent AUCUNE police TTF → greeter SDDM/apps illisibles. + # Hyprland : la stack des raccourcis FWS (mêmes touches que la config + # i3/sway maison) — thunar (Super+E), hyprlock (Super+L), grim+slurp+ + # wl-clipboard (captures), playerctl (touches multimédia). + xfce) PKGS="xfce4 xfce4-goodies sddm noto-fonts"; DM="sddm" ;; + hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts thunar hyprlock grim slurp wl-clipboard playerctl"; DM="sddm" ;; cli|*) PKGS="" ;; esac # Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI). @@ -262,10 +282,60 @@ if [ -n "$PKGS" ]; then if pacman -Sy --noconfirm $PKGS; then [ -n "$DM" ] && systemctl enable "$DM" || true systemctl set-default graphical.target || true - # SDDM (KDE / XFCE / Hyprland) : pavé numérique allumé au login. + # SDDM (KDE / XFCE / Hyprland) : pavé numérique + écran de connexion FWS. + # Le thème « fws » (livré par l'airootfs → recopié par le payload dans + # /usr/share/sddm/themes/fws) est en pur QtQuick/Controls Basic : + # qt6-declarative, dépendance de sddm, suffit → même écran soigné pour + # les 3 DE SANS paquet de thème supplémentaire (Breeze n'existe qu'avec + # plasma). Accent adapté au bureau via theme.conf.user (mécanisme de + # surcharge standard de SDDM, lu par-dessus theme.conf du thème). if [ "$DM" = "sddm" ]; then install -d /etc/sddm.conf.d - printf '[General]\nNumlock=on\n' > /etc/sddm.conf.d/10-fws.conf + cat > /etc/sddm.conf.d/10-fws.conf <<'SDDMEOF' +[General] +Numlock=on + +[Theme] +Current=fws +SDDMEOF + case "$DESK" in + xfce) _ACCENT="#16a085" ;; # sarcelle (assorti à XFCE) + hyprland) _ACCENT="#89b4fa" ;; # bleu Catppuccin (assorti à Hyprland) + *) _ACCENT="#3daee9" ;; # bleu Breeze (KDE, défaut) + esac + if [ -d /usr/share/sddm/themes/fws ]; then + printf '[General]\naccent=%s\n' "$_ACCENT" \ + > /usr/share/sddm/themes/fws/theme.conf.user + else + echo "[FWS] thème SDDM fws introuvable — thème par défaut conservé" + sed -i '/^Current=fws$/d' /etc/sddm.conf.d/10-fws.conf + fi + fi + # GDM (GNOME) : « la même chose » autant que possible — le greeter de + # GDM EST GNOME Shell, il ne se thème pas comme SDDM. On passe par + # dconf (base système « gdm ») : bannière d'accueil FWS, horloge avec + # date complète, pavé numérique allumé — même confort qu'avec SDDM. + if [ "$DM" = "gdm" ]; then + install -d /etc/dconf/profile /etc/dconf/db/gdm.d + cat > /etc/dconf/profile/gdm <<'GDMEOF' +user-db:user +system-db:gdm +file-db:/usr/share/gdm/greeter-dconf-defaults +GDMEOF + cat > /etc/dconf/db/gdm.d/10-fws <<'GDMEOF' +[org/gnome/login-screen] +banner-message-enable=true +banner-message-text='Bienvenue sur FWS' + +[org/gnome/desktop/interface] +clock-show-date=true +clock-show-weekday=true + +[org/gnome/desktop/peripherals/keyboard] +numlock-state=true +remember-numlock-state=false +GDMEOF + dconf update || echo "[FWS] dconf update a échoué (bannière GDM à refaire)" fi # Hyprland en VM : sur GPU virtuel (VMware/VirtualBox) le compositeur # crashe au lancement → SDDM « remet au login ». On le lance via un @@ -317,11 +387,18 @@ if [ "$DESK" = "hyprland" ] && [ -f /usr/local/share/fws/hyprland.conf.tmpl ]; t sed -e "s/__KB_LAYOUT__/${XL:-us}/" -e "s/__KB_VARIANT__/${XV}/" \ /usr/local/share/fws/hyprland.conf.tmpl > /tmp/fws-hyprland.conf install -Dm644 /tmp/fws-hyprland.conf /etc/skel/.config/hypr/hyprland.conf + # Waybar FWS : barre assortie + bouton « ⌨ Raccourcis » (fws-hypr-keys, + # aussi sur SUPER+K) qui liste les binds RÉELS chargés par Hyprland + # (hyprctl binds -j) — les descriptions viennent des bindd de la config. + install -Dm644 /usr/local/share/fws/waybar-config.json /etc/skel/.config/waybar/config + install -Dm644 /usr/local/share/fws/waybar-style.css /etc/skel/.config/waybar/style.css while IFS=: read -r _u _x _uid _g _gec _home _sh; do [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ] && [ -d "$_home" ] || continue install -Dm644 /tmp/fws-hyprland.conf "$_home/.config/hypr/hyprland.conf" + install -Dm644 /usr/local/share/fws/waybar-config.json "$_home/.config/waybar/config" + install -Dm644 /usr/local/share/fws/waybar-style.css "$_home/.config/waybar/style.css" chown "$_u": "$_home/.config" 2>/dev/null || true - chown -R "$_u": "$_home/.config/hypr" 2>/dev/null || true + chown -R "$_u": "$_home/.config/hypr" "$_home/.config/waybar" 2>/dev/null || true done < /etc/passwd rm -f /tmp/fws-hyprland.conf fi From 35f77ba33da2effd913258c3854e1f45180c8f8f Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:13 +0200 Subject: [PATCH 010/136] chore(releng): add file permissions for fws-hypr-keys script --- configs/releng/profiledef.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/releng/profiledef.sh b/configs/releng/profiledef.sh index f3869a9..9aae7dd 100644 --- a/configs/releng/profiledef.sh +++ b/configs/releng/profiledef.sh @@ -25,4 +25,5 @@ file_permissions=( ["/usr/bin/load_policy"]="0:0:755" ["/usr/bin/setstatus"]="0:0:755" ["/usr/local/bin/fws-setup-hardware"]="0:0:755" + ["/usr/local/bin/fws-hypr-keys"]="0:0:755" ) From 5e66f99816391f181c56751daee58bcbb4f6762f Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:20 +0200 Subject: [PATCH 011/136] feat(syslinux): add safe graphics boot option with nomodeset kernel parameter Add a new boot menu entry for FWS without kernel mode setting (KMS) to provide a fallback option for systems where KMS causes issues. This entry uses the nomodeset kernel parameter to force the framebuffer to VESA/EFI mode, which is slower but more reliable for problematic GPU drivers and hypervisors like VMware. --- configs/releng/syslinux/archiso_sys-linux.cfg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/configs/releng/syslinux/archiso_sys-linux.cfg b/configs/releng/syslinux/archiso_sys-linux.cfg index 40e365c..4b238a3 100644 --- a/configs/releng/syslinux/archiso_sys-linux.cfg +++ b/configs/releng/syslinux/archiso_sys-linux.cfg @@ -8,6 +8,23 @@ LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% +# Mode graphique de secours : SANS KMS (nomodeset). Filet de sécurité +# standard pour les GPU/hyperviseurs dont le pilote KMS pose problème : +# X démarre alors sur le framebuffer VESA/EFI (plus lent mais fiable). +# NB : la lenteur au démarrage vue en VM VMware (2-4 min d'écran bleu) +# N'EST PAS un gel graphique — c'est un worker udev tué après 180 s ; +# le boot normal finit par afficher l'installateur (splash ajouté). +LABEL fwsnomodeset +TEXT HELP +Boot FWS WITHOUT kernel mode setting (safe graphics). +Use this if the normal boot freezes on a black/blank screen +(e.g. VMware Workstation vmwgfx hang). +ENDTEXT +MENU LABEL FWS install medium (%ARCH%, BIOS, ^safe graphics) +LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% nomodeset + # Accessibility boot option LABEL fwsspeech TEXT HELP From 4249282052079ef391b6b4b2c874f04afd0d84c5 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:25 +0200 Subject: [PATCH 012/136] fix(python-meh): fix python 3.11 compatibility by replacing removed gettext.ldgettext Replace gettext.ldgettext with gettext.dgettext in Anaconda exception handler since ldgettext was removed in Python 3.11. Without this fix, the exception handler crashes with AttributeError when trying to display errors, resulting in raw tracebacks instead of the meh dialog in both GUI and TUI modes. Also clean up stale __pycache__ directories from previous extractions and add validation to ensure ldgettext is completely removed. --- pkgbuilds/python-meh/PKGBUILD | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pkgbuilds/python-meh/PKGBUILD b/pkgbuilds/python-meh/PKGBUILD index 7d565ed..311d121 100644 --- a/pkgbuilds/python-meh/PKGBUILD +++ b/pkgbuilds/python-meh/PKGBUILD @@ -5,7 +5,7 @@ # l'arborescence à la main plutôt que de patcher la chaîne distutils. pkgname=python-meh pkgver=0.43 -pkgrel=1 +pkgrel=2 pkgdesc="Python exception handling library (dépendance Anaconda)" arch=('any') url="https://github.com/rhinstaller/python-meh" @@ -16,6 +16,24 @@ source=("$pkgname-$pkgver.tar.gz::https://github.com/rhinstaller/python-meh/arch sha256sums=('cd50301794ab68a064715f1ace960f6de07aea809aa85f73087d44573c98be52') _srcdir="python-meh-$_tag" +prepare() { + cd "$srcdir/$_srcdir" + # gettext.ldgettext a été SUPPRIMÉ en Python 3.11 : sans ce remplacement, le + # gestionnaire d'exceptions d'Anaconda plante LUI-MÊME (AttributeError) dès + # qu'il doit AFFICHER une erreur → traceback brut au lieu du dialogue meh, + # en GUI comme en TUI. dgettext est l'équivalent direct (ldgettext n'était + # que la variante bytes). Corrigé en amont après 0.43. + sed -i 's/gettext\.ldgettext(/gettext.dgettext(/' \ + meh/handler.py meh/ui/text.py meh/ui/gui.py + # .pyc d'une extraction précédente (src/ n'est pas nettoyé par makepkg -f) : + # à jeter, sinon ils partiraient dans le paquet via cp -a. + find meh -type d -name __pycache__ -exec rm -rf {} + + if grep -rn --include='*.py' 'ldgettext' meh/; then + echo "ERREUR : ldgettext encore présent après patch" >&2 + return 1 + fi +} + package() { cd "$srcdir/$_srcdir" local sitedir From 7fe54d07916c9834529475b7d6b54ac6f0fca16a Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:32 +0200 Subject: [PATCH 013/136] fix(setup-aur.sh)!: use explicit package list instead of glob for install and publish Change publish_to_repo() to accept explicit file list via variadic arguments instead of a directory glob. This prevents re-publishing stale .pkg files from previous builds that may still exist in BUILD_DIR. Update build_or_skip() to get the actual list of packages produced by the current makepkg invocation using --packagelist, filter for .pkg.tar.* files, verify they exist on disk, and pass only those to pacman -U and publish_to_repo(). This fixes issues where: - After pkgrel bumps, old .pkg files would cause pacman to receive duplicate package names ("repeated target" error) - Stale packages would be republished over the purge in local-repo - Optional debug packages would cause errors when not produced BREAKING CHANGE: publish_to_repo() function signature changed from publish_to_repo(name, directory) to publish_to_repo(name, file1, file2, ...) - callers must pass explicit file paths instead of a directory path --- setup-aur.sh | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/setup-aur.sh b/setup-aur.sh index c73e05a..d446f91 100755 --- a/setup-aur.sh +++ b/setup-aur.sh @@ -232,11 +232,14 @@ repo_has() { # Publie les .pkg d'un build vers local-repo en purgeant d'abord les anciennes # versions de CE paquet (+ son sous-paquet -debug). Le « -[0-9] » empêche # « anaconda » d'attraper « anaconda-widgets » / « anaconda-debug ». +# Prend la LISTE EXPLICITE des fichiers à publier (pas un glob sur le dossier : +# un .pkg d'un build précédent peut traîner dans $BUILD_DIR/ et serait +# republié par-dessus la purge). publish_to_repo() { - local name="$1" d="$2" + local name="$1"; shift rm -f "$LOCAL_REPO/$name"-[0-9]*.pkg.tar.* \ "$LOCAL_REPO/$name"-debug-[0-9]*.pkg.tar.* 2>/dev/null || true - cp -f "$d"/*.pkg.tar.* "$LOCAL_REPO/" || error "Copie de $name vers local-repo échouée" + cp -f "$@" "$LOCAL_REPO/" || error "Copie de $name vers local-repo échouée" } # Construit OU saute (source déjà déposée dans $BUILD_DIR/). @@ -259,8 +262,23 @@ build_or_skip() { chown -R "$BUILD_USER:$BUILD_USER" "$d" su - "$BUILD_USER" -c "cd '$d' && makepkg -sf --noconfirm" \ || error "Build $name échoué" - pacman -U --noconfirm "$d/"*.pkg.tar.* || error "Install de $name échouée" - publish_to_repo "$name" "$d" + # N'installer/publier QUE les paquets produits par CE PKGBUILD dans SA + # version courante (makepkg --packagelist), jamais un glob "$d/"* : après + # un bump de pkgrel, l'ancien .pkg traîne encore dans $d (BUILD_DIR n'est + # pas nettoyé entre les runs) → pacman -U recevait 2× le même nom de + # paquet (« erreur : cible répétée ») et la vieille version repartait + # dans local-repo. Le grep filtre tout bruit éventuel de su - (PAM…). + # NB : --packagelist liste aussi un -debug qui n'est PAS toujours produit + # (paquet pur python : rien à stripper) → ne garder que les fichiers + # réellement présents sur disque. + local -a pkgfiles=() existing=() + local f + mapfile -t pkgfiles < <(su - "$BUILD_USER" -c "cd '$d' && makepkg --packagelist" \ + | grep -E '\.pkg\.tar\.') + for f in "${pkgfiles[@]}"; do [ -e "$f" ] && existing+=("$f"); done + [ "${#existing[@]}" -gt 0 ] || error "Aucun paquet produit trouvé pour $name" + pacman -U --noconfirm "${existing[@]}" || error "Install de $name échouée" + publish_to_repo "$name" "${existing[@]}" success "$name build + install OK" } From 9df1f444bc081acea89f39b4944f6380149cd5ab Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:39 +0200 Subject: [PATCH 014/136] feat(fws): add recap spoke for pre-installation summary Add FWSRecapSpoke, a standalone spoke that displays a comprehensive summary of user configuration choices and detected hardware before installation begins. The spoke intercepts the installation flow between the SummaryHub and ProgressSpoke, allowing users to review and modify their choices before any disk writes occur. Features: - Displays user-selected configuration (language, keyboard, timezone, users, partitioning, desktop, hostname) - Shows detected hardware (virtualization, GPUs, disks, network status) - Provides installation flow overview and warnings about automatic partitioning - Implements back navigation to return to the hub for modifications - Never marks as completed to ensure proper flow control in anaconda's action queue --- .../pyanaconda/ui/gui/spokes/fws_recap.py | 347 ++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py diff --git a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py new file mode 100644 index 0000000..2f97af5 --- /dev/null +++ b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py @@ -0,0 +1,347 @@ +# FWS — Page « Récapitulatif » : écran À PART ENTIÈRE avant l'installation. +# +# POURQUOI ICI (airootfs, pas dans le paquet anaconda) : même mécanisme que la +# spoke « Desktop Environment » (fws_desktop.py) — Anaconda découvre les spokes +# au RUNTIME (collect) dans ce dossier → l'overlay airootfs suffit, AUCUN +# rebuild du paquet anaconda. Le glade associé est dans +# /usr/share/anaconda/ui/spokes/fws_recap.glade (aussi via l'airootfs). +# +# PLACEMENT DANS LE FLUX : standalone spoke « postForHub = SummaryHub » avec +# priority = -10. L'ordre des écrans est pre(SummaryHub) → SummaryHub → +# post(SummaryHub) trié par priority croissante (UserInterface. +# _orderActionClasses). ProgressSpoke — l'écran qui DÉMARRE l'installation +# dans son refresh() — est aussi post(SummaryHub), priority 0 par défaut → +# cette page s'intercale ENTRE les deux : l'utilisateur clique « Commencer +# l'installation » sur le hub, voit CE récapitulatif (le disque n'a encore +# subi AUCUNE écriture), et l'installation ne démarre qu'à son clic +# « Lancer l'installation ». Le bouton « Précédent » ramène au hub pour +# modifier les choix (cf. _on_back_clicked : la file d'actions du GUI est +# consommée à chaque écran, on y réinsère le hub). +# +# CONTENU : configuration choisie par l'utilisateur (via les modules D-Bus +# d'Anaconda : langue, clavier, fuseau, comptes, partitionnement + les +# fichiers /tmp des spokes FWS : bureau, hostname) ET matériel détecté +# (virtualisation, GPU, disques, réseau) — mêmes sources que ce que le +# %post du kickstart et fws-setup-hardware appliqueront. +# +# ⚠ « completed » doit rester False : _instantiateAction SAUTE les standalone +# spokes complétées (mécanisme prévu pour les installs kickstart). +# ⚠ Chemin couplé à la version Python d'Arch (3.14) — comme fws_desktop.py — +# et le bouton « Précédent » s'appuie sur les internes du GUI d'anaconda +# 45.8 (_actions/_currentAction) : à re-vérifier à chaque bump d'anaconda. + +import inspect + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +from pyanaconda.anaconda_loggers import get_module_logger +from pyanaconda.core import util +from pyanaconda.modules.common.constants.objects import DISK_SELECTION +from pyanaconda.modules.common.constants.services import ( + LOCALIZATION, + STORAGE, + TIMEZONE, + USERS, +) +from pyanaconda.modules.common.structures.user import UserData +from pyanaconda.ui.gui import GraphicalUserInterface +from pyanaconda.ui.gui.hubs.summary import SummaryHub +from pyanaconda.ui.gui.spokes import StandaloneSpoke + +log = get_module_logger(__name__) + +__all__ = ["FWSRecapSpoke"] + +# Doit rester aligné sur le %post du kickstart (étape « Bureau choisi ») et +# sur les libellés de la spoke fws_desktop. +_DESKTOP_LABELS = { + "cli": "ligne de commande uniquement (aucun bureau)", + "gnome": "GNOME (+ Firefox, GDM)", + "kde": "KDE Plasma (+ Firefox, SDDM)", + "hyprland": "Hyprland (+ Firefox, SDDM)", + "xfce": "XFCE (+ Firefox, SDDM)", +} + +_PARTITIONING_LABELS = { + "AUTOMATIC": "automatique (recommandé)", + "INTERACTIVE": "personnalisé (assistant)", + "CUSTOM": "personnalisé", + "BLIVET": "avancé (blivet-gui)", + "MANUAL": "points de montage manuels", +} + + +def _safe(getter, default): + """Valeur d'un getter D-Bus/système, ou défaut : le récap ne doit JAMAIS + faire tomber l'installateur, quel que soit le module indisponible (d'où + le except large : dasbus lève des types variés selon la panne).""" + try: + return getter() + except Exception: # pylint: disable=broad-except + return default + + +def _capture(*argv): + """stdout d'une commande, chaîne vide si absente ou en échec.""" + try: + return util.execWithCapture(argv[0], list(argv[1:])) or "" + except (OSError, RuntimeError): + return "" + + +def _read_flag(path): + try: + with open(path) as fh: + return fh.read().strip() + except OSError: + return "" + + +def _config_lines(): + """Section « configuration choisie » : interroge les modules D-Bus + d'Anaconda (remplis par les spokes) + les fichiers /tmp des spokes FWS.""" + lines = [] + + lang = _safe(lambda: LOCALIZATION.get_proxy().Language, "") + if lang: + lines.append(f" • Langue : {lang}") + + layouts = _safe(lambda: list(LOCALIZATION.get_proxy().XLayouts), []) + if layouts: + lines.append(f" • Clavier (X11) : {', '.join(layouts)}") + + tz = _safe(lambda: TIMEZONE.get_proxy().Timezone, "") + if tz: + ntp = _safe(lambda: TIMEZONE.get_proxy().NTPEnabled, None) + suffix = {True: " — synchronisation NTP activée", + False: " — synchronisation NTP désactivée"}.get(ntp, "") + lines.append(f" • Fuseau horaire : {tz}{suffix}") + + users = _safe( + lambda: UserData.from_structure_list(USERS.get_proxy().Users), []) + if users: + names = ", ".join(u.name for u in users if u.name) + lines.append(f" • Utilisateur(s) : {names} (sudo via wheel)") + else: + lines.append(" • Utilisateur(s) : AUCUN — pensez-y avant de lancer !") + + root_locked = _safe(lambda: USERS.get_proxy().IsRootAccountLocked, None) + root_pw = _safe(lambda: USERS.get_proxy().IsRootPasswordSet, None) + if root_locked: + root_txt = "verrouillé (recommandé)" + elif root_pw: + root_txt = "actif, mot de passe défini" + elif root_pw is not None: + # Même règle que l'étape « Sécurité » du %post : un root resté sans + # mot de passe sera verrouillé en fin d'installation. + root_txt = "sans mot de passe → sera VERROUILLÉ en fin d'install" + else: + root_txt = "" + if root_txt: + lines.append(f" • Compte root : {root_txt}") + + # Hostname : écrit par le spoke Utilisateur (patch user.py du paquet + # anaconda). Même nettoyage / même défaut que le %post --nochroot. + hn = "".join(c for c in _read_flag("/tmp/fws-hostname") + if c.isalnum() or c in "._-") or "fws" + lines.append(f" • Nom de machine : {hn}") + + # Bureau : écrit par fws_desktop.apply() (sortie de la spoke). Absent = + # spoke jamais visitée = « cli », exactement le défaut du %post. + desk = _read_flag("/tmp/fws-desktop") or "cli" + lines.append(f" • Bureau : {_DESKTOP_LABELS.get(desk, desk)}") + + method = _safe( + lambda: STORAGE.get_proxy( + STORAGE.get_proxy().AppliedPartitioning).PartitioningMethod, "") + if method: + lines.append(" • Partitionnement : " + f"{_PARTITIONING_LABELS.get(method, method)}") + + return lines, desk, method + + +def _build_summary(): + config_lines, desk, method = _config_lines() + config_text = "\n".join(config_lines) \ + or " (configuration non disponible)" + + # Disques ciblés par l'installation (spoke « Destination »). + selected = set(_safe( + lambda: list(STORAGE.get_proxy(DISK_SELECTION).SelectedDisks), [])) + disks = [] + for line in _capture("lsblk", "-dno", "NAME,SIZE,MODEL,TYPE").splitlines(): + fields = line.split() + if fields and fields[-1] == "disk": + mark = " ← CIBLE de l'installation" if fields[0] in selected else "" + disks.append(" • " + " ".join(fields[:-1]) + mark) + disk_text = "\n".join(disks) or " (aucun disque détecté)" + + if method == "AUTOMATIC": + disk_warn = ( + " ⚠ Rien n'a encore été écrit. Le partitionnement automatique\n" + " EFFACERA ENTIÈREMENT le(s) disque(s) cible(s) au lancement.") + else: + disk_warn = ( + " ⚠ Rien n'a encore été écrit. Au lancement, ce sont vos choix\n" + " de partitionnement faits dans l'installateur qui s'appliqueront.") + + virt = (_capture("systemd-detect-virt").strip().splitlines() or ["none"])[0] + if virt in ("", "none"): + virt = "aucune (machine physique)" + + gpus = [] + for line in _capture("lspci").splitlines(): + low = line.lower() + if ("vga" in low or "3d" in low or "display" in low) and ":" in line: + gpus.append(" • " + line.split(":", 2)[-1].strip()) + gpu_text = "\n".join(gpus) or " (aucune carte graphique détectée)" + + try: + net_ok = util.execWithRedirect("ip", ["route", "get", "1.1.1.1"]) == 0 + except (OSError, RuntimeError): + net_ok = False + if net_ok: + net = "disponible ✔" + else: + net = ("INDISPONIBLE ✖ — bureau, drivers et stack FWS ne\n" + " s'installeront PAS (rattrapable au 1er boot)") + + extras = ("Steam, Wine, VR (Monado/OpenXR), winboat-bin" + if desk != "cli" else "rien de plus (choix CLI)") + + return f"""\ +══════════════════════════════════════════════════════════ + FWS — RÉCAPITULATIF AVANT INSTALLATION +══════════════════════════════════════════════════════════ + +CONFIGURATION CHOISIE +{config_text} + +DISQUES +{disk_warn} +{disk_text} + +MATÉRIEL DÉTECTÉ + • Virtualisation : {virt} + • Réseau : {net} + Cartes graphiques (drivers installés automatiquement en fin d'install) : +{gpu_text} + +DÉROULEMENT DE L'INSTALLATION + 1. Partitionnement, puis copie du système live FWS (payload LiveOS) + 2. Noyau + initramfs régénérés (mkinitcpio), GRUB installé + 3. Bureau choisi + navigateur installés (réseau requis) + 4. Matériel : drivers GPU, outils VM, son, Bluetooth, Podman + + si bureau choisi : {extras} + +« Précédent » pour revenir modifier vos choix — +« Lancer l'installation » pour démarrer réellement l'installation. +""" + + +class FWSRecapSpoke(StandaloneSpoke): + """Récapitulatif des choix, affiché entre le hub et l'installation.""" + + builderObjects = ["fwsRecapWindow"] + mainWidgetName = "fwsRecapWindow" + uiFile = "spokes/fws_recap.glade" + + postForHub = SummaryHub + priority = -10 + + @staticmethod + def get_screen_id(): + """Identifiant unique de cet écran.""" + return "fws-recap" + + @property + def completed(self): + # False, sinon _instantiateAction saute l'écran (cf. en-tête). + return False + + def apply(self): + # Rien à persister : cette page ne fait que montrer l'état. + pass + + def initialize(self): + StandaloneSpoke.initialize(self) + # Le bouton « continuer » de CETTE page est le vrai déclencheur : + # l'écran suivant (ProgressSpoke) démarre la file d'installation. + self.window.get_continue_button().set_label("_Lancer l'installation") + + # Capture pour « Précédent » : initialize() est appelé DEPUIS + # GraphicalUserInterface._on_continue_clicked (clic « Commencer + # l'installation » du hub), AVANT la bascule de _currentAction → à + # cet instant ui._currentAction est ENCORE l'instance du hub Résumé, + # et le « self » de l'appelant est l'UI. Aucune API publique ne les + # expose ; on remonte la pile d'appels (déterministe — pas de scan + # mémoire, pas de variable globale). + self._gui = None + self._hub = None + frame = inspect.currentframe() + try: + frame = frame.f_back + while frame is not None: + candidate = frame.f_locals.get("self") + if isinstance(candidate, GraphicalUserInterface): + self._gui = candidate + current = getattr(candidate, "_currentAction", None) + if isinstance(current, SummaryHub): + self._hub = current + break + frame = frame.f_back + finally: + del frame + + # Bouton « Précédent », placé avec les boutons de navigation + # (à côté de « Quitter » — leur parent est la GtkButtonBox du bas). + quit_button = self.window.get_quit_button() + button_box = quit_button.get_parent() + self._back_button = Gtk.Button.new_with_mnemonic("_Précédent") + self._back_button.connect("clicked", self._on_back_clicked) + button_box.add(self._back_button) + button_box.reorder_child(self._back_button, 0) + if self._gui is None or self._hub is None: + # Références introuvables (flux inattendu) : bouton grisé plutôt + # qu'une navigation cassée — l'install reste possible. + log.warning("FWS recap: hub/UI introuvables, « Précédent » désactivé.") + self._back_button.set_sensitive(False) + self._back_button.show() + + def _on_back_clicked(self, _button): + ui = self._gui + hub = self._hub + if ui is None or hub is None: + return + log.info("FWS recap: retour au hub Résumé pour modification.") + # La file d'actions du GUI est CONSOMMÉE (pop(0)) à chaque écran : + # ici _actions = [FWSRecapSpoke, ProgressSpoke] et le hub en est déjà + # sorti. On le réinsère en tête pour que le prochain « Commencer + # l'installation » ré-enchaîne hub → NOUVELLE page récap (résumé + # recalculé avec les choix modifiés) → installation. + if not ui._actions or ui._actions[0] is not SummaryHub: + ui._actions.insert(0, SummaryHub) + # _on_continue_clicked a désactivé le « continuer » du hub en le + # quittant : on le réarme, sinon « Commencer l'installation » est mort. + hub.window.set_may_continue(True) + # Même séquence que la transition officielle (_on_continue_clicked). + self.exited.emit(self) + hub.refresh() + ui.mainWindow.setCurrentAction(hub) + hub.entered.emit(hub) + ui._currentAction = hub + + def refresh(self): + StandaloneSpoke.refresh(self) + text = _build_summary() + self.builder.get_object("recapView").get_buffer().set_text(text) + # Copie pour le harnais de debug du .xinitrc (fws-debug.txt). + try: + with open("/tmp/fws-hw-summary.txt", "w") as fh: + fh.write(text) + except OSError: + pass From 7aa1276e2c65749b52a10de8acd90aae4e8b0408 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:44 +0200 Subject: [PATCH 015/136] feat(anaconda): add fws recap glade ui definition Add new Glade UI definition file for the FWS recap (summary before installation) spoke. This defines the AnacondaStandaloneWindow layout with a scrollable text view to display installation summary information. --- .../share/anaconda/ui/spokes/fws_recap.glade | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_recap.glade diff --git a/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_recap.glade b/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_recap.glade new file mode 100644 index 0000000..2b8885a --- /dev/null +++ b/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_recap.glade @@ -0,0 +1,85 @@ + + + + + + + False + RÉCAPITULATIF AVANT INSTALLATION + + + False + vertical + + + False + + + False + + + + + + + + + + + False + False + 0 + + + + + False + 0 + 12 + 6 + + + False + vertical + 6 + + + True + True + in + + + True + True + False + False + True + 12 + 12 + 12 + 12 + word-char + + + + + True + True + 0 + + + + + + + True + True + 1 + + + + + + From a28a64310a4982aebfcc37aa1e5d379b36ea3b16 Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:49 +0200 Subject: [PATCH 016/136] feat(releng): add fws-hypr-keys script to display hyprland keyboard shortcuts Add a new Python utility script that displays actual Hyprland keyboard shortcuts from hyprctl binds output. The script: - Queries hyprctl binds to get loaded key bindings from the compositor - Formats keybinds with human-readable modifiers and key labels (French localization) - Displays descriptions from bindd config entries or falls back to dispatcher actions - Opens results in wofi dmenu for incremental search and filtering - Handles special keys like mouse buttons, arrow keys, and common special keys - Deduplicates repeated bindings (e.g., from resize actions) No additional dependencies required beyond python3 and wofi (already in FWS + Hyprland packages). --- .../airootfs/usr/local/bin/fws-hypr-keys | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 configs/releng/airootfs/usr/local/bin/fws-hypr-keys diff --git a/configs/releng/airootfs/usr/local/bin/fws-hypr-keys b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys new file mode 100755 index 0000000..e8c5453 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# FWS — affiche les raccourcis clavier RÉELS de Hyprland. +# +# Source de vérité : « hyprctl binds -j » = les binds effectivement CHARGÉS +# par le compositeur (ceux de ~/.config/hypr/hyprland.conf, y compris ceux +# ajoutés par l'utilisateur après l'installation). Les descriptions viennent +# des « bindd » de la config ; un bind sans description affiche son action +# brute (dispatcher + argument). Affichage : wofi en mode dmenu (recherche +# incrémentale intégrée) — déclenché par le bouton ⌨ de la waybar ou SUPER+K. +# +# python3 et wofi sont déjà sur le système (image FWS + paquets Hyprland) : +# aucune dépendance supplémentaire. + +import json +import subprocess +import sys + +# Bits de modmask (masques X11) dans l'ordre d'affichage voulu. +_MODS = [ + (64, "SUPER"), + (4, "CTRL"), + (8, "ALT"), + (1, "SHIFT"), +] + +# Libellés humains pour les « touches » spéciales. +_KEY_LABELS = { + "mouse:272": "clic gauche", + "mouse:273": "clic droit", + "mouse:274": "clic molette", + "mouse_down": "molette bas", + "mouse_up": "molette haut", + "return": "Entrée", + "space": "Espace", + "escape": "Échap", + "tab": "Tab", + "left": "←", + "right": "→", + "up": "↑", + "down": "↓", +} + + +def _mods(mask): + return [name for bit, name in _MODS if mask & bit] + + +def _combo(bind): + parts = _mods(bind.get("modmask", 0)) + key = bind.get("key") or "" + if not key and bind.get("keycode"): + key = f"code {bind['keycode']}" + parts.append(_KEY_LABELS.get(key.lower(), key)) + return " + ".join(p for p in parts if p) + + +def _action(bind): + desc = (bind.get("description") or "").strip() + if desc: + return desc + arg = (bind.get("arg") or "").strip() + return f"{bind.get('dispatcher', '?')} {arg}".strip() + + +def main(): + try: + raw = subprocess.check_output(["hyprctl", "binds", "-j"], text=True) + binds = json.loads(raw) + except (OSError, subprocess.CalledProcessError, ValueError) as exc: + subprocess.run(["notify-send", "Raccourcis FWS", + f"hyprctl binds a échoué : {exc}"], check=False) + return 1 + + lines = [] + seen = set() + for bind in binds: + combo = _combo(bind) + if not combo or combo in seen: # binde répétés (resize) : une ligne + continue + seen.add(combo) + lines.append(f"{combo:<24} {_action(bind)}") + + if not lines: + lines = ["(aucun raccourci déclaré)"] + + # dmenu = liste + filtre incrémental ; la sélection n'a pas d'effet. + subprocess.run( + ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer", + "--width", "780", "--height", "560", "--insensitive", "--cache-file", "/dev/null"], + input="\n".join(lines), text=True, check=False) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 23df7656e5fd3af6d622361530fa1681c4bf761b Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:53 +0200 Subject: [PATCH 017/136] feat(waybar): add waybar configuration for hyprland desktop environment Add waybar panel configuration with modules for workspaces, window title, clock, volume, network, CPU, and memory monitoring. Configured for top panel layout with French localization support. --- .../usr/local/share/fws/waybar-config.json | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/share/fws/waybar-config.json diff --git a/configs/releng/airootfs/usr/local/share/fws/waybar-config.json b/configs/releng/airootfs/usr/local/share/fws/waybar-config.json new file mode 100644 index 0000000..e55339a --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/waybar-config.json @@ -0,0 +1,51 @@ +{ + "layer": "top", + "position": "top", + "height": 34, + "spacing": 4, + "modules-left": ["hyprland/workspaces", "hyprland/window"], + "modules-center": ["clock"], + "modules-right": ["custom/keyhelp", "pulseaudio", "network", "cpu", "memory", "tray"], + + "hyprland/workspaces": { + "format": "{id}", + "on-click": "activate" + }, + "hyprland/window": { + "max-length": 55, + "separate-outputs": true + }, + "clock": { + "format": "{:%H:%M}", + "format-alt": "{:%A %d %B %Y — %H:%M}", + "tooltip-format": "{calendar}" + }, + "custom/keyhelp": { + "format": "⌨ Raccourcis", + "tooltip-format": "Raccourcis clavier (SUPER+K)", + "on-click": "fws-hypr-keys" + }, + "pulseaudio": { + "format": "Vol {volume}%", + "format-muted": "Muet", + "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", + "tooltip": false + }, + "network": { + "format-wifi": "{essid}", + "format-ethernet": "{ipaddr}", + "format-disconnected": "hors ligne", + "tooltip-format": "{ifname} — {ipaddr}" + }, + "cpu": { + "format": "CPU {usage}%", + "interval": 3 + }, + "memory": { + "format": "RAM {percentage}%", + "interval": 3 + }, + "tray": { + "spacing": 8 + } +} From 5d6d1c6db8b6cb2f9a383e8067a9b26c31dea56f Mon Sep 17 00:00:00 2001 From: nocode Date: Fri, 3 Jul 2026 23:59:58 +0200 Subject: [PATCH 018/136] feat(waybar): add waybar style configuration for fws theme Add CSS stylesheet for Waybar that matches the FWS theme, SDDM appearance, and Hyprland borders. Includes styling for workspaces, clock, custom key help button, and system status modules with Catppuccin blue accent color (#89b4fa). --- .../usr/local/share/fws/waybar-style.css | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/share/fws/waybar-style.css diff --git a/configs/releng/airootfs/usr/local/share/fws/waybar-style.css b/configs/releng/airootfs/usr/local/share/fws/waybar-style.css new file mode 100644 index 0000000..6ef916e --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/waybar-style.css @@ -0,0 +1,63 @@ +/* FWS — style Waybar (assorti au thème SDDM et aux bordures Hyprland). */ + +* { + font-family: "Noto Sans", sans-serif; + font-size: 13px; + min-height: 0; +} + +window#waybar { + background: rgba(26, 26, 46, 0.92); /* #1a1a2e */ + color: #f0f0f5; + border-bottom: 2px solid #89b4fa; /* bleu FWS (Catppuccin) */ +} + +#workspaces button { + color: #a0a0b8; + padding: 0 10px; + border: none; + border-radius: 0; + background: transparent; +} + +#workspaces button.active { + color: #f0f0f5; + border-bottom: 2px solid #89b4fa; +} + +#workspaces button:hover { + background: rgba(255, 255, 255, 0.08); + box-shadow: none; +} + +#window { + color: #a0a0b8; + margin-left: 12px; +} + +#clock { + color: #f0f0f5; + font-weight: bold; +} + +#custom-keyhelp { + background: #89b4fa; + color: #1a1a2e; + font-weight: bold; + padding: 0 12px; + margin: 5px 6px; + border-radius: 8px; +} + +#custom-keyhelp:hover { + background: #b4d0fb; +} + +#pulseaudio, +#network, +#cpu, +#memory, +#tray { + color: #a0a0b8; + padding: 0 10px; +} From 24370461ea0c720f8b7cdc53aeb09942a0f80f72 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:00:05 +0200 Subject: [PATCH 019/136] feat(sddm): add fws login theme for kde xfce and hyprland Introduce a new SDDM theme "fws" designed for FWS with support for KDE, XFCE, and Hyprland desktop environments. The theme is built using pure QtQuick and QtQuick.Controls (Basic style) with no additional dependencies beyond what SDDM already requires. It includes: - Main.qml: Custom login screen with clock, date, user/password fields, session selector, and power controls - metadata.desktop: Theme metadata and configuration - theme.conf: Default configuration with customizable accent color and gradient colors The design uses a dark theme with accent colors and supports capslock detection and login error handling. --- .../usr/share/sddm/themes/fws/Main.qml | 249 ++++++++++++++++++ .../share/sddm/themes/fws/metadata.desktop | 17 ++ .../usr/share/sddm/themes/fws/theme.conf | 7 + 3 files changed, 273 insertions(+) create mode 100644 configs/releng/airootfs/usr/share/sddm/themes/fws/Main.qml create mode 100644 configs/releng/airootfs/usr/share/sddm/themes/fws/metadata.desktop create mode 100644 configs/releng/airootfs/usr/share/sddm/themes/fws/theme.conf diff --git a/configs/releng/airootfs/usr/share/sddm/themes/fws/Main.qml b/configs/releng/airootfs/usr/share/sddm/themes/fws/Main.qml new file mode 100644 index 0000000..14cff6c --- /dev/null +++ b/configs/releng/airootfs/usr/share/sddm/themes/fws/Main.qml @@ -0,0 +1,249 @@ +// Thème SDDM « fws » — écran de connexion FWS (KDE / XFCE / Hyprland). +// +// VOLONTAIREMENT en pur QtQuick + QtQuick.Controls (style Basic) : ces +// modules arrivent avec qt6-declarative, dépendance de sddm lui-même → +// AUCUN paquet supplémentaire requis (pas de Breeze/plasma-workspace, pas +// de QtGraphicalEffects — supprimé en Qt6). Le greeter fournit en contexte +// les objets sddm, userModel, sessionModel, keyboard et config (theme.conf, +// surchargé par theme.conf.user écrit par le %post : accent selon le DE). +import QtQuick +import QtQuick.Controls.Basic + +Rectangle { + id: root + width: 1280 + height: 800 + + readonly property color accent: config.accent || "#3daee9" + readonly property color fieldBg: "#2a2a44" + + gradient: Gradient { + GradientStop { position: 0.0; color: config.colorTop || "#1a1a2e" } + GradientStop { position: 1.0; color: config.colorBottom || "#16213e" } + } + + Connections { + target: sddm + function onLoginFailed() { + errorLabel.text = "Échec de la connexion — vérifiez le mot de passe" + passwordField.text = "" + passwordField.forceActiveFocus() + } + function onLoginSucceeded() { + errorLabel.text = "" + } + } + + function doLogin() { + errorLabel.text = "" + sddm.login(userField.text, passwordField.text, sessionBox.currentIndex) + } + + // --- Horloge ----------------------------------------------------------- + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: { + var now = new Date() + clockLabel.text = Qt.formatTime(now, "hh:mm") + dateLabel.text = Qt.formatDate(now, "dddd d MMMM yyyy") + } + Component.onCompleted: triggered() + } + + Column { + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: parent.height * 0.10 + spacing: 4 + + Text { + id: clockLabel + anchors.horizontalCenter: parent.horizontalCenter + color: "#f0f0f5" + font.pixelSize: 84 + font.weight: Font.Light + } + Text { + id: dateLabel + anchors.horizontalCenter: parent.horizontalCenter + color: "#a0a0b8" + font.pixelSize: 20 + font.capitalization: Font.Capitalize + } + } + + // --- Carte de connexion -------------------------------------------------- + Rectangle { + id: card + anchors.centerIn: parent + anchors.verticalCenterOffset: parent.height * 0.08 + width: 400 + height: cardContent.implicitHeight + 56 + radius: 14 + color: "#232338" + border.color: Qt.rgba(1, 1, 1, 0.10) + border.width: 1 + + Column { + id: cardContent + anchors.centerIn: parent + width: parent.width - 56 + spacing: 14 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: config.greeting || "Bienvenue sur FWS" + color: "#f0f0f5" + font.pixelSize: 22 + font.weight: Font.Medium + } + + Rectangle { width: 44; height: 3; radius: 1.5; color: accent + anchors.horizontalCenter: parent.horizontalCenter } + + TextField { + id: userField + width: parent.width + text: userModel.lastUser + placeholderText: "Utilisateur" + placeholderTextColor: "#7d7d95" + color: "#f0f0f5" + font.pixelSize: 15 + leftPadding: 14 + background: Rectangle { + radius: 8 + color: fieldBg + border.color: userField.activeFocus ? accent : "transparent" + border.width: 2 + } + onAccepted: passwordField.forceActiveFocus() + } + + TextField { + id: passwordField + width: parent.width + placeholderText: "Mot de passe" + placeholderTextColor: "#7d7d95" + color: "#f0f0f5" + font.pixelSize: 15 + leftPadding: 14 + echoMode: TextInput.Password + focus: true + background: Rectangle { + radius: 8 + color: fieldBg + border.color: passwordField.activeFocus ? accent : "transparent" + border.width: 2 + } + onAccepted: doLogin() + } + + Text { + visible: keyboard.capsLock + anchors.horizontalCenter: parent.horizontalCenter + text: "⚠ Verrouillage majuscules activé" + color: "#e6c07b" + font.pixelSize: 13 + } + + Text { + id: errorLabel + width: parent.width + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + color: "#e06c75" + font.pixelSize: 13 + } + + Button { + id: loginButton + width: parent.width + height: 44 + onClicked: doLogin() + contentItem: Text { + text: "Se connecter" + color: "#ffffff" + font.pixelSize: 16 + font.weight: Font.Medium + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + background: Rectangle { + radius: 8 + color: loginButton.down ? Qt.darker(accent, 1.25) + : loginButton.hovered ? Qt.lighter(accent, 1.10) + : accent + } + } + + ComboBox { + id: sessionBox + width: parent.width + model: sessionModel + currentIndex: sessionModel.lastIndex + textRole: "name" + font.pixelSize: 13 + contentItem: Text { + leftPadding: 14 + text: sessionBox.displayText + color: "#a0a0b8" + font.pixelSize: 13 + verticalAlignment: Text.AlignVCenter + } + background: Rectangle { + radius: 8 + color: "transparent" + border.color: Qt.rgba(1, 1, 1, 0.15) + border.width: 1 + } + } + } + } + + // --- Boutons d'alimentation ---------------------------------------------- + // PAS de Repeater avec des fonctions dans un modèle JS : en Qt6 elles ne + // survivent pas toujours à la conversion QVariant (clic silencieusement + // inopérant). Deux boutons explicites via un composant inline. + component PowerButton: Button { + id: powerButton + property string label: "" + height: 36 + contentItem: Text { + text: powerButton.label + color: powerButton.hovered ? "#f0f0f5" : "#a0a0b8" + font.pixelSize: 14 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + leftPadding: 14 + rightPadding: 14 + } + background: Rectangle { + radius: 8 + color: powerButton.hovered ? Qt.rgba(1, 1, 1, 0.08) : "transparent" + border.color: Qt.rgba(1, 1, 1, 0.15) + border.width: 1 + } + } + + Row { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 24 + spacing: 10 + + PowerButton { label: "Redémarrer"; onClicked: sddm.reboot() } + PowerButton { label: "Éteindre"; onClicked: sddm.powerOff() } + } + + // Nom de la machine, discret, en bas à gauche. + Text { + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 24 + text: sddm.hostName + color: "#5d5d78" + font.pixelSize: 13 + } +} diff --git a/configs/releng/airootfs/usr/share/sddm/themes/fws/metadata.desktop b/configs/releng/airootfs/usr/share/sddm/themes/fws/metadata.desktop new file mode 100644 index 0000000..0b43f10 --- /dev/null +++ b/configs/releng/airootfs/usr/share/sddm/themes/fws/metadata.desktop @@ -0,0 +1,17 @@ +[SddmGreeterTheme] +Name=FWS +Description=Écran de connexion FWS +Author=FWS +Copyright=FWS +License=GPL-2.0-or-later +Type=sddm-theme +Version=1.0 +Website= +Screenshot= +MainScript=Main.qml +ConfigFile=theme.conf +TranslationsDirectory= +Email= +Theme-Id=fws +Theme-API=2.0 +QtVersion=6 diff --git a/configs/releng/airootfs/usr/share/sddm/themes/fws/theme.conf b/configs/releng/airootfs/usr/share/sddm/themes/fws/theme.conf new file mode 100644 index 0000000..1b647d9 --- /dev/null +++ b/configs/releng/airootfs/usr/share/sddm/themes/fws/theme.conf @@ -0,0 +1,7 @@ +# Thème SDDM « fws » — valeurs par défaut, surchargées par theme.conf.user +# (écrit par le %post du kickstart : accent différent selon le bureau choisi). +[General] +accent=#3daee9 +colorTop=#1a1a2e +colorBottom=#16213e +greeting=Bienvenue sur FWS From be0844b50bb54edd8f0e905a23df20dc1854dd8e Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:00:11 +0200 Subject: [PATCH 020/136] feat(releng): add uefi boot entry with nomodeset graphics option Add a new UEFI boot loader entry for Arch Linux installation medium with the nomodeset kernel parameter. This provides a fallback boot option for systems with GPU or hypervisor drivers that have issues with KMS (kernel mode setting), allowing the system to fall back to VESA/EFI framebuffer graphics mode which is slower but more reliable. --- .../loader/entries/01b-archiso-linux-nomodeset.conf | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf diff --git a/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf b/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf new file mode 100644 index 0000000..3695de0 --- /dev/null +++ b/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf @@ -0,0 +1,8 @@ +# Mode graphique de secours : SANS KMS (nomodeset). Filet de sécurité +# standard pour les GPU/hyperviseurs dont le pilote KMS pose problème : +# X démarre alors sur le framebuffer VESA/EFI (plus lent mais fiable). +title FWS install medium (%ARCH%, UEFI, safe graphics) +sort-key 01b +linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% nomodeset From 7c11f53520717e85fe55d6ba14f0a94ca27427cb Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:12:53 +0200 Subject: [PATCH 021/136] fix(releng): add udev event timeout to archiso linux boot entry Add udev.event_timeout=45 kernel parameter to the UEFI boot entry for the archiso linux image. This timeout helps prevent boot delays caused by udev waiting for device events to complete. --- configs/releng/efiboot/loader/entries/01-archiso-linux.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/releng/efiboot/loader/entries/01-archiso-linux.conf b/configs/releng/efiboot/loader/entries/01-archiso-linux.conf index 1d02178..19928c5 100644 --- a/configs/releng/efiboot/loader/entries/01-archiso-linux.conf +++ b/configs/releng/efiboot/loader/entries/01-archiso-linux.conf @@ -2,4 +2,4 @@ title FWS install medium (%ARCH%, UEFI) sort-key 01 linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% +options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% udev.event_timeout=45 From 218b0707a4935d1a2cf00612c461f62303fec1ed Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:13:04 +0200 Subject: [PATCH 022/136] fix(efiboot): add udev event timeout to nomodeset boot entry Add udev.event_timeout=45 parameter to the safe graphics boot option to prevent timeout issues during device initialization on systems with slower hardware or complex device trees. --- .../efiboot/loader/entries/01b-archiso-linux-nomodeset.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf b/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf index 3695de0..68d8260 100644 --- a/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf +++ b/configs/releng/efiboot/loader/entries/01b-archiso-linux-nomodeset.conf @@ -5,4 +5,4 @@ title FWS install medium (%ARCH%, UEFI, safe graphics) sort-key 01b linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% nomodeset +options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% nomodeset udev.event_timeout=45 From 053998d1c0d7bb1eee78a07ed870186c840c2916 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:13:09 +0200 Subject: [PATCH 023/136] fix(releng): add udev event timeout to speech boot entry Add udev.event_timeout=45 parameter to the accessibility boot entry to prevent timeout issues during device initialization on systems with slower hardware or many devices. --- .../releng/efiboot/loader/entries/02-archiso-speech-linux.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/releng/efiboot/loader/entries/02-archiso-speech-linux.conf b/configs/releng/efiboot/loader/entries/02-archiso-speech-linux.conf index 7bf988d..9ac6e15 100644 --- a/configs/releng/efiboot/loader/entries/02-archiso-speech-linux.conf +++ b/configs/releng/efiboot/loader/entries/02-archiso-speech-linux.conf @@ -2,4 +2,4 @@ title FWS install medium (%ARCH%, UEFI) with speech sort-key 02 linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on +options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on udev.event_timeout=45 From 754b6e88020be37b233c70e9e39dbe2e1c954cdc Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:13:13 +0200 Subject: [PATCH 024/136] fix(syslinux): add udev event timeout to all boot options Add udev.event_timeout=45 parameter to all APPEND kernel boot options in the syslinux configuration to prevent udev event timeout issues during boot on systems with slow device initialization. --- configs/releng/syslinux/archiso_sys-linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configs/releng/syslinux/archiso_sys-linux.cfg b/configs/releng/syslinux/archiso_sys-linux.cfg index 4b238a3..a215031 100644 --- a/configs/releng/syslinux/archiso_sys-linux.cfg +++ b/configs/releng/syslinux/archiso_sys-linux.cfg @@ -6,7 +6,7 @@ ENDTEXT MENU LABEL FWS install medium (%ARCH%, BIOS) LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% +APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% udev.event_timeout=45 # Mode graphique de secours : SANS KMS (nomodeset). Filet de sécurité # standard pour les GPU/hyperviseurs dont le pilote KMS pose problème : @@ -23,7 +23,7 @@ ENDTEXT MENU LABEL FWS install medium (%ARCH%, BIOS, ^safe graphics) LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% nomodeset +APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% nomodeset udev.event_timeout=45 # Accessibility boot option LABEL fwsspeech @@ -34,4 +34,4 @@ ENDTEXT MENU LABEL FWS install medium (%ARCH%, BIOS) with ^speech LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on +APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on udev.event_timeout=45 From d6212deaa95e08306b7cd8b06e7eb4a8f2efa8d2 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:25:45 +0200 Subject: [PATCH 025/136] feat(fws-hypr-keys): add optional style support and adjust wofi dimensions - Import os module to check for style file existence - Add _STYLE constant pointing to wofi-keys.css stylesheet - Increase wofi window dimensions from 780x560 to 820x600 - Conditionally apply custom style if the stylesheet exists - Refactor wofi command construction for better readability --- .../releng/airootfs/usr/local/bin/fws-hypr-keys | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/configs/releng/airootfs/usr/local/bin/fws-hypr-keys b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys index e8c5453..9580d94 100755 --- a/configs/releng/airootfs/usr/local/bin/fws-hypr-keys +++ b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys @@ -12,9 +12,12 @@ # aucune dépendance supplémentaire. import json +import os import subprocess import sys +_STYLE = "/usr/local/share/fws/wofi-keys.css" + # Bits de modmask (masques X11) dans l'ordre d'affichage voulu. _MODS = [ (64, "SUPER"), @@ -84,10 +87,13 @@ def main(): lines = ["(aucun raccourci déclaré)"] # dmenu = liste + filtre incrémental ; la sélection n'a pas d'effet. - subprocess.run( - ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer", - "--width", "780", "--height", "560", "--insensitive", "--cache-file", "/dev/null"], - input="\n".join(lines), text=True, check=False) + cmd = ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer", + "--width", "820", "--height", "600", "--insensitive", + "--cache-file", "/dev/null"] + if os.path.exists(_STYLE): + # Style dédié : monospace (colonnes alignées) + palette FWS. + cmd += ["--style", _STYLE] + subprocess.run(cmd, input="\n".join(lines), text=True, check=False) return 0 From 0ab90857e5a23e840e8f1d7337b8980b08365f89 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:25:57 +0200 Subject: [PATCH 026/136] feat(fws-setup-hardware): add brightnessctl and blueman to base stack Add brightnessctl for brightness control without root via logind, consumed by XF86MonBrightness* keys and waybar backlight module. Add blueman as graphical Bluetooth manager for desktop environments that don't provide their own (KDE and GNOME have built-in managers). Blueman provides system tray integration and pairing assistant. Update comments to clarify the purpose of these new packages. --- .../releng/airootfs/usr/local/bin/fws-setup-hardware | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/configs/releng/airootfs/usr/local/bin/fws-setup-hardware b/configs/releng/airootfs/usr/local/bin/fws-setup-hardware index 07a2fa5..614a91c 100755 --- a/configs/releng/airootfs/usr/local/bin/fws-setup-hardware +++ b/configs/releng/airootfs/usr/local/bin/fws-setup-hardware @@ -37,9 +37,16 @@ case "$(systemd-detect-virt 2>/dev/null)" in microsoft) DRIVERS="$DRIVERS hyperv"; VMSVC="hv_fcopy_daemon hv_kvp_daemon hv_vss_daemon" ;; esac -# ── 3) Stack de base : son / micro / casque, Bluetooth, conteneurs ─────────── +# ── 3) Stack de base : son / micro / casque, Bluetooth, luminosité, conteneurs +# brightnessctl : réglage de luminosité sans root (via logind) — consommé par +# les touches XF86MonBrightness* et la molette du module backlight de waybar. BASE="pipewire pipewire-alsa pipewire-pulse pipewire-jack wireplumber \ - pavucontrol bluez bluez-utils podman" + pavucontrol bluez bluez-utils brightnessctl podman" +# Gestionnaire Bluetooth graphique : KDE et GNOME ont le leur ; blueman pour +# les bureaux qui n'en fournissent pas (tray + assistant d'appairage). +case "$DESK" in + hyprland|xfce) BASE="$BASE blueman" ;; +esac # ── 4) Stack desktop : jeux, Windows-compat, VR (si un bureau est choisi) ──── DESKTOP="" From 8224a24d028eaa6cc5501b65daaf7edc8e815794 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:02 +0200 Subject: [PATCH 027/136] chore(hyprland): add startup services and brightness/blueman window rules - Add mako notification daemon to startup services - Add nm-applet for network tray icon - Add polkit-gnome authentication agent for privilege escalation dialogs - Add brightness control keybinds for XF86MonBrightnessUp/Down - Add float window rule for blueman-manager - Update startup comment to describe all session initialization tasks --- .../airootfs/usr/local/share/fws/hyprland.conf.tmpl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl index 8888d0b..bfac8ed 100644 --- a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -61,8 +61,13 @@ misc { background_color = 0x1a1a2e # bleu nuit FWS (aucun fond requis) } -# Barre d'état au démarrage. +# Démarrage de session : barre d'état, notifications, réseau dans le tray, +# agent d'authentification GUI (indispensable pour les apps qui demandent +# les droits admin : gestionnaire de disques, blueman…). exec-once = waybar +exec-once = mako +exec-once = nm-applet +exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 $mod = SUPER @@ -149,6 +154,10 @@ bindl = , XF86AudioPlay, exec, playerctl play-pause bindl = , XF86AudioNext, exec, playerctl next bindl = , XF86AudioPrev, exec, playerctl previous +# --- Luminosité de l'écran (portables : touches Fn) ------------------------------ +bindel = , XF86MonBrightnessUp, exec, brightnessctl set +5% +bindel = , XF86MonBrightnessDown, exec, brightnessctl set 5%- + # --- Souris : déplacer / redimensionner les fenêtres ----------------------------- bindm = $mod, mouse:272, movewindow bindm = $mod, mouse:273, resizewindow @@ -159,4 +168,5 @@ bindm = $mod, mouse:273, resizewindow windowrule = float on, match:class ^(floating-term)$ windowrule = size 900 550, match:class ^(floating-term)$ windowrule = float on, match:class ^([Pp]avucontrol|org.pulseaudio.pavucontrol)$ +windowrule = float on, match:class ^(.?[Bb]lueman-manager.*)$ windowrule = float on, match:title ^(Picture-in-Picture)$ From 289a70c10c3c81dfbf19dc4e8d904d55e40adc7b Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:09 +0200 Subject: [PATCH 028/136] style(waybar): enhance waybar configuration with improved styling and additional modules Update waybar configuration with: - Adjusted height (34 to 36) and spacing (4 to 2) - Added margins (top: 6, left: 10, right: 10) - Added workspace navigation with scroll (e-1/e+1) - Added backlight, bluetooth, and battery modules - Enhanced clock format with calendar styling - Improved audio controls with pavucontrol integration - Added network bandwidth display - Updated all module icons to use modern emoji/nerd font glyphs - Improved tooltips with more detailed information - Adjusted max window name length from 55 to 45 characters --- .../usr/local/share/fws/waybar-config.json | 80 ++++++++++++++----- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/configs/releng/airootfs/usr/local/share/fws/waybar-config.json b/configs/releng/airootfs/usr/local/share/fws/waybar-config.json index e55339a..a3c9358 100644 --- a/configs/releng/airootfs/usr/local/share/fws/waybar-config.json +++ b/configs/releng/airootfs/usr/local/share/fws/waybar-config.json @@ -1,51 +1,89 @@ { "layer": "top", "position": "top", - "height": 34, - "spacing": 4, + "height": 36, + "spacing": 2, + "margin-top": 6, + "margin-left": 10, + "margin-right": 10, "modules-left": ["hyprland/workspaces", "hyprland/window"], "modules-center": ["clock"], - "modules-right": ["custom/keyhelp", "pulseaudio", "network", "cpu", "memory", "tray"], + "modules-right": ["custom/keyhelp", "backlight", "pulseaudio", "bluetooth", "network", "cpu", "memory", "battery", "tray"], "hyprland/workspaces": { "format": "{id}", - "on-click": "activate" + "on-click": "activate", + "on-scroll-up": "hyprctl dispatch workspace e-1", + "on-scroll-down": "hyprctl dispatch workspace e+1" }, "hyprland/window": { - "max-length": 55, + "max-length": 45, "separate-outputs": true }, "clock": { - "format": "{:%H:%M}", - "format-alt": "{:%A %d %B %Y — %H:%M}", - "tooltip-format": "{calendar}" + "format": "󰥔 {:%H:%M %A %d %B %Y}", + "format-alt": "󰥔 {:%H:%M}", + "tooltip-format": "{calendar}", + "calendar": { + "format": { + "today": "{}" + } + } }, "custom/keyhelp": { - "format": "⌨ Raccourcis", + "format": "󰌌 Raccourcis", "tooltip-format": "Raccourcis clavier (SUPER+K)", "on-click": "fws-hypr-keys" }, + "backlight": { + "format": "{icon} {percent}%", + "format-icons": ["󰃞", "󰃟", "󰃠"], + "on-scroll-up": "brightnessctl set +5%", + "on-scroll-down": "brightnessctl set 5%-", + "tooltip-format": "Luminosité {percent}% (molette pour régler)" + }, "pulseaudio": { - "format": "Vol {volume}%", - "format-muted": "Muet", - "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", - "tooltip": false + "format": "{icon} {volume}%", + "format-muted": "󰝟 muet", + "format-icons": { "default": ["󰕿", "󰖀", "󰕾"] }, + "on-click": "pavucontrol", + "on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", + "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 2%+", + "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%-", + "tooltip-format": "{desc} — clic : mixeur, clic droit : muet" + }, + "bluetooth": { + "format": "󰂯", + "format-disabled": "󰂲", + "format-connected": "󰂱 {num_connections}", + "on-click": "blueman-manager", + "tooltip-format": "{controller_alias}\t{controller_address}", + "tooltip-format-connected": "{device_enumerate}" }, "network": { - "format-wifi": "{essid}", - "format-ethernet": "{ipaddr}", - "format-disconnected": "hors ligne", - "tooltip-format": "{ifname} — {ipaddr}" + "format-wifi": "󰤨 {essid}", + "format-ethernet": "󰈀 {ipaddr}", + "format-disconnected": "󰤭 hors ligne", + "tooltip-format": "{ifname} — {ipaddr}\n⇡ {bandwidthUpBytes} ⇣ {bandwidthDownBytes}" }, "cpu": { - "format": "CPU {usage}%", + "format": " {usage}%", "interval": 3 }, "memory": { - "format": "RAM {percentage}%", - "interval": 3 + "format": " {percentage}%", + "interval": 3, + "tooltip-format": "{used:0.1f} / {total:0.1f} Gio" + }, + "battery": { + "states": { "warning": 25, "critical": 10 }, + "format": "{icon} {capacity}%", + "format-charging": "󰂄 {capacity}%", + "format-icons": ["󰁺", "󰁼", "󰁾", "󰂀", "󰁹"], + "tooltip-format": "{timeTo}" }, "tray": { - "spacing": 8 + "spacing": 8, + "icon-size": 16 } } From 4857a9fda96d2c48c4b4abfe93654d8efcf3da99 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:16 +0200 Subject: [PATCH 029/136] style(waybar): redesign waybar stylesheet with catppuccin mocha theme and pill-style modules Update waybar-style.css to version 2 with the following changes: - Switch to Catppuccin Mocha color scheme with blue accents - Redesign bar as floating rounded container instead of bottom border - Style modules as pill-shaped boxes with individual backgrounds - Add Nerd Font symbols support for better icons - Improve workspace buttons with hover effects and transitions - Add tooltip styling and proper color coding for each module - Update clock styling with dedicated background - Enhance battery, network, and bluetooth status colors - Refine spacing, padding, and border-radius throughout for modern appearance --- .../usr/local/share/fws/waybar-style.css | 102 +++++++++++++----- 1 file changed, 73 insertions(+), 29 deletions(-) diff --git a/configs/releng/airootfs/usr/local/share/fws/waybar-style.css b/configs/releng/airootfs/usr/local/share/fws/waybar-style.css index 6ef916e..88c9617 100644 --- a/configs/releng/airootfs/usr/local/share/fws/waybar-style.css +++ b/configs/releng/airootfs/usr/local/share/fws/waybar-style.css @@ -1,63 +1,107 @@ -/* FWS — style Waybar (assorti au thème SDDM et aux bordures Hyprland). */ +/* FWS — style Waybar v2 (Catppuccin Mocha, nuances de bleu). + Barre flottante arrondie, modules en « pilules », icônes Nerd Font + (paquet ttf-nerd-fonts-symbols, installé avec le bureau Hyprland). */ * { - font-family: "Noto Sans", sans-serif; + font-family: "Noto Sans", "Symbols Nerd Font", sans-serif; font-size: 13px; min-height: 0; } window#waybar { - background: rgba(26, 26, 46, 0.92); /* #1a1a2e */ - color: #f0f0f5; - border-bottom: 2px solid #89b4fa; /* bleu FWS (Catppuccin) */ + background: rgba(30, 30, 46, 0.88); /* base #1e1e2e */ + color: #cdd6f4; /* text */ + border: 1px solid rgba(137, 180, 250, 0.35); + border-radius: 14px; +} + +tooltip { + background: #1e1e2e; + border: 1px solid #89b4fa; + border-radius: 10px; +} +tooltip label { color: #cdd6f4; } + +/* --- Espaces de travail --------------------------------------------------- */ +#workspaces { + background: #313244; /* surface0 */ + margin: 5px 4px; + border-radius: 10px; + padding: 0 4px; } #workspaces button { - color: #a0a0b8; - padding: 0 10px; + color: #a6adc8; /* subtext0 */ + padding: 0 8px; + margin: 3px 2px; border: none; - border-radius: 0; + border-radius: 8px; background: transparent; + transition: all 0.2s ease; } #workspaces button.active { - color: #f0f0f5; - border-bottom: 2px solid #89b4fa; + color: #1e1e2e; + background: #89b4fa; /* bleu */ + font-weight: bold; } #workspaces button:hover { - background: rgba(255, 255, 255, 0.08); + color: #cdd6f4; + background: #45475a; box-shadow: none; } #window { - color: #a0a0b8; - margin-left: 12px; + color: #a6adc8; + margin-left: 10px; + font-style: italic; } +/* --- Horloge (centre) ------------------------------------------------------ */ #clock { - color: #f0f0f5; + color: #cdd6f4; font-weight: bold; + background: #313244; + padding: 0 16px; + margin: 5px 0; + border-radius: 10px; } -#custom-keyhelp { - background: #89b4fa; - color: #1a1a2e; - font-weight: bold; - padding: 0 12px; - margin: 5px 6px; - border-radius: 8px; -} - -#custom-keyhelp:hover { - background: #b4d0fb; -} - +/* --- Modules de droite : pilules ------------------------------------------- */ +#custom-keyhelp, +#backlight, #pulseaudio, +#bluetooth, #network, #cpu, #memory, +#battery, #tray { - color: #a0a0b8; - padding: 0 10px; + background: #313244; + padding: 0 12px; + margin: 5px 3px; + border-radius: 10px; + color: #cdd6f4; } + +#custom-keyhelp { + background: #89b4fa; /* bouton d'appel : bleu plein */ + color: #1e1e2e; + font-weight: bold; +} +#custom-keyhelp:hover { background: #b4d0fb; } + +#backlight { color: #f9e2af; } /* jaune doux */ +#pulseaudio { color: #89b4fa; } +#pulseaudio.muted { color: #6c7086; } +#bluetooth { color: #74c7ec; } /* sapphire */ +#bluetooth.disabled { color: #6c7086; } +#network { color: #94e2d5; } /* teal */ +#network.disconnected { color: #f38ba8; } +#cpu { color: #cba6f7; } /* mauve */ +#memory { color: #eba0ac; } /* maroon */ + +#battery.warning { color: #f9e2af; } +#battery.critical { color: #f38ba8; } +#battery.charging { color: #a6e3a1; } From 038700e22def394baa0cbb2a37c4fce1f9a99dbe Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:23 +0200 Subject: [PATCH 030/136] feat(hyprland): add desktop portal and notification support to hyprland setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing packages for hyprland desktop environment: - mako + libnotify for notifications - polkit-gnome for GUI authentication - network-manager-applet for network management in tray - xdg-desktop-portal-hyprland for screen sharing - gvfs for USB mounting in thunar - ttf-nerd-fonts-symbols for waybar icons Add start-hyprland launcher support for hyprland ≥0.53 to properly prepare systemd session/environment. Add wofi configuration files (config and style.css) for application menu styling. Update skeleton directory setup to install wofi configs for new users and fix chown path formatting. --- .../share/anaconda/interactive-defaults.ks | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index 5ad44c3..6cef60d 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -269,9 +269,15 @@ case "$DESK" in # Hyprland ne garantissent AUCUNE police TTF → greeter SDDM/apps illisibles. # Hyprland : la stack des raccourcis FWS (mêmes touches que la config # i3/sway maison) — thunar (Super+E), hyprlock (Super+L), grim+slurp+ - # wl-clipboard (captures), playerctl (touches multimédia). + # wl-clipboard (captures), playerctl (touches multimédia) — plus la + # plomberie de bureau : mako+libnotify (notifications), polkit-gnome + # (agent d'authentification GUI), network-manager-applet (réseau dans le + # tray), xdg-desktop-portal-hyprland (partage d'écran/portails), gvfs + # (montage USB dans thunar), ttf-nerd-fonts-symbols (icônes waybar). + # Le son (PipeWire+pavucontrol), le Bluetooth (bluez+blueman) et la + # luminosité (brightnessctl) sont installés par fws-setup-hardware. xfce) PKGS="xfce4 xfce4-goodies sddm noto-fonts"; DM="sddm" ;; - hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts thunar hyprlock grim slurp wl-clipboard playerctl"; DM="sddm" ;; + hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts thunar hyprlock grim slurp wl-clipboard playerctl mako libnotify polkit-gnome network-manager-applet xdg-desktop-portal-hyprland gvfs ttf-nerd-fonts-symbols"; DM="sddm" ;; cli|*) PKGS="" ;; esac # Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI). @@ -355,6 +361,11 @@ if systemd-detect-virt --quiet 2>/dev/null; then export WLR_RENDERER_ALLOW_SOFTWARE=1 WLR_NO_HARDWARE_CURSORS=1 export AQ_NO_ATOMIC=1 fi +# Hyprland ≥ 0.53 : start-hyprland est le lanceur officiel (prépare la +# session/env systemd) — sans lui, bandeau « started without start-hyprland ». +if command -v start-hyprland >/dev/null 2>&1; then + exec start-hyprland "$@" +fi exec Hyprland "$@" HYEOF chmod 755 /usr/local/bin/fws-hyprland @@ -392,13 +403,20 @@ if [ "$DESK" = "hyprland" ] && [ -f /usr/local/share/fws/hyprland.conf.tmpl ]; t # (hyprctl binds -j) — les descriptions viennent des bindd de la config. install -Dm644 /usr/local/share/fws/waybar-config.json /etc/skel/.config/waybar/config install -Dm644 /usr/local/share/fws/waybar-style.css /etc/skel/.config/waybar/style.css + # wofi : style du menu d'applications (Super+R) — le panneau « Raccourcis » + # a son propre style (wofi-keys.css), passé en --style par fws-hypr-keys. + install -Dm644 /usr/local/share/fws/wofi-config /etc/skel/.config/wofi/config + install -Dm644 /usr/local/share/fws/wofi-style.css /etc/skel/.config/wofi/style.css while IFS=: read -r _u _x _uid _g _gec _home _sh; do [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ] && [ -d "$_home" ] || continue install -Dm644 /tmp/fws-hyprland.conf "$_home/.config/hypr/hyprland.conf" install -Dm644 /usr/local/share/fws/waybar-config.json "$_home/.config/waybar/config" install -Dm644 /usr/local/share/fws/waybar-style.css "$_home/.config/waybar/style.css" + install -Dm644 /usr/local/share/fws/wofi-config "$_home/.config/wofi/config" + install -Dm644 /usr/local/share/fws/wofi-style.css "$_home/.config/wofi/style.css" chown "$_u": "$_home/.config" 2>/dev/null || true - chown -R "$_u": "$_home/.config/hypr" "$_home/.config/waybar" 2>/dev/null || true + chown -R "$_u": "$_home/.config/hypr" "$_home/.config/waybar" \ + "$_home/.config/wofi" 2>/dev/null || true done < /etc/passwd rm -f /tmp/fws-hyprland.conf fi From e98a8320fb2ef39cda454330b43dc23a9011be04 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:27 +0200 Subject: [PATCH 031/136] feat(wofi): add wofi application menu configuration Add wofi configuration file for FWS with settings for case-insensitive search, image support, custom dimensions, and application prompt. --- configs/releng/airootfs/usr/local/share/fws/wofi-config | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/share/fws/wofi-config diff --git a/configs/releng/airootfs/usr/local/share/fws/wofi-config b/configs/releng/airootfs/usr/local/share/fws/wofi-config new file mode 100644 index 0000000..a5cae46 --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/wofi-config @@ -0,0 +1,7 @@ +# FWS — configuration wofi (menu d'applications). +insensitive=true +allow_images=true +image_size=24 +prompt=Applications +width=560 +height=440 From 53942aece01f55de4048e1ac92d3d19ad435c576 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:31 +0200 Subject: [PATCH 032/136] feat(releng): add wofi keyboard shortcuts panel styling Add CSS stylesheet for the FWS keyboard shortcuts panel (fws-hypr-keys) using monospace font to align key combinations with descriptions. Uses the same color palette as the wofi menu with Catppuccin theme colors. --- .../usr/local/share/fws/wofi-keys.css | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/share/fws/wofi-keys.css diff --git a/configs/releng/airootfs/usr/local/share/fws/wofi-keys.css b/configs/releng/airootfs/usr/local/share/fws/wofi-keys.css new file mode 100644 index 0000000..34a4ce7 --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/wofi-keys.css @@ -0,0 +1,40 @@ +/* FWS — style du panneau « Raccourcis clavier » (fws-hypr-keys). + Même palette que le menu wofi, mais police MONOSPACE : les colonnes + combinaison/description sont alignées par des espaces. */ + +window { + background-color: rgba(30, 30, 46, 0.97); + border: 2px solid #89b4fa; + border-radius: 14px; + font-family: "Noto Sans Mono", monospace; + font-size: 13px; +} + +#input { + background-color: #313244; + color: #cdd6f4; + border: none; + border-radius: 10px; + margin: 12px; + padding: 8px 12px; + font-family: "Noto Sans", sans-serif; +} + +#input image { color: #89b4fa; } + +#inner-box { + margin: 0 8px 8px 8px; +} + +#entry { + padding: 5px 10px; + border-radius: 8px; + color: #cdd6f4; +} + +#entry:selected { + background-color: #313244; + color: #89b4fa; +} + +#text { color: inherit; } From 3a5efffc61040315cdf123a453820e6c49bc9d04 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 00:26:37 +0200 Subject: [PATCH 033/136] feat(wofi-style): add wofi application menu styling with catppuccin mocha theme Add a new CSS stylesheet for wofi (application launcher menu triggered with Super+R) that implements the Catppuccin Mocha blue color scheme. The stylesheet includes styling for the window, input field, menu entries, and selection states with rounded corners and appropriate contrast ratios. --- .../usr/local/share/fws/wofi-style.css | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/share/fws/wofi-style.css diff --git a/configs/releng/airootfs/usr/local/share/fws/wofi-style.css b/configs/releng/airootfs/usr/local/share/fws/wofi-style.css new file mode 100644 index 0000000..f891383 --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/wofi-style.css @@ -0,0 +1,42 @@ +/* FWS — style wofi (menu d'applications Super+R). Catppuccin Mocha, bleu. */ + +window { + background-color: rgba(30, 30, 46, 0.96); /* base #1e1e2e */ + border: 2px solid #89b4fa; + border-radius: 14px; + font-family: "Noto Sans", sans-serif; + font-size: 14px; +} + +#input { + background-color: #313244; /* surface0 */ + color: #cdd6f4; + border: none; + border-radius: 10px; + margin: 12px; + padding: 8px 12px; +} + +#input image { color: #89b4fa; } + +#inner-box { + margin: 0 8px 8px 8px; +} + +#entry { + padding: 8px 10px; + border-radius: 10px; + color: #cdd6f4; +} + +#entry:selected { + background-color: #89b4fa; + color: #1e1e2e; +} + +#entry:selected #text { color: #1e1e2e; } + +#text { + margin-left: 8px; + color: inherit; +} From 6e59e1d4c42cd94111756f300079d4137dc4e811 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:00:53 +0200 Subject: [PATCH 034/136] chore(baseline): update installer preparation message in french MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the estimated time message from '2 à 4 minutes' to 'Encore une à deux minutes' to provide more accurate timing information to users during the FWS installer preparation phase. --- configs/baseline/airootfs/root/.xinitrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/baseline/airootfs/root/.xinitrc b/configs/baseline/airootfs/root/.xinitrc index c05ca75..78f6968 100644 --- a/configs/baseline/airootfs/root/.xinitrc +++ b/configs/baseline/airootfs/root/.xinitrc @@ -48,7 +48,7 @@ if command -v liveinst >/dev/null 2>&1; then if command -v zenity >/dev/null 2>&1; then tail -f /dev/null | zenity --progress --pulsate --no-cancel \ --title="FWS" \ - --text="Préparation de l'installateur FWS…\n\nAnalyse du matériel et des disques en cours.\nCela peut prendre 2 à 4 minutes, c'est normal." \ + --text="Préparation de l'installateur FWS…\n\nAnalyse du matériel et des disques en cours.\nEncore une à deux minutes, c'est normal." \ --width=420 2>/dev/null & _SPLASH_PID=$! fi From cef3b291d13f73bc81dee8c03491165b5f01eefb Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:01:09 +0200 Subject: [PATCH 035/136] chore(packages): add fws-dnd package to baseline x86_64 configuration Add the fws-dnd package (D&D 5e Manager for dice, characters, grimoire, sessions, and combat) to the baseline x86_64 packages list under the FWS section. --- configs/baseline/packages.x86_64 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/baseline/packages.x86_64 b/configs/baseline/packages.x86_64 index 86cd99c..c9a6c78 100644 --- a/configs/baseline/packages.x86_64 +++ b/configs/baseline/packages.x86_64 @@ -103,6 +103,8 @@ open-vm-tools # --- FWS (fws-local) --- winboat-bin +# Gestionnaire D&D 5e (dés, personnages, grimoire, sessions, combat). +fws-dnd # --- Installateur Anaconda (fws-local) --- # 'anaconda' tire automatiquement anaconda-widgets + toutes ses dépendances From 96e5721ad85a305c46fde648d9af96d323c7addd Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:01:12 +0200 Subject: [PATCH 036/136] chore(hyprland): add blueman applet and remove steam keybinding Add blueman-applet to the exec-once commands for bluetooth management. Remove the Steam launcher keybinding (SUPER+KP_Multiply) from the configuration. --- configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl index bfac8ed..3a13719 100644 --- a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -67,6 +67,7 @@ misc { exec-once = waybar exec-once = mako exec-once = nm-applet +exec-once = blueman-applet exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 $mod = SUPER @@ -77,7 +78,6 @@ bindd = $mod SHIFT, Return, Terminal flottant, exec, kitty --class floating-term bindd = $mod, R, Menu des applications, exec, wofi --show drun bindd = $mod, E, Gestionnaire de fichiers, exec, thunar bindd = $mod, B, Ouvrir Firefox, exec, firefox -bindd = $mod, KP_Multiply, Lancer Steam, exec, steam bindd = $mod, K, Afficher les raccourcis clavier, exec, fws-hypr-keys # --- Fenêtres --------------------------------------------------------------- From 43ecf7f54f17eba403ae70419a7c8d7b6421e6b3 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:01:20 +0200 Subject: [PATCH 037/136] chore(releng): add pipewire and bluetooth packages to desktop environments Add PipeWire audio stack (pipewire, pipewire-pulse, wireplumber, pavucontrol) and Bluetooth support (bluez, bluez-utils, blueman) to xfce and hyprland package lists to ensure they are installed alongside the desktop environment. Enable bluetooth.service at installation time for hyprland to have Bluetooth ready at first boot. Update comments to reflect the new guaranteed installation of audio and Bluetooth components as part of the desktop environment transaction. --- .../usr/share/anaconda/interactive-defaults.ks | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index 6cef60d..ea05fc9 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -274,10 +274,13 @@ case "$DESK" in # (agent d'authentification GUI), network-manager-applet (réseau dans le # tray), xdg-desktop-portal-hyprland (partage d'écran/portails), gvfs # (montage USB dans thunar), ttf-nerd-fonts-symbols (icônes waybar). - # Le son (PipeWire+pavucontrol), le Bluetooth (bluez+blueman) et la - # luminosité (brightnessctl) sont installés par fws-setup-hardware. - xfce) PKGS="xfce4 xfce4-goodies sddm noto-fonts"; DM="sddm" ;; - hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts thunar hyprlock grim slurp wl-clipboard playerctl mako libnotify polkit-gnome network-manager-applet xdg-desktop-portal-hyprland gvfs ttf-nerd-fonts-symbols"; DM="sddm" ;; + # Son et Bluetooth GARANTIS avec le bureau : la stack PipeWire + le + # mixeur (pavucontrol) + bluez/blueman partent dans la MÊME transaction + # pacman que le DE — si le bureau s'installe, ses gestionnaires aussi + # (fws-setup-hardware les re-propose ensuite en --needed : sans effet + # s'ils sont déjà là, filet de secours sinon). + xfce) PKGS="xfce4 xfce4-goodies sddm noto-fonts pipewire pipewire-pulse wireplumber pavucontrol"; DM="sddm" ;; + hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts thunar hyprlock grim slurp wl-clipboard playerctl mako libnotify polkit-gnome network-manager-applet xdg-desktop-portal-hyprland gvfs ttf-nerd-fonts-symbols pipewire pipewire-alsa pipewire-pulse wireplumber pavucontrol bluez bluez-utils blueman"; DM="sddm" ;; cli|*) PKGS="" ;; esac # Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI). @@ -373,6 +376,9 @@ HYEOF sed -i 's|^Exec=.*|Exec=/usr/local/bin/fws-hyprland|' \ /usr/share/wayland-sessions/hyprland.desktop fi + # Bluetooth prêt au 1er démarrage (bluez vient d'être installé + # avec le bureau ; fws-setup-hardware le refait — idempotent). + systemctl enable bluetooth.service 2>/dev/null || true fi else echo "[FWS] Bureau '$DESK' non installé (réseau ?) — à refaire après le 1er boot." From 81dfac3762a635eeeaf066451006920e5558122c Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:01:27 +0200 Subject: [PATCH 038/136] chore(releng): add fws-dnd package to x86_64 configuration Add fws-dnd (D&D 5e manager for dice, characters, grimoire, sessions, and combat) to the releng packages.x86_64 configuration. --- configs/releng/packages.x86_64 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/releng/packages.x86_64 b/configs/releng/packages.x86_64 index 6584427..52fe6a7 100644 --- a/configs/releng/packages.x86_64 +++ b/configs/releng/packages.x86_64 @@ -100,6 +100,8 @@ open-vm-tools # --- FWS (fws-local) --- winboat-bin +# Gestionnaire D&D 5e (dés, personnages, grimoire, sessions, combat). +fws-dnd # --- Installateur Anaconda (fws-local) --- # 'anaconda' tire automatiquement anaconda-widgets + toutes ses dépendances From c56db3de044d4648d8b339fe382dfdc73b0386b0 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:02:50 +0200 Subject: [PATCH 039/136] chore(releng): remove fws-dnd package from x86_64 build Remove the fws-dnd package and its associated comment from the x86_64 package list. This package is no longer needed for the release engineering build. --- configs/releng/packages.x86_64 | 2 -- 1 file changed, 2 deletions(-) diff --git a/configs/releng/packages.x86_64 b/configs/releng/packages.x86_64 index 52fe6a7..6584427 100644 --- a/configs/releng/packages.x86_64 +++ b/configs/releng/packages.x86_64 @@ -100,8 +100,6 @@ open-vm-tools # --- FWS (fws-local) --- winboat-bin -# Gestionnaire D&D 5e (dés, personnages, grimoire, sessions, combat). -fws-dnd # --- Installateur Anaconda (fws-local) --- # 'anaconda' tire automatiquement anaconda-widgets + toutes ses dépendances From e20523470f8fa51fc670dad66385b569fa98b1c2 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 01:07:39 +0200 Subject: [PATCH 040/136] feat(anaconda): add customized summary glade ui file Add a customized version of anaconda's summary.glade UI definition file to the baseline airootfs configuration. This file is based on anaconda 45.8 but with the "We won't touch your disks..." label removed from the bottom of the hub, allowing the overlay to mask the original package file without requiring an anaconda rebuild. --- .../usr/share/anaconda/ui/hubs/summary.glade | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade diff --git a/configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade b/configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade new file mode 100644 index 0000000..4996e69 --- /dev/null +++ b/configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade @@ -0,0 +1,133 @@ + + + + + + + + False + INSTALLATION SUMMARY + quitButton + continueButton + + + False + vertical + + + False + + + False + + + + + + + + + + + False + False + 0 + + + + + False + 0 + 12 + 6 + + + False + vertical + 6 + + + True + True + never + + + + + + True + True + 1 + + + + + + + True + True + 1 + + + + + True + False + 6 + 6 + 12 + end + + + _Quit + False + True + True + True + True + True + + + False + True + 0 + + + + + _Begin Installation + False + True + False + True + True + True + + + + False + True + end + 1 + + + + + False + True + 2 + + + + + + + INSTALLATION SUMMARY + + + + From 2aaf1cbfd5309ec586385f5fbd450f1902aab305 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 02:52:18 +0200 Subject: [PATCH 041/136] chore(baseline): add anaconda summary hub glade override in xinitrc Add logic to override the anaconda summary hub glade file at live boot time. The custom glade file is stored in /usr/local/share/fws and copied to /usr/share/anaconda/ui/hubs/summary.glade during X initialization. This workaround is necessary because mkarchiso applies the airootfs overlay before pacstrap, which prevents pacman from installing anaconda over existing files. The file is therefore delivered to /usr/local/share/fws and overlaid at boot when the live overlay is writable. --- configs/baseline/airootfs/root/.xinitrc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/configs/baseline/airootfs/root/.xinitrc b/configs/baseline/airootfs/root/.xinitrc index 78f6968..d9c898d 100644 --- a/configs/baseline/airootfs/root/.xinitrc +++ b/configs/baseline/airootfs/root/.xinitrc @@ -53,6 +53,17 @@ if command -v liveinst >/dev/null 2>&1; then _SPLASH_PID=$! fi + # Hub Résumé SANS le libellé « We won't touch your disks… » : notre glade + # modifié NE PEUT PAS être livré directement à son chemin final — + # mkarchiso pose l'overlay airootfs AVANT pacstrap, et pacman refuse + # alors d'installer anaconda par-dessus (« exists in filesystem »). On le + # livre donc sous /usr/local/share/fws et on ÉCRASE ici, au boot du live + # (l'overlay du live est inscriptible), le fichier du paquet. + if [ -f /usr/local/share/fws/anaconda-summary-hub.glade ]; then + cp -f /usr/local/share/fws/anaconda-summary-hub.glade \ + /usr/share/anaconda/ui/hubs/summary.glade 2>/dev/null || true + fi + LIVEINST_LOG=/tmp/fws-liveinst.log # Bus D-Bus de SESSION : au démarrage (--liveinst), inhibit_screensaver() # de pyanaconda se connecte au bus de session. S'il n'y en a AUCUN (notre From dd71664b9e97c9e62531b311757d2a7fb427662a Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 02:52:24 +0200 Subject: [PATCH 042/136] chore(baseline): remove anaconda summary glade file overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete the customized summary.glade file that was overlaying the anaconda package file. This file was previously used to hide the "We won't touch your disks…" message at the bottom of the installation summary hub. --- .../usr/share/anaconda/ui/hubs/summary.glade | 133 ------------------ 1 file changed, 133 deletions(-) delete mode 100644 configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade diff --git a/configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade b/configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade deleted file mode 100644 index 4996e69..0000000 --- a/configs/baseline/airootfs/usr/share/anaconda/ui/hubs/summary.glade +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - - - False - INSTALLATION SUMMARY - quitButton - continueButton - - - False - vertical - - - False - - - False - - - - - - - - - - - False - False - 0 - - - - - False - 0 - 12 - 6 - - - False - vertical - 6 - - - True - True - never - - - - - - True - True - 1 - - - - - - - True - True - 1 - - - - - True - False - 6 - 6 - 12 - end - - - _Quit - False - True - True - True - True - True - - - False - True - 0 - - - - - _Begin Installation - False - True - False - True - True - True - - - - False - True - end - 1 - - - - - False - True - 2 - - - - - - - INSTALLATION SUMMARY - - - - From a09278b63f3d307687e8b184be97ab801d4bef5b Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 02:52:33 +0200 Subject: [PATCH 043/136] feat(anaconda): add modified anaconda summary hub glade template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add anaconda-summary-hub.glade file, a customized copy of anaconda 45.8's summary.glade without the "We won't touch your disks…" disclaimer label at the bottom of the hub. This file is placed in a neutral path (usr/local/share/fws/) because mkarchiso applies the airootfs before pacstrap. Placing it at the anaconda package path would cause pacman to refuse installation due to filesystem conflicts. The live environment's .xinitrc copies this file to /usr/share/anaconda/ui/hubs/summary.glade during boot. --- .../share/fws/anaconda-summary-hub.glade | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 configs/baseline/airootfs/usr/local/share/fws/anaconda-summary-hub.glade diff --git a/configs/baseline/airootfs/usr/local/share/fws/anaconda-summary-hub.glade b/configs/baseline/airootfs/usr/local/share/fws/anaconda-summary-hub.glade new file mode 100644 index 0000000..db733f0 --- /dev/null +++ b/configs/baseline/airootfs/usr/local/share/fws/anaconda-summary-hub.glade @@ -0,0 +1,136 @@ + + + + + + + + False + INSTALLATION SUMMARY + quitButton + continueButton + + + False + vertical + + + False + + + False + + + + + + + + + + + False + False + 0 + + + + + False + 0 + 12 + 6 + + + False + vertical + 6 + + + True + True + never + + + + + + True + True + 1 + + + + + + + True + True + 1 + + + + + True + False + 6 + 6 + 12 + end + + + _Quit + False + True + True + True + True + True + + + False + True + 0 + + + + + _Begin Installation + False + True + False + True + True + True + + + + False + True + end + 1 + + + + + False + True + 2 + + + + + + + INSTALLATION SUMMARY + + + + From 4d123b6f5db4db578ad1079dc7cd176e92321483 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:05:57 +0200 Subject: [PATCH 044/136] fix(hyprland): only launch blueman-applet if bluetooth adapter exists Prevent blueman-applet from showing connection errors in virtual machines where no Bluetooth adapter is present. The applet now checks for the existence of a Bluetooth adapter in /sys/class/bluetooth before launching. This change adds a conditional check that gracefully skips the applet initialization when no hardware is available, improving user experience in VM environments. --- .../releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl index 3a13719..105ebc2 100644 --- a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -67,7 +67,9 @@ misc { exec-once = waybar exec-once = mako exec-once = nm-applet -exec-once = blueman-applet +# Applet Bluetooth : seulement si un adaptateur existe (en VM il n'y en a +# pas → blueman afficherait une erreur « Connection to BlueZ failed »). +exec-once = sh -c '[ -n "$(ls -A /sys/class/bluetooth 2>/dev/null)" ] && exec blueman-applet' exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 $mod = SUPER From 75113980f09eefd2d4d0f9e93235740d3a47410a Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:06:25 +0200 Subject: [PATCH 045/136] refactor(waybar): add format-no-controller for bluetooth module Configure waybar bluetooth module to use an empty format when no bluetooth controller is detected, improving UI consistency. --- configs/releng/airootfs/usr/local/share/fws/waybar-config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/releng/airootfs/usr/local/share/fws/waybar-config.json b/configs/releng/airootfs/usr/local/share/fws/waybar-config.json index a3c9358..1ab24df 100644 --- a/configs/releng/airootfs/usr/local/share/fws/waybar-config.json +++ b/configs/releng/airootfs/usr/local/share/fws/waybar-config.json @@ -56,6 +56,7 @@ "format": "󰂯", "format-disabled": "󰂲", "format-connected": "󰂱 {num_connections}", + "format-no-controller": "", "on-click": "blueman-manager", "tooltip-format": "{controller_alias}\t{controller_address}", "tooltip-format-connected": "{device_enumerate}" From d0e431329d170a86defbb6cadf58a289659d9dda Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:06:39 +0200 Subject: [PATCH 046/136] refactor(hyprland): disable splash rendering in hyprland configuration Add disable_splash_rendering option to misc section to hide the startup splash message at the bottom of the screen. --- configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl index 105ebc2..676bcb5 100644 --- a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -57,6 +57,7 @@ animations { misc { disable_hyprland_logo = true + disable_splash_rendering = true # pas de « Thanks xxx! » en bas d'écran force_default_wallpaper = 0 background_color = 0x1a1a2e # bleu nuit FWS (aucun fond requis) } From 8e2e74a227c0089511e04a79210ea37e1f3a0f45 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:29:44 +0200 Subject: [PATCH 047/136] feat(fws_desktop): add i3 desktop option and update hyprland description Add i3 window manager as a desktop choice with X11 and SteamVR compatibility note. Update Hyprland description to clarify it uses Wayland and is not compatible with VR. --- .../site-packages/pyanaconda/ui/gui/spokes/fws_desktop.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_desktop.py b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_desktop.py index b92ab7e..607e3cc 100644 --- a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_desktop.py +++ b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_desktop.py @@ -27,7 +27,8 @@ _CHOICES = [ ("cli", _("Command line only (no desktop)")), ("gnome", "GNOME"), ("kde", "KDE Plasma"), - ("hyprland", "Hyprland"), + ("hyprland", "Hyprland — Wayland (non compatible VR)"), + ("i3", "i3 — X11 (compatible VR : SteamVR)"), ("xfce", "XFCE"), ] _DESKTOP_FILE = "/tmp/fws-desktop" From 14d138cae4d70b6af2ff7794dff9917bb2736020 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:29:56 +0200 Subject: [PATCH 048/136] feat(fws_recap): add i3 desktop option and update hyprland description Add i3 desktop environment option with X11 and VR compatibility note. Update hyprland description to clarify Wayland protocol and VR incompatibility. Both descriptions now include information about included applications (Firefox, SDDM). --- .../site-packages/pyanaconda/ui/gui/spokes/fws_recap.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py index 2f97af5..b2ceb8a 100644 --- a/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py +++ b/configs/baseline/airootfs/usr/lib/python3.14/site-packages/pyanaconda/ui/gui/spokes/fws_recap.py @@ -61,7 +61,8 @@ _DESKTOP_LABELS = { "cli": "ligne de commande uniquement (aucun bureau)", "gnome": "GNOME (+ Firefox, GDM)", "kde": "KDE Plasma (+ Firefox, SDDM)", - "hyprland": "Hyprland (+ Firefox, SDDM)", + "hyprland": "Hyprland — Wayland, non compatible VR (+ Firefox, SDDM)", + "i3": "i3 — X11, compatible VR/SteamVR (+ Firefox, SDDM)", "xfce": "XFCE (+ Firefox, SDDM)", } From 9f46b9bb1b3b49eb08d7fc318125da13d7c77e41 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:02 +0200 Subject: [PATCH 049/136] feat(fws_desktop): add i3 window manager option with VR compatibility note Add i3 X11 window manager as a desktop environment option with explicit VR compatibility information. Update Hyprland label to clarify it uses Wayland and is not VR compatible. Adjust position indices for subsequent radio button options. --- .../anaconda/ui/spokes/fws_desktop.glade | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_desktop.glade b/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_desktop.glade index 00e6784..6d5fafb 100644 --- a/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_desktop.glade +++ b/configs/baseline/airootfs/usr/share/anaconda/ui/spokes/fws_desktop.glade @@ -110,7 +110,7 @@ - Hyprland + Hyprland — Wayland (NOT VR compatible) True True False @@ -123,6 +123,21 @@ 4 + + + i3 — X11 (VR compatible: SteamVR, HTC Vive, Valve Index…) + True + True + False + True + radio_cli + + + False + True + 5 + + XFCE @@ -135,7 +150,7 @@ False True - 5 + 6 From 4a598c854a475c308ee9709e3f9949a002c7801b Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:07 +0200 Subject: [PATCH 050/136] chore(baseline): add fws-vr-setup executable permission --- configs/baseline/profiledef.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 8f51919..8a3ec2e 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -30,4 +30,5 @@ file_permissions=( ["/usr/bin/setstatus"]="0:0:755" ["/usr/local/bin/fws-setup-hardware"]="0:0:755" ["/usr/local/bin/fws-hypr-keys"]="0:0:755" + ["/usr/local/bin/fws-vr-setup"]="0:0:755" ) From 95eb6c15e0e172fe2961a4c8a78719428652248b Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:12 +0200 Subject: [PATCH 051/136] fix(fws-setup-hardware): add blueman bluetooth manager support for i3 desktop Include blueman in the base packages for i3 desktop environment, alongside hyprland and xfce, to provide graphical bluetooth management and pairing assistant for i3 users. --- configs/releng/airootfs/usr/local/bin/fws-setup-hardware | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/releng/airootfs/usr/local/bin/fws-setup-hardware b/configs/releng/airootfs/usr/local/bin/fws-setup-hardware index 614a91c..0f49db7 100755 --- a/configs/releng/airootfs/usr/local/bin/fws-setup-hardware +++ b/configs/releng/airootfs/usr/local/bin/fws-setup-hardware @@ -45,7 +45,7 @@ BASE="pipewire pipewire-alsa pipewire-pulse pipewire-jack wireplumber \ # Gestionnaire Bluetooth graphique : KDE et GNOME ont le leur ; blueman pour # les bureaux qui n'en fournissent pas (tray + assistant d'appairage). case "$DESK" in - hyprland|xfce) BASE="$BASE blueman" ;; + hyprland|xfce|i3) BASE="$BASE blueman" ;; esac # ── 4) Stack desktop : jeux, Windows-compat, VR (si un bureau est choisi) ──── From 5f108c607b78143f7fd3e0bb34390f2600965f4c Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:18 +0200 Subject: [PATCH 052/136] feat(releng): add i3 window manager desktop environment configuration Add i3 window manager as a selectable desktop environment option in the anaconda kickstart configuration. Includes: - i3-wm with essential packages (i3status, i3lock, rofi, kitty, etc.) - X11 server requirement for VR compatibility (SteamVR incompatible with Wayland) - Bluetooth service enablement for i3 sessions - Icon cache update for VR launcher visibility in rofi - i3 configuration template installation for skeleton and existing users - Keyboard layout handling via X11 xorg.conf.d (no keyboard injection needed) This enables users to install a lightweight X11-based desktop environment with VR support capabilities. --- .../share/anaconda/interactive-defaults.ks | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks index ea05fc9..3f0fa8a 100644 --- a/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks +++ b/configs/releng/airootfs/usr/share/anaconda/interactive-defaults.ks @@ -281,6 +281,11 @@ case "$DESK" in # s'ils sont déjà là, filet de secours sinon). xfce) PKGS="xfce4 xfce4-goodies sddm noto-fonts pipewire pipewire-pulse wireplumber pavucontrol"; DM="sddm" ;; hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts thunar hyprlock grim slurp wl-clipboard playerctl mako libnotify polkit-gnome network-manager-applet xdg-desktop-portal-hyprland gvfs ttf-nerd-fonts-symbols pipewire pipewire-alsa pipewire-pulse wireplumber pavucontrol bluez bluez-utils blueman"; DM="sddm" ;; + # i3 : session X11 → COMPATIBLE VR (SteamVR ne marche pas sous Wayland). + # xorg-server est requis (SDDM ne le tire pas) ; maim+xclip = captures X11, + # dunst = notifications X11 (équivalent de mako), i3lock = verrouillage. + # fws-vr-setup (Super+Shift+V ou menu) installe les drivers du casque. + i3) PKGS="i3-wm i3status i3lock xorg-server rofi kitty thunar sddm noto-fonts ttf-nerd-fonts-symbols maim xclip dunst libnotify polkit-gnome network-manager-applet gvfs playerctl brightnessctl pipewire pipewire-alsa pipewire-pulse wireplumber pavucontrol bluez bluez-utils blueman"; DM="sddm" ;; cli|*) PKGS="" ;; esac # Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI). @@ -380,6 +385,11 @@ HYEOF # avec le bureau ; fws-setup-hardware le refait — idempotent). systemctl enable bluetooth.service 2>/dev/null || true fi + if [ "$DESK" = "i3" ]; then + systemctl enable bluetooth.service 2>/dev/null || true + # Icône du lanceur « Installation VR » (casque) visible dans rofi. + gtk-update-icon-cache -f /usr/share/icons/hicolor 2>/dev/null || true + fi else echo "[FWS] Bureau '$DESK' non installé (réseau ?) — à refaire après le 1er boot." fi @@ -427,6 +437,19 @@ if [ "$DESK" = "hyprland" ] && [ -f /usr/local/share/fws/hyprland.conf.tmpl ]; t rm -f /tmp/fws-hyprland.conf fi +# --- Config i3 (si choisi) : raccourcis FWS + barre + autostart ------------- +# Pas d'injection clavier ici : les sessions X11 lisent la disposition dans +# /etc/X11/xorg.conf.d/00-keyboard.conf, écrite à l'étape 3bis. +if [ "$DESK" = "i3" ] && [ -f /usr/local/share/fws/i3-config ]; then + install -Dm644 /usr/local/share/fws/i3-config /etc/skel/.config/i3/config + while IFS=: read -r _u _x _uid _g _gec _home _sh; do + [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ] && [ -d "$_home" ] || continue + install -Dm644 /usr/local/share/fws/i3-config "$_home/.config/i3/config" + chown "$_u": "$_home/.config" 2>/dev/null || true + chown -R "$_u": "$_home/.config/i3" 2>/dev/null || true + done < /etc/passwd +fi + # --- 4bis) Sudo : l'utilisateur créé doit pouvoir administrer ----------------- # Arch laisse « %wheel » COMMENTÉ dans sudoers → même un membre de wheel ne peut # pas sudo. On active le groupe wheel (drop-in) ET on y ajoute tous les From 3c12d9514c1cfe64b051e483d0008ab0abf307cd Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:23 +0200 Subject: [PATCH 053/136] chore(releng): add fws-vr-setup executable to file permissions Register the new fws-vr-setup script with executable permissions (755) in the releng profile configuration. --- configs/releng/profiledef.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/releng/profiledef.sh b/configs/releng/profiledef.sh index 9aae7dd..33b838b 100644 --- a/configs/releng/profiledef.sh +++ b/configs/releng/profiledef.sh @@ -26,4 +26,5 @@ file_permissions=( ["/usr/bin/setstatus"]="0:0:755" ["/usr/local/bin/fws-setup-hardware"]="0:0:755" ["/usr/local/bin/fws-hypr-keys"]="0:0:755" + ["/usr/local/bin/fws-vr-setup"]="0:0:755" ) From 06121343e78ec867c1bc1ac39352b3ce9edab863 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:28 +0200 Subject: [PATCH 054/136] feat(releng): add fws-vr-setup script for VR driver installation Add interactive shell script for installing VR drivers and runtimes based on headset type. Supports HTC Vive/Valve Index (native SteamVR), Meta Quest/Pico (ALVR streaming), and Monado (OpenXR runtime). Script automatically detects GPU and installs appropriate 32-bit Vulkan libraries required by SteamVR. Includes multilib configuration and user guidance for each VR setup path. --- .../airootfs/usr/local/bin/fws-vr-setup | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 configs/releng/airootfs/usr/local/bin/fws-vr-setup diff --git a/configs/releng/airootfs/usr/local/bin/fws-vr-setup b/configs/releng/airootfs/usr/local/bin/fws-vr-setup new file mode 100755 index 0000000..65e4fb1 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-vr-setup @@ -0,0 +1,95 @@ +#!/bin/bash +# ============================================================================ +# FWS — installation des drivers/runtimes VR selon le casque. +# +# À lancer depuis un terminal (Super+Shift+V sous i3, ou l'entrée +# « Installation VR (FWS) » du menu d'applications). Réservé aux sessions +# X11 (i3) : SteamVR ne fonctionne PAS sous Wayland/Hyprland. +# +# Réalité du support Linux (résumé honnête) : +# • HTC Vive / Vive Pro / Valve Index (stations lighthouse) → NATIF via +# SteamVR. C'est le chemin le plus fiable. +# • Meta/Oculus Quest 1-3, Pico → PAS de support officiel ; streaming +# Wi-Fi via ALVR (+ SteamVR). ALVR n'est pas dans les dépôts Arch : +# le script installe la base et donne la marche à suivre. +# • Oculus Rift CV1/S (filaire) → pas de support utilisable. +# • Monado : runtime OpenXR libre (déjà proposé par fws-setup-hardware), +# utile pour les applis OpenXR natives sans SteamVR. +# ============================================================================ +set -u +say() { printf '\n\033[1;34m==> %s\033[0m\n' "$*"; } +warn() { printf '\033[1;33m ⚠ %s\033[0m\n' "$*"; } + +if [ "$(id -u)" -ne 0 ]; then + exec sudo "$0" "$@" +fi + +# lib32 Vulkan selon le GPU (indispensable à SteamVR, qui est 32/64 bits). +GPU="$(lspci 2>/dev/null | grep -iE 'VGA compatible controller|3D controller|Display controller')" +LIB32="lib32-mesa" +case "$GPU" in + *NVIDIA*|*GeForce*) LIB32="$LIB32 lib32-nvidia-utils" ;; + *AMD*|*ATI*|*Radeon*) LIB32="$LIB32 lib32-vulkan-radeon" ;; + *Intel*) LIB32="$LIB32 lib32-vulkan-intel" ;; +esac + +install_pkgs() { + # multilib requis pour Steam/lib32. + grep -qE '^\[multilib\]' /etc/pacman.conf \ + || printf '\n[multilib]\nInclude = /etc/pacman.d/mirrorlist\n' >> /etc/pacman.conf + pacman -Sy --noconfirm || { warn "synchro pacman échouée (réseau ?)"; return 1; } + local valid="" p + for p in "$@"; do + pacman -Si "$p" >/dev/null 2>&1 && valid="$valid $p" || warn "paquet inconnu ignoré : $p" + done + # shellcheck disable=SC2086 + pacman -S --noconfirm --needed $valid +} + +steamvr_base() { + say "Installation de la base SteamVR (Steam + Vulkan 32 bits : $LIB32)…" + # shellcheck disable=SC2086 + install_pkgs steam $LIB32 || return 1 + say "Base installée. Étapes suivantes :" + echo " 1. Lance Steam, connecte-toi, puis installe « SteamVR » (Bibliothèque → Outils)." + echo " 2. Branche le casque et les stations, puis lance SteamVR." + echo " 3. Premier lancement : SteamVR peut demander à ajuster les règles udev — accepte." +} + +case "${1:-menu}" in + menu) + cat <<'MENU' + + ╔══════════════════════════════════════════════════════════╗ + ║ FWS — Installation VR (session X11 requise) ║ + ╠══════════════════════════════════════════════════════════╣ + ║ 1) HTC Vive / Vive Pro / Valve Index (natif, SteamVR) ║ + ║ 2) Meta Quest / Pico (streaming ALVR) ║ + ║ 3) Monado (runtime OpenXR libre, sans SteamVR) ║ + ║ q) Quitter ║ + ╚══════════════════════════════════════════════════════════╝ +MENU + read -rp " Choix : " choice + exec "$0" "$choice" + ;; + 1|vive|index) + steamvr_base || exit 1 + ;; + 2|quest|pico) + steamvr_base || exit 1 + say "Streaming Quest/Pico : il faut AUSSI ALVR (pas dans les dépôts Arch) :" + echo " 1. Télécharge le .tar.gz « ALVR Launcher » : https://github.com/alvr-org/ALVR/releases" + echo " 2. Sur le casque, installe le client ALVR (App Lab / SideQuest)." + echo " 3. Lance ALVR sur le PC (même Wi-Fi 5 GHz que le casque) — il pilote SteamVR." + ;; + 3|monado) + say "Installation de Monado (OpenXR) + outils…" + install_pkgs monado || exit 1 + say "Monado installé. Les applis OpenXR le trouvent via /usr/share/openxr/." + ;; + q|Q) exit 0 ;; + *) warn "choix inconnu : ${1}"; exec "$0" menu ;; +esac + +echo +read -rp "Terminé — appuie sur Entrée pour fermer. " _ From 2a3824a9917ae37ea380502d3dfd20af198aac9a Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:38 +0200 Subject: [PATCH 055/136] feat(i3): add default i3 window manager configuration Add FWS default i3 configuration file with X11 session support. Includes: - Color scheme based on Catppuccin Mocha palette - Keyboard bindings for common applications and window management - VR headset driver setup integration (Super+Shift+V) - Multi-monitor and workspace navigation support - Screenshot and multimedia control bindings - Status bar configuration with i3status - Autostart for dunst, nm-applet, polkit-gnome, and blueman --- .../airootfs/usr/local/share/fws/i3-config | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/share/fws/i3-config diff --git a/configs/releng/airootfs/usr/local/share/fws/i3-config b/configs/releng/airootfs/usr/local/share/fws/i3-config new file mode 100644 index 0000000..2742931 --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/i3-config @@ -0,0 +1,156 @@ +# FWS — configuration i3 par défaut (session X11, COMPATIBLE VR). +# SteamVR fonctionne en X11 : c'est le bureau à choisir pour un casque VR +# (HTC Vive, Valve Index…). Lance « fws-vr-setup » (Super+Shift+V, ou menu) +# pour installer les drivers/runtimes selon ton casque. +# Le clavier X11 est configuré système via /etc/X11/xorg.conf.d/00-keyboard.conf +# (écrit par l'installateur selon ton choix Anaconda) : rien à régler ici. + +set $mod Mod4 +set $term kitty +set $filemanager thunar +set $menu rofi -show drun -show-icons +set $browser firefox + +# Couleurs — nuances de bleu (Catppuccin Mocha, comme SDDM/waybar FWS) +set $base #1e1e2e +set $surface0 #313244 +set $text #cdd6f4 +set $blue #89b4fa +set $sapphire #74c7ec +set $red #f38ba8 + +# classe bordure fond texte indicateur child_border +client.focused $blue $blue $base $sapphire $blue +client.focused_inactive $surface0 $surface0 $text $surface0 $surface0 +client.unfocused $surface0 $surface0 $text $surface0 $surface0 +client.urgent $red $red $base $red $red +client.background $base + +font pango:Noto Sans 10 +default_border pixel 2 +gaps inner 4 +gaps outer 4 + +################## +## APPLICATIONS ## +################## +bindsym $mod+Return exec $term +bindsym $mod+Shift+Return exec kitty --class floating-term +bindsym $mod+r exec $menu +bindsym $mod+e exec $filemanager +bindsym $mod+b exec $browser +# VR : installation des drivers/runtimes casque (HTC Vive, Index, Quest…) +bindsym $mod+Shift+v exec kitty -e fws-vr-setup + +############## +## FENETRES ## +############## +bindsym $mod+q kill +bindsym $mod+v floating toggle +bindsym $mod+f fullscreen toggle +bindsym $mod+j split toggle +bindsym $mod+l exec i3lock -c 1e1e2e +# Quitter i3 → retour à SDDM +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'Quitter i3 et revenir à SDDM ?' -B 'Oui, quitter' 'i3-msg exit'" +bindsym $mod+Shift+c reload + +# Focus (flèches) +bindsym $mod+Left focus left +bindsym $mod+Right focus right +bindsym $mod+Up focus up +bindsym $mod+Down focus down +# Déplacer la fenêtre +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Right move right +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Down move down +# Redimensionner (Ctrl + flèches) +bindsym $mod+Ctrl+Left resize shrink width 30 px +bindsym $mod+Ctrl+Right resize grow width 30 px +bindsym $mod+Ctrl+Up resize shrink height 30 px +bindsym $mod+Ctrl+Down resize grow height 30 px + +################ +## WORKSPACES ## +################ +bindsym $mod+1 workspace number 1 +bindsym $mod+2 workspace number 2 +bindsym $mod+3 workspace number 3 +bindsym $mod+4 workspace number 4 +bindsym $mod+5 workspace number 5 +bindsym $mod+6 workspace number 6 +bindsym $mod+7 workspace number 7 +bindsym $mod+8 workspace number 8 +bindsym $mod+9 workspace number 9 +bindsym $mod+0 workspace number 10 +bindsym $mod+Shift+1 move container to workspace number 1 +bindsym $mod+Shift+2 move container to workspace number 2 +bindsym $mod+Shift+3 move container to workspace number 3 +bindsym $mod+Shift+4 move container to workspace number 4 +bindsym $mod+Shift+5 move container to workspace number 5 +bindsym $mod+Shift+6 move container to workspace number 6 +bindsym $mod+Shift+7 move container to workspace number 7 +bindsym $mod+Shift+8 move container to workspace number 8 +bindsym $mod+Shift+9 move container to workspace number 9 +bindsym $mod+Shift+0 move container to workspace number 10 +# Multi-écrans +bindsym $mod+Ctrl+1 move container to output left +bindsym $mod+Ctrl+2 move container to output right +# Molette = changer de workspace +bindsym $mod+button4 workspace prev +bindsym $mod+button5 workspace next +# Scratchpad +bindsym $mod+s scratchpad show +bindsym $mod+Shift+s move scratchpad + +############## +## CAPTURES ## +############## +bindsym Print exec --no-startup-id "maim | xclip -selection clipboard -t image/png" +bindsym $mod+Print exec --no-startup-id "maim -s | xclip -selection clipboard -t image/png" +bindsym $mod+Shift+Print exec --no-startup-id "mkdir -p ~/Images && maim -s ~/Images/capture_$(date +%Y-%m-%d_%H-%M-%S).png" + +################ +## MULTIMEDIA ## +################ +bindsym XF86AudioRaiseVolume exec --no-startup-id wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ +bindsym XF86AudioLowerVolume exec --no-startup-id wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindsym XF86AudioMute exec --no-startup-id wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindsym XF86AudioPlay exec --no-startup-id playerctl play-pause +bindsym XF86AudioNext exec --no-startup-id playerctl next +bindsym XF86AudioPrev exec --no-startup-id playerctl previous +bindsym XF86MonBrightnessUp exec --no-startup-id brightnessctl set +5% +bindsym XF86MonBrightnessDown exec --no-startup-id brightnessctl set 5%- + +##################### +## REGLES FENETRES ## +##################### +for_window [class="floating-term"] floating enable, resize set 900 550 +for_window [class="(?i)pavucontrol"] floating enable, resize set 700 500 +for_window [class="(?i)blueman-manager"] floating enable +for_window [title="Picture-in-Picture"] floating enable + +########### +## BARRE ## +########### +bar { + status_command i3status + position top + colors { + background $base + statusline $text + separator $surface0 + # classe bordure fond texte + focused_workspace $blue $blue $base + inactive_workspace $surface0 $base $text + urgent_workspace $red $red $base + } +} + +############### +## AUTOSTART ## +############### +exec --no-startup-id dunst +exec --no-startup-id nm-applet +exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 +exec --no-startup-id sh -c '[ -n "$(ls -A /sys/class/bluetooth 2>/dev/null)" ] && exec blueman-applet' From b408c84a8c718bcad6e585aaefe1b1204220a7f8 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:41 +0200 Subject: [PATCH 056/136] feat(releng): add fws-vr-setup desktop application entry Add desktop application entry for VR setup tool that allows users to install drivers and runtimes for VR headsets including HTC Vive, Valve Index, and Meta Quest devices. The application launches fws-vr-setup command in a kitty terminal. --- .../usr/share/applications/fws-vr-setup.desktop | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 configs/releng/airootfs/usr/share/applications/fws-vr-setup.desktop diff --git a/configs/releng/airootfs/usr/share/applications/fws-vr-setup.desktop b/configs/releng/airootfs/usr/share/applications/fws-vr-setup.desktop new file mode 100644 index 0000000..64016cb --- /dev/null +++ b/configs/releng/airootfs/usr/share/applications/fws-vr-setup.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Name=Installation VR (FWS) +Name[en]=VR Setup (FWS) +Comment=Installer les drivers/runtimes pour casque VR (HTC Vive, Index, Quest…) +Exec=kitty -e fws-vr-setup +Icon=fws-vr +Terminal=false +Categories=System;Settings; +Keywords=VR;SteamVR;Vive;Index;Quest;casque; From a63021cde7a4dcacd610e965ef2fbc6c55fa2852 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:30:46 +0200 Subject: [PATCH 057/136] feat(icons): add fws-vr vr headset icon Add scalable SVR icon for the fws-vr-setup launcher using FWS/Catppuccin color palette. The icon depicts a VR headset with straps, lenses, and nose notch in blue and dark theme colors. --- .../share/icons/hicolor/scalable/apps/fws-vr.svg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 configs/releng/airootfs/usr/share/icons/hicolor/scalable/apps/fws-vr.svg diff --git a/configs/releng/airootfs/usr/share/icons/hicolor/scalable/apps/fws-vr.svg b/configs/releng/airootfs/usr/share/icons/hicolor/scalable/apps/fws-vr.svg new file mode 100644 index 0000000..c6e4ba1 --- /dev/null +++ b/configs/releng/airootfs/usr/share/icons/hicolor/scalable/apps/fws-vr.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + From 2c5f08330a2921e79ef4c7cfc215453523044ee5 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 03:59:09 +0200 Subject: [PATCH 058/136] refactor(fws-keys): make keyboard shortcuts tool universal for hyprland and i3 Rename fws-hypr-keys to fws-keys and extend it to support both Hyprland and i3 desktop environments. The tool now detects the session type and uses appropriate methods: - Hyprland: queries hyprctl binds for real loaded bindings (wofi dmenu) - i3: parses ~/.config/i3/config with variable resolution (rofi dmenu) Update all references in configs and templates. Add VM detection warning in fws-vr-setup to prevent VR attempts in virtual machines where GPU/USB access is unavailable. Add ttf-liberation font dependency for Steam UI stability on minimal installations and improve error guidance for Steam crashes. --- configs/baseline/profiledef.sh | 2 +- .../airootfs/usr/local/bin/fws-hypr-keys | 101 ------------ .../releng/airootfs/usr/local/bin/fws-keys | 129 +++++++++++++++ .../airootfs/usr/local/bin/fws-vr-setup | 22 ++- .../usr/local/share/fws/hyprland.conf.tmpl | 4 +- .../airootfs/usr/local/share/fws/i3-config | 21 +-- .../airootfs/usr/local/share/fws/picom.conf | 19 +++ .../usr/local/share/fws/polybar-config.ini | 156 ++++++++++++++++++ .../usr/local/share/fws/waybar-config.json | 2 +- .../usr/local/share/fws/wofi-keys.css | 2 +- .../share/anaconda/interactive-defaults.ks | 15 +- configs/releng/profiledef.sh | 2 +- 12 files changed, 350 insertions(+), 125 deletions(-) delete mode 100755 configs/releng/airootfs/usr/local/bin/fws-hypr-keys create mode 100755 configs/releng/airootfs/usr/local/bin/fws-keys create mode 100644 configs/releng/airootfs/usr/local/share/fws/picom.conf create mode 100644 configs/releng/airootfs/usr/local/share/fws/polybar-config.ini diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 8a3ec2e..2245265 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -29,6 +29,6 @@ file_permissions=( ["/usr/bin/load_policy"]="0:0:755" ["/usr/bin/setstatus"]="0:0:755" ["/usr/local/bin/fws-setup-hardware"]="0:0:755" - ["/usr/local/bin/fws-hypr-keys"]="0:0:755" + ["/usr/local/bin/fws-keys"]="0:0:755" ["/usr/local/bin/fws-vr-setup"]="0:0:755" ) diff --git a/configs/releng/airootfs/usr/local/bin/fws-hypr-keys b/configs/releng/airootfs/usr/local/bin/fws-hypr-keys deleted file mode 100755 index 9580d94..0000000 --- a/configs/releng/airootfs/usr/local/bin/fws-hypr-keys +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python3 -# FWS — affiche les raccourcis clavier RÉELS de Hyprland. -# -# Source de vérité : « hyprctl binds -j » = les binds effectivement CHARGÉS -# par le compositeur (ceux de ~/.config/hypr/hyprland.conf, y compris ceux -# ajoutés par l'utilisateur après l'installation). Les descriptions viennent -# des « bindd » de la config ; un bind sans description affiche son action -# brute (dispatcher + argument). Affichage : wofi en mode dmenu (recherche -# incrémentale intégrée) — déclenché par le bouton ⌨ de la waybar ou SUPER+K. -# -# python3 et wofi sont déjà sur le système (image FWS + paquets Hyprland) : -# aucune dépendance supplémentaire. - -import json -import os -import subprocess -import sys - -_STYLE = "/usr/local/share/fws/wofi-keys.css" - -# Bits de modmask (masques X11) dans l'ordre d'affichage voulu. -_MODS = [ - (64, "SUPER"), - (4, "CTRL"), - (8, "ALT"), - (1, "SHIFT"), -] - -# Libellés humains pour les « touches » spéciales. -_KEY_LABELS = { - "mouse:272": "clic gauche", - "mouse:273": "clic droit", - "mouse:274": "clic molette", - "mouse_down": "molette bas", - "mouse_up": "molette haut", - "return": "Entrée", - "space": "Espace", - "escape": "Échap", - "tab": "Tab", - "left": "←", - "right": "→", - "up": "↑", - "down": "↓", -} - - -def _mods(mask): - return [name for bit, name in _MODS if mask & bit] - - -def _combo(bind): - parts = _mods(bind.get("modmask", 0)) - key = bind.get("key") or "" - if not key and bind.get("keycode"): - key = f"code {bind['keycode']}" - parts.append(_KEY_LABELS.get(key.lower(), key)) - return " + ".join(p for p in parts if p) - - -def _action(bind): - desc = (bind.get("description") or "").strip() - if desc: - return desc - arg = (bind.get("arg") or "").strip() - return f"{bind.get('dispatcher', '?')} {arg}".strip() - - -def main(): - try: - raw = subprocess.check_output(["hyprctl", "binds", "-j"], text=True) - binds = json.loads(raw) - except (OSError, subprocess.CalledProcessError, ValueError) as exc: - subprocess.run(["notify-send", "Raccourcis FWS", - f"hyprctl binds a échoué : {exc}"], check=False) - return 1 - - lines = [] - seen = set() - for bind in binds: - combo = _combo(bind) - if not combo or combo in seen: # binde répétés (resize) : une ligne - continue - seen.add(combo) - lines.append(f"{combo:<24} {_action(bind)}") - - if not lines: - lines = ["(aucun raccourci déclaré)"] - - # dmenu = liste + filtre incrémental ; la sélection n'a pas d'effet. - cmd = ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer", - "--width", "820", "--height", "600", "--insensitive", - "--cache-file", "/dev/null"] - if os.path.exists(_STYLE): - # Style dédié : monospace (colonnes alignées) + palette FWS. - cmd += ["--style", _STYLE] - subprocess.run(cmd, input="\n".join(lines), text=True, check=False) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/configs/releng/airootfs/usr/local/bin/fws-keys b/configs/releng/airootfs/usr/local/bin/fws-keys new file mode 100755 index 0000000..0e3dc5e --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-keys @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# FWS — affiche les raccourcis clavier RÉELS de la session (bouton ⌨ de la +# barre ou Super+K). Universel : +# • Hyprland : « hyprctl binds -j » = les binds effectivement chargés +# (descriptions des bindd) — affichage wofi (Wayland). +# • i3 : parse ~/.config/i3/config (bindsym, variables résolues) +# — affichage rofi (X11). +# Aucune dépendance hors python3 + wofi/rofi (déjà installés avec le bureau). + +import json +import os +import re +import subprocess +import sys + +_WOFI_STYLE = "/usr/local/share/fws/wofi-keys.css" + +# Bits de modmask Hyprland (masques X11) dans l'ordre d'affichage voulu. +_MODS = [(64, "SUPER"), (4, "CTRL"), (8, "ALT"), (1, "SHIFT")] + +_KEY_LABELS = { + "mouse:272": "clic gauche", + "mouse:273": "clic droit", + "mouse:274": "clic molette", + "mouse_down": "molette bas", + "mouse_up": "molette haut", + "button4": "molette haut", + "button5": "molette bas", + "return": "Entrée", + "space": "Espace", + "escape": "Échap", + "tab": "Tab", + "left": "←", + "right": "→", + "up": "↑", + "down": "↓", + "print": "Impr écran", +} + + +def _label(key): + return _KEY_LABELS.get(key.lower(), key) + + +# --- Hyprland : binds réels via hyprctl ------------------------------------ +def hyprland_lines(): + raw = subprocess.check_output(["hyprctl", "binds", "-j"], text=True) + lines, seen = [], set() + for bind in json.loads(raw): + parts = [name for bit, name in _MODS if bind.get("modmask", 0) & bit] + key = bind.get("key") or (f"code {bind['keycode']}" if bind.get("keycode") else "") + parts.append(_label(key)) + combo = " + ".join(p for p in parts if p) + if not combo or combo in seen: + continue + seen.add(combo) + desc = (bind.get("description") or "").strip() \ + or f"{bind.get('dispatcher', '?')} {(bind.get('arg') or '').strip()}".strip() + lines.append(f"{combo:<24} {desc}") + return lines + + +# --- i3 : parse de la config (variables résolues) ---------------------------- +def i3_lines(): + path = os.path.expanduser("~/.config/i3/config") + variables = {} + lines, seen = [], set() + with open(path, encoding="utf-8", errors="replace") as fh: + content = fh.readlines() + for line in content: + m = re.match(r"\s*set\s+(\$\S+)\s+(.+)$", line) + if m: + variables[m.group(1)] = m.group(2).strip() + def resolve(text): + # $var les plus longs d'abord ($filemanager avant $file…). + for var in sorted(variables, key=len, reverse=True): + text = text.replace(var, variables[var]) + return text + for line in content: + m = re.match(r"\s*bindsym\s+(?:--\S+\s+)*(\S+)\s+(.+)$", line) + if not m: + continue + combo_raw, action = m.groups() + combo_raw = resolve(combo_raw).replace("Mod4", "Super").replace("Mod1", "Alt") + combo = " + ".join(_label(k) for k in combo_raw.split("+")) + if combo in seen: + continue + seen.add(combo) + action = resolve(action) + action = re.sub(r"^exec\s+(--no-startup-id\s+)?", "", action).strip().strip('"') + lines.append(f"{combo:<24} {action}") + return lines + + +def show(lines): + if not lines: + lines = ["(aucun raccourci trouvé)"] + text = "\n".join(lines) + if os.environ.get("HYPRLAND_INSTANCE_SIGNATURE"): + cmd = ["wofi", "--dmenu", "--prompt", "Raccourcis clavier — taper pour filtrer", + "--width", "820", "--height", "600", "--insensitive", + "--cache-file", "/dev/null"] + if os.path.exists(_WOFI_STYLE): + cmd += ["--style", _WOFI_STYLE] + else: + # X11/i3 : rofi en dmenu, style assorti (mono pour l'alignement). + cmd = ["rofi", "-dmenu", "-i", "-p", "Raccourcis clavier", + "-no-custom", + "-theme-str", 'window { width: 880px; } listview { lines: 18; }', + "-theme-str", '* { font: "Noto Sans Mono 11"; }'] + subprocess.run(cmd, input=text, text=True, check=False) + + +def main(): + try: + if os.environ.get("HYPRLAND_INSTANCE_SIGNATURE"): + lines = hyprland_lines() + else: + lines = i3_lines() + except Exception as exc: # noqa: BLE001 — best effort, jamais de crash muet + subprocess.run(["notify-send", "Raccourcis FWS", f"Erreur : {exc}"], + check=False) + return 1 + show(lines) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/configs/releng/airootfs/usr/local/bin/fws-vr-setup b/configs/releng/airootfs/usr/local/bin/fws-vr-setup index 65e4fb1..34beca4 100755 --- a/configs/releng/airootfs/usr/local/bin/fws-vr-setup +++ b/configs/releng/airootfs/usr/local/bin/fws-vr-setup @@ -24,6 +24,18 @@ if [ "$(id -u)" -ne 0 ]; then exec sudo "$0" "$@" fi +# VM = cul-de-sac VR : pas d'accès direct au GPU ni à l'USB/DisplayPort du +# casque, et Steam (steamwebhelper) est INSTABLE en rendu logiciel (llvmpipe). +# On prévient au lieu de laisser l'utilisateur croire à une panne de FWS. +if systemd-detect-virt --quiet 2>/dev/null; then + warn "Machine VIRTUELLE détectée ($(systemd-detect-virt 2>/dev/null))." + warn "La VR ne fonctionnera PAS ici : casque et GPU inaccessibles depuis une VM." + warn "Steam lui-même peut planter en rendu logiciel (steamwebhelper)." + echo " → Fais cette installation sur la machine RÉELLE avec le casque branché." + read -rp " Continuer quand même (tests uniquement) ? [o/N] " _ok + case "$_ok" in o|O|oui) ;; *) exit 0 ;; esac +fi + # lib32 Vulkan selon le GPU (indispensable à SteamVR, qui est 32/64 bits). GPU="$(lspci 2>/dev/null | grep -iE 'VGA compatible controller|3D controller|Display controller')" LIB32="lib32-mesa" @@ -48,12 +60,20 @@ install_pkgs() { steamvr_base() { say "Installation de la base SteamVR (Steam + Vulkan 32 bits : $LIB32)…" + # ttf-liberation : polices attendues par l'interface Steam (évite des + # rendus cassés/plantages cosmétiques sur install minimale). # shellcheck disable=SC2086 - install_pkgs steam $LIB32 || return 1 + install_pkgs steam $LIB32 ttf-liberation || return 1 say "Base installée. Étapes suivantes :" echo " 1. Lance Steam, connecte-toi, puis installe « SteamVR » (Bibliothèque → Outils)." echo " 2. Branche le casque et les stations, puis lance SteamVR." echo " 3. Premier lancement : SteamVR peut demander à ajuster les règles udev — accepte." + say "Si Steam PLANTE (fenêtre qui se ferme, souvent steamwebhelper) :" + echo " • Vérifie l'espace disque (SteamVR ≈ 5 Go) : df -h ~" + echo " • GPU faible / VM / rendu logiciel — lance :" + echo " steam -cef-disable-gpu -cef-disable-gpu-compositing" + echo " • Pour voir l'erreur exacte : lance « steam » depuis un terminal," + echo " ou regarde ~/.steam/steam/logs/ (console_log.txt, bootstrap_log.txt)." } case "${1:-menu}" in diff --git a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl index 676bcb5..2d00db5 100644 --- a/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl +++ b/configs/releng/airootfs/usr/local/share/fws/hyprland.conf.tmpl @@ -7,7 +7,7 @@ # # Les raccourcis sont déclarés avec « bindd » (bind + description) : la # description alimente l'écran « Raccourcis clavier » (bouton ⌨ de la barre -# ou SUPER+K → fws-hypr-keys, qui lit les binds RÉELS via hyprctl). Ajoute +# ou SUPER+K → fws-keys, qui lit les binds RÉELS via hyprctl). Ajoute # tes propres bindd : ils apparaîtront automatiquement dans la liste. # ⚠ Pas de virgule dans les descriptions (séparateur de champs Hyprland). @@ -81,7 +81,7 @@ bindd = $mod SHIFT, Return, Terminal flottant, exec, kitty --class floating-term bindd = $mod, R, Menu des applications, exec, wofi --show drun bindd = $mod, E, Gestionnaire de fichiers, exec, thunar bindd = $mod, B, Ouvrir Firefox, exec, firefox -bindd = $mod, K, Afficher les raccourcis clavier, exec, fws-hypr-keys +bindd = $mod, K, Afficher les raccourcis clavier, exec, fws-keys # --- Fenêtres --------------------------------------------------------------- bindd = $mod, Q, Fermer la fenêtre, killactive, diff --git a/configs/releng/airootfs/usr/local/share/fws/i3-config b/configs/releng/airootfs/usr/local/share/fws/i3-config index 2742931..52bfb39 100644 --- a/configs/releng/airootfs/usr/local/share/fws/i3-config +++ b/configs/releng/airootfs/usr/local/share/fws/i3-config @@ -41,6 +41,8 @@ bindsym $mod+e exec $filemanager bindsym $mod+b exec $browser # VR : installation des drivers/runtimes casque (HTC Vive, Index, Quest…) bindsym $mod+Shift+v exec kitty -e fws-vr-setup +# Panneau des raccourcis clavier (aussi via le bouton ⌌ de la barre) +bindsym $mod+k exec fws-keys ############## ## FENETRES ## @@ -133,23 +135,16 @@ for_window [title="Picture-in-Picture"] floating enable ########### ## BARRE ## ########### -bar { - status_command i3status - position top - colors { - background $base - statusline $text - separator $surface0 - # classe bordure fond texte - focused_workspace $blue $blue $base - inactive_workspace $surface0 $base $text - urgent_workspace $red $red $base - } -} +# Polybar (config ~/.config/polybar/config.ini) : clone visuel de la waybar +# Hyprland FWS — pilules, icônes, horloge+date au centre, bouton Raccourcis. +# exec_always + pkill : la barre survit proprement aux reload ($mod+Shift+c). +exec_always --no-startup-id sh -c 'pkill -x polybar; sleep 0.3; exec polybar -q fws' ############### ## AUTOSTART ## ############### +# picom : coins arrondis (parité visuelle avec Hyprland) — config FWS légère. +exec --no-startup-id picom --config ~/.config/picom.conf exec --no-startup-id dunst exec --no-startup-id nm-applet exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 diff --git a/configs/releng/airootfs/usr/local/share/fws/picom.conf b/configs/releng/airootfs/usr/local/share/fws/picom.conf new file mode 100644 index 0000000..6edbb89 --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/picom.conf @@ -0,0 +1,19 @@ +# FWS — picom minimal (session i3) : coins arrondis comme sous Hyprland. +# xrender : fiable partout, y compris en VM (rendu logiciel) ; pas de flou ni +# d'ombres (parité avec la config Hyprland FWS, et léger pour la VR). +backend = "xrender"; +vsync = true; + +corner-radius = 8; +rounded-corners-exclude = [ + "window_type = 'dock'", # polybar gère son propre arrondi + "class_g = 'i3-frame'" +]; + +shadow = false; +fading = true; +fade-in-step = 0.08; +fade-out-step = 0.08; + +# VR / jeux plein écran : ne pas composer par-dessus (latence). +unredir-if-possible = true; diff --git a/configs/releng/airootfs/usr/local/share/fws/polybar-config.ini b/configs/releng/airootfs/usr/local/share/fws/polybar-config.ini new file mode 100644 index 0000000..9922af7 --- /dev/null +++ b/configs/releng/airootfs/usr/local/share/fws/polybar-config.ini @@ -0,0 +1,156 @@ +; FWS — polybar (session i3) : clone visuel de la waybar Hyprland. +; Barre flottante arrondie, modules en « pilules » Catppuccin Mocha, +; icônes Nerd Font (ttf-nerd-fonts-symbols). Horloge + date au centre, +; bouton « ⌌ Raccourcis » (fws-keys), volume/réseau/CPU/RAM/tray à droite. + +[colors] +base = #E01e1e2e +surface0 = #313244 +text = #cdd6f4 +subtext = #a6adc8 +blue = #89b4fa +sapphire = #74c7ec +teal = #94e2d5 +mauve = #cba6f7 +maroon = #eba0ac +yellow = #f9e2af +red = #f38ba8 +darkbase = #1e1e2e + +[bar/fws] +monitor = ${env:MONITOR:} +width = 100%:-20 +offset-x = 10 +offset-y = 6 +height = 36 +radius = 14 +background = ${colors.base} +foreground = ${colors.text} +border-size = 1 +border-color = #5989b4fa +padding-left = 1 +padding-right = 1 +module-margin = 1 +line-size = 0 +font-0 = Noto Sans:size=10;2 +font-1 = Symbols Nerd Font:size=12;3 +font-2 = Noto Sans:weight=bold:size=10;2 +modules-left = i3 xwindow +modules-center = date +modules-right = keyhelp backlight pulseaudio network cpu memory tray +enable-ipc = true +wm-restack = i3 + +[module/i3] +type = internal/i3 +pin-workspaces = true +show-urgent = true +strip-wsnumbers = false +format = +label-focused = %name% +label-focused-background = ${colors.blue} +label-focused-foreground = ${colors.darkbase} +label-focused-padding = 2 +label-unfocused = %name% +label-unfocused-background = ${colors.surface0} +label-unfocused-foreground = ${colors.subtext} +label-unfocused-padding = 2 +label-visible = %name% +label-visible-background = ${colors.surface0} +label-visible-padding = 2 +label-urgent = %name% +label-urgent-background = ${colors.red} +label-urgent-foreground = ${colors.darkbase} +label-urgent-padding = 2 + +[module/xwindow] +type = internal/xwindow +label = %title:0:45:…% +label-foreground = ${colors.subtext} +format-padding = 1 + +[module/date] +type = internal/date +interval = 1 +date = %A %d %B %Y +time = %H:%M +label = 󰥔 %time% %date% +label-font = 3 +format-background = ${colors.surface0} +format-padding = 3 + +[module/keyhelp] +type = custom/script +exec = echo "󰌌 Raccourcis" +interval = 3600 +click-left = fws-keys +format-background = ${colors.blue} +format-foreground = ${colors.darkbase} +format-padding = 2 +label-font = 3 + +[module/backlight] +type = internal/backlight +enable-scroll = true +format =