|
2 | 2 | import argparse
|
3 | 3 | import asyncio
|
4 | 4 | import logging
|
| 5 | +import os |
| 6 | +import signal |
| 7 | +import subprocess |
5 | 8 | import sys
|
6 | 9 | import threading
|
7 | 10 | import tkinter
|
@@ -369,9 +372,32 @@ def main():
|
369 | 372 | root.geometry("500x400")
|
370 | 373 | root.iconbitmap("extra/icon.ico")
|
371 | 374 | scroll_frame = ScrollableFrame(root)
|
372 |
| - KasaDevices(scroll_frame.scrollable_frame).pack() |
| 375 | + device_frame = KasaDevices(scroll_frame.scrollable_frame) |
| 376 | + device_frame.pack() |
373 | 377 | scroll_frame.pack(fill=tkinter.BOTH, expand=True)
|
374 |
| - root.mainloop() |
| 378 | + try: |
| 379 | + root.mainloop() |
| 380 | + except KeyboardInterrupt: |
| 381 | + logger.info("Caught KeyboardInterrupt. Shutting down.") |
| 382 | + finally: |
| 383 | + logger.info("Tkinter mainloop has exited.") |
| 384 | + # stop the event loop |
| 385 | + device_frame.event_loop.call_soon_threadsafe(device_frame.event_loop.stop) |
| 386 | + device_frame.event_loop.call_soon_threadsafe(device_frame.event_loop.close) |
| 387 | + |
| 388 | + logger.info("Stopped asyncio event loop") |
| 389 | + # wait up to three seconds |
| 390 | + device_frame.event_thread.join(3) |
| 391 | + if device_frame.event_thread.is_alive(): |
| 392 | + # If we get here, then it is likely that there is an uncooperative |
| 393 | + # asyncio task that is hogging the CPU and not surrending control |
| 394 | + # via await. |
| 395 | + logger.warning("Failed to stop event thread.") |
| 396 | + # Since asyncio is not behaving, we need to kill ourselves. |
| 397 | + if os.name == "nt": |
| 398 | + subprocess.run(["taskkill", "/IM", str(os.getpid()), "/F"]) |
| 399 | + else: |
| 400 | + os.kill(os.getpid(), signal.SIGKILL) |
375 | 401 |
|
376 | 402 |
|
377 | 403 | if __name__ == "__main__":
|
|
0 commit comments