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.
importlib.import_module(). L'application n'est chargée en mémoire que lorsque l'utilisateur clique sur son icône.Window : Lorsqu'une application est lancée, l'AppManager demande d'abord à window.py de créer un cadre vide (la fausse fenêtre). Ensuite, il appelle la fonction obligatoire start(fenetre_interne) du module de l'application en lui passant ce cadre.try/except. Si le code d'une application (par exemple l'Éditeur) contient une erreur fatale, le crash est intercepté par l'AppManager. Au lieu de faire planter tout GrimOS, le système affiche simplement une petite boîte de dialogue d'erreur et détruit la fenêtre fautive.AppManager pour qu'il force les fenêtres à prendre la taille maximale de l'écran dès leur instanciation.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}")