import sys from PySide6.QtCore import QCoreApplication, Qt from PySide6.QtGui import QSurfaceFormat from PySide6.QtWidgets import QApplication, QMessageBox from .utils.ytsage_logger import logger from .gui.ytsage_gui_main import YTSageApp # Import the main application class from ytsage_gui_main def _configure_opengl() -> None: """ Must run before QApplication exists -- both settings are ignored afterwards. AA_ShareOpenGLContexts puts every widget context in one sharing group, so a reparent no longer loses GL *resources*. It does not stop Qt destroying and recreating the widget's own context (MpvRenderWidget handles that); it removes a whole second class of failure around it. The surface format is deliberately minimal. mpv renders into our FBO and needs no depth, stencil or alpha from the default framebuffer, and asking for them is what produced `OpenGL error INVALID_ENUM` on some drivers. No GL version or profile is requested on purpose: pinning a core profile breaks software and GLES stacks that libmpv would otherwise accept. """ QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True) fmt = QSurfaceFormat() fmt.setSwapBehavior(QSurfaceFormat.SwapBehavior.DoubleBuffer) fmt.setSwapInterval(1) fmt.setDepthBufferSize(0) fmt.setStencilBufferSize(0) fmt.setAlphaBufferSize(0) QSurfaceFormat.setDefaultFormat(fmt) def show_error_dialog(message): # A QMessageBox needs a live QApplication; if startup failed before (or # while) creating one, constructing the dialog would abort the process # and swallow the real error. if QApplication.instance() is None: print(f"Application Error: {message}", file=sys.stderr) return error_dialog = QMessageBox() error_dialog.setIcon(QMessageBox.Icon.Critical) error_dialog.setText("Application Error") error_dialog.setInformativeText(message) error_dialog.setWindowTitle("Error") error_dialog.exec() def main(): try: logger.info("Starting SageTube application") _configure_opengl() app = QApplication(sys.argv) app.setApplicationName("SageTube") app.setDesktopFileName("sagetube") # Before the main window: this retro-fits icons, tooltips and # accessible names onto every button as it is first polished. from .gui.ytsage_ui_polish import install as install_ui_polish install_ui_polish(app) window = YTSageApp() # Instantiate the main application class window.show() logger.info("Application window shown, entering main loop") sys.exit(app.exec()) except Exception as e: logger.critical(f"Critical application error: {e}", exc_info=True) show_error_dialog(f"Critical error: {e}") sys.exit(1) if __name__ == "__main__": main()