Annexe : Noyau - app_manager.py

Rôle et utilité

Le fichier core/app_manager.py est le "Chef d'Orchestre" des logiciels de GrimOS. Puisqu'il n'y a pas de gestionnaire de fenêtres Unix classique, c'est ce script qui est responsable de lancer les applications, de les confiner dans de fausses fenêtres, et de les fermer. Il lit le registre (config/applications.json) pour savoir quelles applications existent.

Implémentation technique

Pistes de modification

Code Source

import importlib
import traceback
import json
import os
import tkinter as tk
from tkinter import messagebox
from core.window import Window

class AppManager:
    def __init__(self, desktop):
        self.desktop = desktop
        self.active_windows = []
        self.session_file = os.path.join(os.path.dirname(__file__), '..', 'data', 'session.json')

    def launch_app(self, app_config, geometry=None, is_maximized=False, **kwargs):
        module_name = app_config.get("module")
        app_name = app_config.get("name", "Application")

        try:
            module = importlib.import_module(module_name)
            importlib.reload(module)

            if geometry:
                win = Window(self.desktop.desktop_frame, desktop=self.desktop, app_config=app_config, 
                             title=app_name, 
                             x=geometry["x"], y=geometry["y"], 
                             width=geometry["width"], height=geometry["height"],
                             is_maximized=is_maximized, filepath=kwargs.get("filepath"))
            else:
                w = app_config.get("width", 400)
                h = app_config.get("height", 300)
                x = app_config.get("x", 50)
                y = app_config.get("y", 50)
                win = Window(self.desktop.desktop_frame, desktop=self.desktop, app_config=app_config, title=app_name, width=w, height=h, x=x, y=y, filepath=kwargs.get("filepath"))

            self.active_windows.append(win)

            if hasattr(module, 'start'):
                module.start(win.content, app_manager=self, **kwargs)
                win.after(100, win.lift)
            else:
                raise AttributeError(f"Le module {module_name} n'a pas de fonction 'start(window, ...)'.")

        except Exception as e:
            if 'win' in locals() and win.winfo_exists():
                win.destroy()
            err_msg = traceback.format_exc()
            self.show_error(app_name, err_msg)

    def show_error(self, app_name, error_traceback):
        messagebox.showerror(f"Erreur application: {app_name}", f"Une erreur est survenue :\n\n{error_traceback}")

    def save_session(self):
        session_data = []
        for win in self.active_windows:
            win.update_saved_geometry()
            session_data.append({
                "app_config": win.app_config,
                "geometry": win.saved_geometry,
                "is_maximized": win.is_maximized
            })

        try:
            os.makedirs(os.path.dirname(self.session_file), exist_ok=True)
            with open(self.session_file, 'w', encoding='utf-8') as f:
                json.dump(session_data, f)
        except Exception as e:
            print(f"Erreur sauvegarde session: {e}")

    def restore_session(self):
        if not os.path.exists(self.session_file):
            return

        try:
            with open(self.session_file, 'r', encoding='utf-8') as f:
                session_data = json.load(f)

            for data in session_data:
                geom = data.get("geometry")
                if geom and (geom.get("width", 0) <= 10 or geom.get("height", 0) <= 10):
                    geom = None
                self.launch_app(data["app_config"], geom, data.get("is_maximized", False))
        except Exception as e:
            print(f"Erreur restauration session: {e}")