apps/imprimante/app.py est une interface minimaliste pour interagir avec le gestionnaire d'impression standard de Linux (CUPS - Common UNIX Printing System). Elle permet de lister les imprimantes disponibles et d'envoyer rapidement une page de test pour vérifier la connexion matérielle.
lpstat : Au lieu de coder des drivers complexes, l'application exécute la commande lpstat -p en arrière-plan. Elle "parse" (découpe) la sortie texte pour en extraire le nom de chaque imprimante configurée et son état actuel (prête, en veille, ou erreur).lpr -P [nom_imprimante] /usr/share/cups/data/testprint, déclenchant l'impression de la page de test officielle de Linux de façon parfaitement transparente.lpq, qui liste les documents actuellement en attente d'impression. Un bouton permettrait alors d'annuler une impression (cancel [job_id]).import tkinter as tk
from tkinter import messagebox, simpledialog
import subprocess
import os
def start(window, app_manager=None, **kwargs):
frame = tk.Frame(window, bg="white")
frame.pack(fill="both", expand=True)
icon_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "icons")
window.icons = getattr(window, "icons", {})
for iname in ['btn_search', 'btn_print', 'btn_refresh']:
if iname not in window.icons:
ipath = os.path.join(icon_dir, iname + ".png")
if os.path.exists(ipath):
window.icons[iname] = tk.PhotoImage(file=ipath)
header = tk.Label(frame, text="Gestionnaire d'Impression (CUPS)", font=("Arial", 12, "bold"), bg="white", fg="blue")
header.pack(pady=10)
list_frame = tk.Frame(frame, bg="white")
list_frame.pack(fill="both", expand=True, padx=10, pady=5)
listbox = tk.Listbox(list_frame, font=("Arial", 10), height=8)
listbox.pack(side="left", fill="both", expand=True)
scrollbar = tk.Scrollbar(list_frame, orient="vertical", command=listbox.yview)
scrollbar.pack(side="right", fill="y")
listbox.config(yscrollcommand=scrollbar.set)
# Actions Frame
btn_frame = tk.Frame(frame, bg="white")
btn_frame.pack(fill="x", padx=10, pady=10)
def refresh_printers():
listbox.delete(0, tk.END)
try:
# Récupérer l'imprimante par défaut
res_def = subprocess.run(['lpstat', '-d'], capture_output=True, text=True)
default_printer = ""
if res_def.returncode == 0 and "destination système par défaut :" in res_def.stdout or "system default destination:" in res_def.stdout:
default_printer = res_def.stdout.split(":")[1].strip()
res = subprocess.run(['lpstat', '-p'], capture_output=True, text=True)
if res.returncode == 0 and res.stdout.strip():
for line in res.stdout.split('\n'):
if line.startswith("printer"):
parts = line.split()
if len(parts) >= 2:
pname = parts[1]
state = " ".join(parts[2:])
display_text = f"{pname} - {state}"
if pname == default_printer:
display_text = f"⭐ [DÉFAUT] {display_text}"
listbox.insert(tk.END, display_text)
else:
listbox.insert(tk.END, "Aucune imprimante trouvée ou CUPS non installé.")
except FileNotFoundError:
listbox.insert(tk.END, "Erreur: 'lpstat' introuvable. Avez-vous installé 'cups' ?")
def set_default():
pwd = app_manager.desktop.settings.get("sudo_pwd") if app_manager else None
if not pwd:
messagebox.showerror("Erreur", "Veuillez configurer votre mot de passe système dans les Paramètres.")
return
selection = listbox.curselection()
if not selection:
messagebox.showwarning("Attention", "Veuillez sélectionner une imprimante.")
return
item = listbox.get(selection[0])
printer_name = item.replace("⭐ [DÉFAUT] ", "").split()[0]
if printer_name == "Aucune" or printer_name == "Erreur:": return
try:
cmd = f"lpadmin -d {printer_name}"
res = subprocess.run(['sudo', '-S', 'bash', '-c', cmd], input=pwd+'\n', text=True, capture_output=True)
if res.returncode == 0:
messagebox.showinfo("Succès", f"{printer_name} est maintenant l'imprimante par défaut !")
refresh_printers()
else:
messagebox.showerror("Erreur", f"Impossible de définir l'imprimante par défaut :\n{res.stderr}")
except Exception as e:
messagebox.showerror("Exception", str(e))
def print_test():
selection = listbox.curselection()
if not selection:
messagebox.showwarning("Attention", "Veuillez sélectionner une imprimante.")
return
item = listbox.get(selection[0])
printer_name = item.replace("⭐ [DÉFAUT] ", "").split()[0]
if printer_name == "Aucune" or printer_name == "Erreur:":
return
try:
# lp -d printer_name /usr/share/cups/data/testprint
res = subprocess.run(['lp', '-d', printer_name, '/usr/share/cups/data/testprint'], capture_output=True, text=True)
if res.returncode == 0:
messagebox.showinfo("Succès", f"Page de test envoyée à {printer_name}.")
else:
messagebox.showerror("Erreur", f"Échec de l'impression:\n{res.stderr}")
except FileNotFoundError:
messagebox.showerror("Erreur", "La commande 'lp' est introuvable.")
def add_network_printer():
pwd = app_manager.desktop.settings.get("sudo_pwd") if app_manager else None
if not pwd:
messagebox.showerror("Erreur", "Veuillez configurer votre mot de passe système (Sudo) dans les Paramètres.")
return
ip = simpledialog.askstring("Ajouter Imprimante", "Entrez l'adresse IP de l'imprimante réseau :\n(ex: 192.168.1.50)", parent=window)
if not ip:
return
name = simpledialog.askstring("Nom de l'imprimante", "Donnez un nom court à l'imprimante (sans espace) :\n(ex: Bureau)", parent=window)
if not name or " " in name:
messagebox.showerror("Erreur", "Nom invalide (ne doit pas contenir d'espaces).")
return
# lpadmin -p <name> -v ipp://<ip>/ipp/print -E -m everywhere
cmd = f"lpadmin -p {name} -v ipp://{ip}/ipp/print -E -m everywhere"
try:
res = subprocess.run(['sudo', '-S', 'bash', '-c', cmd], input=pwd+'\n', text=True, capture_output=True)
if res.returncode == 0:
# Set as default
subprocess.run(['sudo', '-S', 'bash', '-c', f"lpadmin -d {name}"], input=pwd+'\n', text=True, capture_output=True)
messagebox.showinfo("Succès", f"L'imprimante {name} a été ajoutée avec succès et définie par défaut.")
refresh_printers()
else:
# Fallback to simple socket if IPP Everywhere fails (some older printers)
cmd_fallback = f"lpadmin -p {name} -v socket://{ip} -E"
res_fb = subprocess.run(['sudo', '-S', 'bash', '-c', cmd_fallback], input=pwd+'\n', text=True, capture_output=True)
if res_fb.returncode == 0:
messagebox.showinfo("Succès", f"L'imprimante {name} a été ajoutée (Mode basique sans driver IPP).")
refresh_printers()
else:
messagebox.showerror("Erreur", f"L'ajout a échoué.\n{res.stderr}\n{res_fb.stderr}")
except Exception as e:
messagebox.showerror("Exception", str(e))
def auto_search():
pwd = app_manager.desktop.settings.get("sudo_pwd") if app_manager else None
if not pwd:
messagebox.showerror("Erreur", "Veuillez configurer votre mot de passe système (Sudo) dans les Paramètres.")
return
messagebox.showinfo("Recherche", "La détection automatique va démarrer (cela peut prendre quelques secondes)...")
try:
res = subprocess.run(['ippfind'], capture_output=True, text=True)
if res.returncode == 0 and res.stdout.strip():
uris = res.stdout.strip().split('\n')
uri = uris[0] # Prendre la première imprimante trouvée
name = simpledialog.askstring("Imprimante trouvée", f"Une imprimante a été détectée !\nURI: {uri}\n\nDonnez-lui un nom court (sans espace) :", parent=window)
if not name or " " in name:
return
cmd = f"lpadmin -p {name} -v {uri} -E -m everywhere"
res_add = subprocess.run(['sudo', '-S', 'bash', '-c', cmd], input=pwd+'\n', text=True, capture_output=True)
if res_add.returncode == 0:
subprocess.run(['sudo', '-S', 'bash', '-c', f"lpadmin -d {name}"], input=pwd+'\n', text=True, capture_output=True)
messagebox.showinfo("Succès", f"L'imprimante {name} a été configurée et définie par défaut !")
refresh_printers()
else:
messagebox.showerror("Erreur", f"L'ajout a échoué.\n{res_add.stderr}")
else:
messagebox.showinfo("Résultat", "Aucune imprimante IPP détectée sur le réseau local.")
except FileNotFoundError:
messagebox.showerror("Erreur", "L'outil de recherche (ippfind) est introuvable. Installez cups-client.")
btn_add = tk.Button(btn_frame, text="➕ Ajouter (IP)", command=add_network_printer, bg="lightblue")
btn_add.pack(side="left", padx=5)
btn_search = tk.Button(btn_frame, text=" Détection Auto", image=window.icons.get('btn_search'), compound="left", command=auto_search, bg="#ffeb3b")
btn_search.pack(side="left", padx=5)
btn_test = tk.Button(btn_frame, text=" Page de Test", image=window.icons.get('btn_print'), compound="left", command=print_test, bg="lightgreen")
btn_test.pack(side="left", padx=5)
btn_default = tk.Button(btn_frame, text="⭐ Définir Défaut", command=set_default, bg="orange")
btn_default.pack(side="left", padx=5)
btn_ref = tk.Button(btn_frame, text=" Actualiser", image=window.icons.get('btn_refresh'), compound="left", command=refresh_printers)
btn_ref.pack(side="right", padx=5)
# Note d'installation
note = tk.Label(frame, text="Note: L'impression nécessite d'installer les utilitaires système:\nsudo apt-get install cups cups-client printer-driver-all",
font=("Arial", 8, "italic"), bg="white", fg="gray")
note.pack(pady=5)
refresh_printers()