Files
nocode 1c74b59459 fix(fws-hello): set window type hint to dialog and prevent resizing
Import Gdk and GLib modules to properly configure window behavior.

Set deterministic WM_CLASS using GLib.set_prgname() so that i3/Hyprland
window rules targeting "fws-hello" floating window behavior work correctly.

Set window type hint to DIALOG and disable resizing to ensure the window
remains floating with its natural size instead of being stretched across
the entire workspace, which would result in unreadable layout.
2026-07-04 13:42:24 +02:00

159 lines
5.4 KiB
Python
Executable File

#!/usr/bin/env python3
# FWS — fenêtre de bienvenue au premier démarrage (pendant post-install de la
# page récap de l'installateur). Boutons : mise à jour, codecs, VR, raccourcis,
# Proton-GE. GTK3 : présent sur TOUS les bureaux FWS (Firefox le tire) ;
# python-gobject est installé avec le bureau par le kickstart.
#
# Lancement : /etc/xdg/autostart (KDE/GNOME/XFCE) et exec des configs
# Hyprland/i3, toujours avec --autostart : on se retire sans bruit si
# l'utilisateur a coché « ne plus afficher » (~/.config/fws/hello-done).
import os
import shutil
import subprocess
import sys
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
# WM_CLASS déterministe : les règles i3/Hyprland « fenêtre flottante »
# ciblent cette classe.
GLib.set_prgname("fws-hello")
_FLAG = os.path.expanduser("~/.config/fws/hello-done")
_CODECS = ("gst-plugins-base gst-plugins-good gst-plugins-bad "
"gst-plugins-ugly gst-libav ffmpeg mpv")
# (libellé, description, commande, en_terminal)
_ACTIONS = [
("Mettre à jour le système",
"pacman -Syu + nettoyage du cache",
"fws-update", True),
("Installer les codecs multimédia",
"lecture vidéo/audio (GStreamer, ffmpeg, mpv)",
f"sudo pacman -S --needed {_CODECS}", True),
("Proton-GE pour Steam",
"meilleure compatibilité des jeux Windows",
"fws-proton-ge", True),
("Configurer la VR",
"drivers casque : HTC Vive, Index, Quest…",
"fws-vr-setup", True),
]
_TERMINALS = ["kitty", "konsole", "gnome-terminal", "xfce4-terminal", "xterm"]
def _terminal():
for term in _TERMINALS:
if shutil.which(term):
return term
return None
def _run(command, in_terminal):
if in_terminal:
term = _terminal()
if term is None:
return
if term == "gnome-terminal":
argv = [term, "--", "sh", "-c", command]
else:
argv = [term, "-e", "sh", "-c", command]
else:
argv = ["sh", "-c", command]
subprocess.Popen(argv) # noqa: S603 — commandes internes FWS
class HelloWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Bienvenue sur FWS")
self.set_default_size(460, -1)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_border_width(18)
# DIALOGUE : les tuileurs (i3/Hyprland) laissent les dialogues en
# flottant → la fenêtre garde sa taille naturelle au lieu d'être
# étirée sur tout l'espace de travail (layout illisible sinon).
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
self.set_resizable(False)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
self.add(box)
title = Gtk.Label()
title.set_markup("<span size='x-large' weight='bold'>Bienvenue sur FWS !</span>")
box.pack_start(title, False, False, 0)
subtitle = Gtk.Label(
label="Ton système est prêt. Quelques réglages utiles pour bien démarrer :")
subtitle.set_line_wrap(True)
subtitle.set_xalign(0)
box.pack_start(subtitle, False, False, 0)
actions = list(_ACTIONS)
# Raccourcis clavier : uniquement sur les sessions qui ont fws-keys
# (Hyprland/i3) — les autres bureaux ont leurs propres réglages.
session = os.environ.get("XDG_CURRENT_DESKTOP", "").lower()
if os.environ.get("HYPRLAND_INSTANCE_SIGNATURE") or "i3" in session:
actions.append(("Voir les raccourcis clavier",
"aussi disponible à tout moment : Super+K",
"fws-keys", False))
for label, desc, command, in_term in actions:
button = Gtk.Button()
inner = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
lab = Gtk.Label()
lab.set_markup(f"<b>{label}</b>")
lab.set_xalign(0)
sub = Gtk.Label(label=desc)
sub.set_xalign(0)
sub.get_style_context().add_class("dim-label")
inner.pack_start(lab, False, False, 0)
inner.pack_start(sub, False, False, 0)
button.add(inner)
button.connect("clicked",
lambda _b, c=command, t=in_term: _run(c, t))
box.pack_start(button, False, False, 0)
self._again = Gtk.CheckButton(label="Afficher cette fenêtre au prochain démarrage")
self._again.set_active(False)
box.pack_start(self._again, False, False, 6)
close = Gtk.Button(label="Fermer")
close.connect("clicked", lambda _b: self.close())
box.pack_start(close, False, False, 0)
self.connect("destroy", self._on_destroy)
def _on_destroy(self, _win):
if not self._again.get_active():
os.makedirs(os.path.dirname(_FLAG), exist_ok=True)
with open(_FLAG, "w") as fh:
fh.write("ok\n")
else:
try:
os.unlink(_FLAG)
except OSError:
pass
Gtk.main_quit()
def main():
if "--autostart" in sys.argv and os.path.exists(_FLAG):
return 0
# Pas d'affichage joignable (lancement hors session graphique) : on se
# retire sans traceback plutôt que de crasher.
if not Gtk.init_check()[0]:
return 1
win = HelloWindow()
win.show_all()
Gtk.main()
return 0
if __name__ == "__main__":
sys.exit(main())