diff --git a/CHANGELOG.md b/CHANGELOG.md index 5735cab..1d9677e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed +- The Console Hub no longer crashes on exit (segfault or `corrupted double-linked list` abort in `PySide::destroyQCoreApplication`, leaving a core dump on every quit). The window and tray icon are now destroyed before Python shuts down. - **GC573 green/white speckles and audio crackle on HDMI 2.0 sources (4K60, 1440p120):** - The IT6664 input receiver was left at its fixed power-on equaliser (RS `0x1f`, forced), so >340 MHz TMDS links decoded a steady stream of wrong characters. The errors were re-encoded by the IT6664, so they showed up on the HDMI OUT passthrough too and were invisible to the IT6805. Windows was clean on the same hardware and cable. - New `gc573_user_rx_eq.[ch]` drives both receivers (IT6664 input and IT6805 capture share the same ITE receiver core). On HDMI 2.0 lock it measures per-lane TMDS character errors (CED), leaves error-free links alone, and otherwise runs hardware auto-EQ with DFE taps, falling back to a per-lane RS sweep and skew retraining scored by measured errors. diff --git a/tools/everlive/everlive_viewer.py b/tools/everlive/everlive_viewer.py index 1b1e60e..e3d3ffd 100755 --- a/tools/everlive/everlive_viewer.py +++ b/tools/everlive/everlive_viewer.py @@ -5020,6 +5020,25 @@ def closeEvent(self, event): event.accept() +def _destroy_qt_objects(app, window): + """Tear the Qt object tree down while Python still owns it. + + Leaving it to PySide's interpreter-exit cleanup destroys some QObjects + twice (segfault or "corrupted double-linked list" abort in + PySide::destroyQCoreApplication on every quit). + """ + try: + tray = getattr(window, "tray_icon", None) + if tray is not None: + tray.hide() + window.hide() + window.deleteLater() + app.sendPostedEvents(None, QEvent.Type.DeferredDelete) + app.processEvents() + except Exception: + pass + + def main(): parser = argparse.ArgumentParser(description="EverLive - Live Gamer 4K Console Gaming Screen") parser.add_argument("-f", "--fullscreen", action="store_true", help="Launch directly in fullscreen") @@ -5193,7 +5212,10 @@ def sig_handler(sig, frame): headless_start=args.headless, v4l2_device=args.v4l2) if not args.tray: window.show() - sys.exit(app.exec()) + code = app.exec() + _destroy_qt_objects(app, window) + del window + sys.exit(code) if __name__ == "__main__":