Преглед изворни кода

fix(touch): restore QEventLoop pattern for proper QTimer support

The qasync.run() + await quit_event.wait() pattern doesn't properly
process QTimer.singleShot callbacks, which broke touch-to-wake
(the callback to start touch monitoring never fired).

Restored the original QEventLoop + run_forever() pattern which
properly integrates Qt timers. Using qasync 0.28.0 which should
have fixes for the CPU spin issues reported in earlier versions.

This should fix touch-to-wake while maintaining reasonable CPU usage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tuanchris пре 1 недеља
родитељ
комит
8a4a0f8610
1 измењених фајлова са 31 додато и 39 уклоњено
  1. 31 39
      dune-weaver-touch/main.py

+ 31 - 39
dune-weaver-touch/main.py

@@ -8,7 +8,7 @@ from pathlib import Path
 from PySide6.QtCore import QUrl, QTimer, QObject, QEvent
 from PySide6.QtGui import QGuiApplication, QTouchEvent, QMouseEvent
 from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterType, QQmlContext
-import qasync
+from qasync import QEventLoop
 
 # Load environment variables from .env file if it exists
 from dotenv import load_dotenv
@@ -96,12 +96,22 @@ def is_pi5():
     except:
         return False
 
-async def async_main(app):
-    """Main async function that runs the Qt application.
+def main():
+    # Enable virtual keyboard
+    os.environ['QT_IM_MODULE'] = 'qtvirtualkeyboard'
+
+    app = QGuiApplication(sys.argv)
+
+    # Install first-touch filter to ignore wake-up touches
+    first_touch_filter = FirstTouchFilter(idle_threshold_seconds=2.0)
+    app.installEventFilter(first_touch_filter)
+    logger.info("✅ First-touch filter installed on application")
+
+    # Setup async event loop using QEventLoop
+    # This properly integrates Qt and asyncio, including QTimer callbacks
+    loop = QEventLoop(app)
+    asyncio.set_event_loop(loop)
 
-    Uses qasync's event loop integration - do NOT call app.processEvents()
-    manually as qasync handles Qt/asyncio integration automatically.
-    """
     # Register types
     qmlRegisterType(Backend, "DuneWeaver", 1, 0, "Backend")
     qmlRegisterType(PatternModel, "DuneWeaver", 1, 0, "PatternModel")
@@ -123,52 +133,34 @@ async def async_main(app):
         logger.error("❌ Failed to load QML - no root objects")
         return -1
 
-    # Schedule startup tasks
-    asyncio.create_task(startup_tasks())
-
-    logger.info("✅ Qt application started successfully")
-
-    # Create an asyncio event that will be set when the app quits
-    # This is the proper way to wait - qasync handles event loop integration
-    quit_event = asyncio.Event()
-    app.aboutToQuit.connect(quit_event.set)
-
-    # Wait for the app to quit
-    # This properly yields to the event loop, allowing:
-    # - Qt events to be processed (handled by qasync)
-    # - Other async tasks (like aiohttp in Backend) to run
-    # - No CPU spinning since we're awaiting an event, not polling
-    await quit_event.wait()
+    # Schedule startup tasks after event loop starts
+    def schedule_startup():
+        asyncio.create_task(startup_tasks())
 
-    logger.info("🛑 Application shutdown complete")
-    return 0
-
-def main():
-    # Enable virtual keyboard
-    os.environ['QT_IM_MODULE'] = 'qtvirtualkeyboard'
-
-    app = QGuiApplication(sys.argv)
-
-    # Install first-touch filter to ignore wake-up touches
-    first_touch_filter = FirstTouchFilter(idle_threshold_seconds=2.0)
-    app.installEventFilter(first_touch_filter)
-    logger.info("✅ First-touch filter installed on application")
+    QTimer.singleShot(100, schedule_startup)
 
     # Setup signal handlers for clean shutdown
     def signal_handler(signum, frame):
         logger.info("🛑 Received shutdown signal, exiting...")
+        loop.stop()
         app.quit()
 
     signal.signal(signal.SIGINT, signal_handler)
     signal.signal(signal.SIGTERM, signal_handler)
 
-    # Use qasync.run() to properly integrate Qt and asyncio event loops
-    # qasync handles all event loop integration - we just await the quit signal
+    logger.info("✅ Qt application started successfully")
+
+    # Run the event loop
+    # Using qasync 0.28.0 which should have CPU spin fixes
     try:
-        qasync.run(async_main(app))
+        with loop:
+            loop.run_forever()
     except KeyboardInterrupt:
-        logger.info("🛑 KeyboardInterrupt received")
+        logger.info("🛑 KeyboardInterrupt received, shutting down...")
+    finally:
+        loop.close()
 
+    logger.info("🛑 Application shutdown complete")
     return 0
 
 if __name__ == "__main__":