main_qt.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. # -*- coding: utf-8 -*-
  2. """
  3. A.L.I.G. - Advanced Laser Imaging Generator
  4. ===========================================
  5. Version: 0.99b
  6. Author: Alexandre "MoMo"
  7. License: MIT
  8. """
  9. import sys
  10. import os
  11. import traceback
  12. # Force XWayland sous Linux/Wayland pour obtenir la décoration native Qt
  13. # (boutons min/max/close). Sans ça, GNOME+Wayland délègue au compositeur
  14. # qui ignore les WindowFlags hints et n'affiche pas les boutons.
  15. # setdefault : n'écrase pas si l'utilisateur a déjà défini QT_QPA_PLATFORM.
  16. if sys.platform.startswith("linux"):
  17. os.environ.setdefault("QT_QPA_PLATFORM", "xcb")
  18. # Désactive la détection du thème GNOME via D-Bus (indisponible sous XWayland)
  19. # ce qui supprime le warning "org.freedesktop.portal.Desktop not provided".
  20. os.environ.setdefault("QT_QPA_PLATFORMTHEME", "")
  21. from PyQt6.QtWidgets import QApplication, QMessageBox
  22. from PyQt6.QtCore import Qt, QTimer, QPropertyAnimation, QEasingCurve
  23. from PyQt6.QtGui import QPalette, QColor
  24. from core.config_manager import ConfigManager
  25. from utils.gui_utils import setup_app_id
  26. from gui.main_window_qt import MainWindowQt
  27. IS_WINDOWS = sys.platform == "win32"
  28. def show_fatal_error(message: str) -> None:
  29. """Affiche une erreur fatale de manière cross-platform."""
  30. if IS_WINDOWS:
  31. import ctypes
  32. ctypes.windll.user32.MessageBoxW(0, message, "ALIG Qt - Fatal Error", 0x10)
  33. else:
  34. app = QApplication.instance() or QApplication(sys.argv)
  35. msg = QMessageBox()
  36. msg.setIcon(QMessageBox.Icon.Critical)
  37. msg.setWindowTitle("ALIG Qt - Fatal Error")
  38. msg.setText("Une erreur fatale s'est produite.")
  39. msg.setDetailedText(message)
  40. msg.exec()
  41. def supports_window_opacity() -> bool:
  42. """
  43. Vérifie si le backend Qt supporte la transparence des fenêtres.
  44. - XCB (Linux X11) : non supporté sans composite manager → False
  45. - Wayland, Windows, macOS : supporté → True
  46. IMPORTANT : doit être appelé APRÈS QApplication.__init__().
  47. """
  48. app = QApplication.instance()
  49. if app is None:
  50. return False
  51. platform = app.platformName()
  52. # XCB = X11 classique. Wayland expose "wayland", Windows "windows", macOS "cocoa".
  53. return platform not in ("xcb",)
  54. def main():
  55. try:
  56. setup_app_id()
  57. base_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
  58. config_path = os.path.join(base_dir, "alig_config.json")
  59. config_manager = ConfigManager(config_path)
  60. app = QApplication(sys.argv)
  61. # Détection APRÈS création de QApplication — platformName() est alors fiable.
  62. use_opacity = supports_window_opacity()
  63. window = MainWindowQt(controller=config_manager)
  64. # setUpdatesEnabled(False) masque le rendu initial sans toucher à l'opacité.
  65. # On ne touche JAMAIS à windowOpacity avant show() — cela génère des warnings
  66. # sur XCB (Linux) même quand use_opacity est False.
  67. window.setUpdatesEnabled(False)
  68. def reveal_final():
  69. data = config_manager.get_section("window_settings")
  70. if data.get("is_maximized", False):
  71. window.showMaximized()
  72. else:
  73. window.show()
  74. if use_opacity:
  75. # Opacité initialisée à 0 APRÈS show() — XCB ne se plaint plus
  76. window.setWindowOpacity(0.0)
  77. window.setUpdatesEnabled(True)
  78. if use_opacity:
  79. window.fade_anim = QPropertyAnimation(window, b"windowOpacity")
  80. window.fade_anim.setDuration(250)
  81. window.fade_anim.setStartValue(0.0)
  82. window.fade_anim.setEndValue(1.0)
  83. window.fade_anim.setEasingCurve(QEasingCurve.Type.OutCubic)
  84. window.fade_anim.start()
  85. window.raise_()
  86. window.fade_anim.finished.connect(
  87. lambda: QTimer.singleShot(200, window._preload_raster_view))
  88. else:
  89. # Linux XCB ou tout backend sans opacity : affichage direct
  90. window.raise_()
  91. QTimer.singleShot(200, window._preload_raster_view)
  92. window.ui_ready.connect(reveal_final)
  93. sys.exit(app.exec())
  94. except Exception:
  95. error_message = traceback.format_exc()
  96. print("\n" + "="*50)
  97. print("SÉCURITÉ ALIG - ERREUR DÉTECTÉE")
  98. print("="*50)
  99. print(error_message)
  100. print("="*50 + "\n")
  101. show_fatal_error(error_message)
  102. if __name__ == "__main__":
  103. main()