瀏覽代碼

ensure closing window stops window-method-executor
to prevent freezes on app reload and similar

Rodja Trappe 2 年之前
父節點
當前提交
3a1014229d
共有 1 個文件被更改,包括 30 次插入24 次删除
  1. 30 24
      nicegui/native_mode.py

+ 30 - 24
nicegui/native_mode.py

@@ -1,13 +1,13 @@
 import _thread
 import logging
-import multiprocessing
+import multiprocessing as mp
 import queue
 import socket
 import sys
 import tempfile
 import time
 import warnings
-from threading import Thread
+from threading import Event, Thread
 
 from . import globals, helpers, native
 
@@ -22,8 +22,7 @@ except ModuleNotFoundError:
 
 def open_window(
     host: str, port: int, title: str, width: int, height: int, fullscreen: bool,
-    method_queue: multiprocessing.Queue,
-    response_queue: multiprocessing.Queue,
+    method_queue: mp.Queue, response_queue: mp.Queue,
 ) -> None:
     while not helpers.is_port_open(host, port):
         time.sleep(0.1)
@@ -33,30 +32,37 @@ def open_window(
 
     try:
         window = webview.create_window(**window_kwargs)
-
-        def process_bridge():
-            while True:
-                try:
-                    method, args, kwargs = method_queue.get(block=False)
-                    print(f'calling window.{method}{args}', flush=True)
-                    attr = getattr(window, method)
-                    if callable(attr):
-                        response = attr(*args, **kwargs)
-                        if response is not None:
-                            response_queue.put(response)
-                    else:
-                        logging.error(f'window.{method} is not callable')
-                except queue.Empty:
-                    time.sleep(0.01)
-        t = Thread(target=process_bridge)
-        t.start()
-
+        closing = Event()
+        window.events.closing += lambda: closing.set()
+        start_window_method_executor(window, method_queue, response_queue, closing)
         webview.start(storage_path=tempfile.mkdtemp(), **globals.app.native.start_args)
     except NameError:
         print('Native mode is not supported in this configuration. Please install pywebview to use it.')
         sys.exit(1)
 
 
+def start_window_method_executor(
+        window: webview.Window, method_queue: mp.Queue, response_queue: mp.Queue, closing: Event
+) -> None:
+    def window_method_executor():
+        while not closing.is_set():
+            try:
+                method, args, kwargs = method_queue.get(block=False)
+                attr = getattr(window, method)
+                if callable(attr):
+                    response = attr(*args, **kwargs)
+                    if response is not None:
+                        response_queue.put(response)
+                else:
+                    logging.error(f'window.{method} is not callable')
+            except queue.Empty:
+                time.sleep(0.01)
+            except:
+                logging.exception(f'error in window.{method}')
+    t = Thread(target=window_method_executor)
+    t.start()
+
+
 def activate(host: str, port: int, title: str, width: int, height: int, fullscreen: bool) -> None:
     def check_shutdown() -> None:
         while process.is_alive():
@@ -66,8 +72,8 @@ def activate(host: str, port: int, title: str, width: int, height: int, fullscre
             time.sleep(0.1)
         _thread.interrupt_main()
 
-    multiprocessing.freeze_support()
-    process = multiprocessing.Process(
+    mp.freeze_support()
+    process = mp.Process(
         target=open_window,
         args=(host, port, title, width, height, fullscreen, native.method_queue, native.response_queue),
         daemon=False