From 4df4b2bff39353f67d309e304a3092c4c9702e72 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 4 Jul 2026 13:43:39 +0200 Subject: [PATCH] feat(fws-about): add fws-about dialog application for system information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new GTK3-based Python application that displays an "About FWS" dialog with two tabs: - "Le projet FWS" tab: shows project name, description, features, and home URL - "Système" tab: displays system information including OS, kernel, desktop environment, hardware (CPU, memory, GPUs, disks) The application detects system information from /proc, lsblk, lspci, and environment variables. It replaces the default Xfce About dialog with FWS branding. --- .../releng/airootfs/usr/local/bin/fws-about | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100755 configs/releng/airootfs/usr/local/bin/fws-about diff --git a/configs/releng/airootfs/usr/local/bin/fws-about b/configs/releng/airootfs/usr/local/bin/fws-about new file mode 100755 index 0000000..223db89 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-about @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +# FWS — fenêtre « À propos » : deux onglets, « Le projet FWS » (ce qu'est FWS, +# version, liens) et « Système » (matériel + logiciel détectés). Remplace le +# « About Xfce » de libxfce4ui par une page de marque FWS. GTK3 (python-gobject +# installé avec le bureau). + +import os +import re +import subprocess + +import gi + +gi.require_version("Gtk", "3.0") +gi.require_version("Gdk", "3.0") # sinon gi charge Gdk 4.0 (conflit avec Gtk3) +from gi.repository import Gdk, GLib, Gtk # noqa: E402 + +GLib.set_prgname("fws-about") + + +def _osrelease(): + data = {} + for path in ("/etc/os-release", "/usr/lib/os-release"): + try: + with open(path) as fh: + for line in fh: + m = re.match(r'^([A-Z_]+)=(.*)$', line.strip()) + if m: + data[m.group(1)] = m.group(2).strip('"') + break + except OSError: + continue + return data + + +def _cmd(*argv): + try: + return subprocess.check_output(argv, text=True, + stderr=subprocess.DEVNULL).strip() + except (OSError, subprocess.CalledProcessError): + return "" + + +def _cpu(): + try: + with open("/proc/cpuinfo") as fh: + for line in fh: + if line.startswith("model name"): + return line.split(":", 1)[1].strip() + except OSError: + pass + return "inconnu" + + +def _mem(): + try: + with open("/proc/meminfo") as fh: + for line in fh: + if line.startswith("MemTotal"): + kib = int(line.split()[1]) + return f"{kib / 1048576:.1f} Gio" + except OSError: + pass + return "inconnu" + + +def _gpus(): + out = [] + for line in _cmd("lspci").splitlines(): + low = line.lower() + if "vga" in low or "3d" in low or "display" in low: + out.append(line.split(":", 2)[-1].strip()) + return out or ["inconnu"] + + +def _desktop(): + if os.environ.get("HYPRLAND_INSTANCE_SIGNATURE"): + return "Hyprland" + env = os.environ.get("XDG_CURRENT_DESKTOP") \ + or os.environ.get("DESKTOP_SESSION") or "" + return env or "inconnu" + + +def _session_type(): + t = os.environ.get("XDG_SESSION_TYPE", "") + return {"wayland": "Wayland", "x11": "X11"}.get(t, t or "inconnu") + + +def _disks(): + out = [] + for line in _cmd("lsblk", "-dno", "NAME,SIZE,MODEL,TYPE").splitlines(): + f = line.split() + if f and f[-1] == "disk": + out.append(" ".join(f[:-1])) + return out or ["inconnu"] + + +def _grid(rows): + grid = Gtk.Grid(column_spacing=18, row_spacing=8, margin=18) + for i, (key, val) in enumerate(rows): + k = Gtk.Label(xalign=1) + k.set_markup(f"{GLib.markup_escape_text(key)}") + k.get_style_context().add_class("dim-label") + v = Gtk.Label(label=val, xalign=0, selectable=True) + v.set_line_wrap(True) + grid.attach(k, 0, i, 1, 1) + grid.attach(v, 1, i, 1, 1) + return grid + + +def _project_tab(osr): + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10, margin=20) + title = Gtk.Label() + name = osr.get("PRETTY_NAME") or osr.get("NAME") or "FWS Linux" + title.set_markup(f"{name}") + box.pack_start(title, False, False, 0) + + tag = Gtk.Label(label="Une distribution Arch Linux pensée pour remplacer " + "Windows : bureau prêt à l'emploi, jeux, VR et " + "compatibilité applicative.") + tag.set_line_wrap(True) + tag.set_max_width_chars(52) + box.pack_start(tag, False, False, 0) + + feats = Gtk.Label() + feats.set_markup( + "Inclus : installateur graphique · plusieurs bureaux " + "(GNOME, KDE, Hyprland, i3, XFCE) · Steam & Proton-GE · " + "réalité virtuelle (SteamVR) · winboat (applications Windows) · " + "pare-feu · réparation système intégrée.") + feats.set_line_wrap(True) + feats.set_max_width_chars(52) + feats.set_xalign(0) + box.pack_start(feats, False, False, 6) + + home = osr.get("HOME_URL") or "https://github.com/You-re-like-Windows-a-bitch/fws" + link = Gtk.LinkButton.new_with_label(home, "Site du projet") + box.pack_start(link, False, False, 0) + return box + + +def _system_tab(osr): + rows = [ + ("Système", osr.get("PRETTY_NAME", "FWS Linux")), + ("Build", osr.get("BUILD_ID", "rolling")), + ("Noyau", _cmd("uname", "-r") or "inconnu"), + ("Bureau", _desktop()), + ("Affichage", _session_type()), + ("Nom de machine", _cmd("hostname") or os.uname().nodename), + ("Processeur", _cpu()), + ("Mémoire", _mem()), + ("Carte(s) graphique(s)", "\n".join(_gpus())), + ("Disque(s)", "\n".join(_disks())), + ] + scroll = Gtk.ScrolledWindow() + scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + scroll.add(_grid(rows)) + return scroll + + +class AboutWindow(Gtk.Window): + def __init__(self): + super().__init__(title="À propos de FWS") + self.set_default_size(520, 460) + self.set_position(Gtk.WindowPosition.CENTER) + self.set_type_hint(Gdk.WindowTypeHint.DIALOG) + + osr = _osrelease() + notebook = Gtk.Notebook() + notebook.append_page(_project_tab(osr), Gtk.Label(label="Le projet FWS")) + notebook.append_page(_system_tab(osr), Gtk.Label(label="Système")) + self.add(notebook) + self.connect("destroy", Gtk.main_quit) + + +def main(): + if not Gtk.init_check()[0]: + return 1 + win = AboutWindow() + win.show_all() + Gtk.main() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())