Annexe : Application - Gestionnaire des tâches (TaskMgr)

Rôle et utilité

L'application apps/taskmgr/app.py permet à l'utilisateur de surveiller les processus en cours d'exécution sur la machine et de "tuer" (fermer de force) les applications qui ne répondent plus. C'est l'équivalent du classique "Ctrl+Alt+Suppr" sous Windows.

Implémentation technique

Pistes de modification

Code Source

import tkinter as tk
from tkinter import ttk, messagebox
import os
import signal

def start(window, app_manager=None, **kwargs):
    top_frame = tk.Frame(window, bg="lightgray")
    top_frame.pack(side="top", fill="x")

    btn_kill = tk.Button(top_frame, text=" Fin de tâche", image=(app_manager.desktop.icons.get("btn_kill") if app_manager else None), compound="left", bg="red", fg="white", font=("Arial", 9, "bold"))
    btn_kill.pack(side="left", padx=5, pady=5)

    btn_refresh = tk.Button(top_frame, text=" Actualiser", image=(app_manager.desktop.icons.get("btn_refresh") if app_manager else None), compound="left", font=("Arial", 9))
    btn_refresh.pack(side="left", padx=5, pady=5)

    def show_help():
        msg = (
            "Aide du Gestionnaire des Tâches\n\n"
            "• Cette liste affiche les processus en cours sur le système.\n"
            "• Le bouton rouge 'Fin de tâche' envoie un signal d'arrêt immédiat (kill) au programme.\n\n"
            "⚠️ Attention : Tuer un processus vital (comme systemd, xorg, ou dbus) causera "
            "le plantage immédiat de l'interface ou du système."
        )
        messagebox.showinfo("Aide Gestionnaire", msg)

    btn_help = tk.Button(top_frame, text=" Aide", image=(app_manager.desktop.icons.get("btn_help") if app_manager else None), compound="left", command=show_help, relief="flat", bg="lightblue")
    btn_help.pack(side="right", padx=5, pady=2)

    tree_frame = tk.Frame(window)
    tree_frame.pack(fill="both", expand=True)

    scrollbar = tk.Scrollbar(tree_frame)
    scrollbar.pack(side="right", fill="y")

    tree = ttk.Treeview(tree_frame, columns=("PID", "Name", "State"), show="headings", yscrollcommand=scrollbar.set)
    tree.heading("PID", text="PID")
    tree.heading("Name", text="Nom du processus")
    tree.heading("State", text="État")
    tree.column("PID", width=60, anchor="center")
    tree.column("Name", width=250)
    tree.column("State", width=60, anchor="center")
    tree.pack(side="left", fill="both", expand=True)
    scrollbar.config(command=tree.yview)

    def refresh():
        for i in tree.get_children():
            tree.delete(i)

        try:
            pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
            pids.sort(key=int)
            for pid_str in pids:
                try:
                    with open(f"/proc/{pid_str}/stat", "r") as f:
                        stat = f.read().split()
                        # stat[1] is the process name, usually in parentheses like (systemd)
                        name = stat[1].strip("()")
                        state = stat[2]
                        tree.insert("", "end", values=(pid_str, name, state))
                except Exception:
                    continue
        except Exception as e:
            messagebox.showerror("Erreur", f"Impossible de lire /proc:\n{e}")

    def kill_proc():
        selected = tree.selection()
        if not selected:
            return
        item = tree.item(selected[0])
        pid = int(item['values'][0])
        name = item['values'][1]

        # Prevent killing vital system processes lightly
        if pid in (1, 2) or "xorg" in str(name).lower() or "python" in str(name).lower():
            if not messagebox.askyesno("Attention Système", f"Tuer '{name}' (PID: {pid}) pourrait crasher le système ! Continuer ?"):
                return

        if messagebox.askyesno("Confirmer", f"Voulez-vous forcer l'arrêt de '{name}' (PID: {pid}) ?"):
            try:
                os.kill(pid, signal.SIGKILL)
                window.after(500, refresh)
            except PermissionError:
                messagebox.showerror("Accès refusé", f"Vous n'avez pas les droits pour tuer ce processus (PID: {pid}).")
            except Exception as e:
                messagebox.showerror("Erreur", f"Impossible de terminer le processus:\n{e}")

    btn_refresh.config(command=refresh)
    btn_kill.config(command=kill_proc)

    refresh()