Skip to content

Commit dbf0e05

Browse files
committed
[Winforms] Fixes Ctrl+C signal handling in WinForms platform
1 parent 0415bea commit dbf0e05

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

webview/platforms/winforms.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ctypes
22
import logging
33
import os
4+
import signal
45
import sys
56
import tempfile
67
import threading
@@ -33,6 +34,20 @@
3334
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
3435
logger = logging.getLogger('pywebview')
3536
cache_dir = None
37+
_sigint_received = False
38+
39+
40+
def _sigint_handler(signum, frame):
41+
"""
42+
Handler for SIGINT signal (Ctrl+C).
43+
44+
Sets a flag that's checked by the timer in the GUI thread. This is necessary because
45+
the signal handler runs in the main thread, but Application.Exit() must be called
46+
from the GUI thread. The timer in create_window() checks this flag periodically and
47+
exits the application when it's set.
48+
"""
49+
global _sigint_received
50+
_sigint_received = True
3651

3752

3853
def _is_new_version(current_version: str, new_version: str) -> bool:
@@ -748,11 +763,28 @@ def create():
748763
_main_window_created.set()
749764

750765
if window.uid == 'master':
766+
767+
def timer_tick(sender, e):
768+
# Check if SIGINT was received and exit from GUI thread
769+
global _sigint_received
770+
if _sigint_received:
771+
app.Exit()
772+
773+
# Create a timer to periodically allow the Python interpreter to run
774+
# This enables the signal handler to be called even when the WinForms event loop is running
775+
timer = WinForms.Timer()
776+
timer.Interval = 500 # 500ms
777+
timer.Tick += timer_tick
778+
timer.Start()
779+
751780
app.Run()
752781

753782
app = WinForms.Application
754783

755784
if window.uid == 'master':
785+
# Set up Ctrl+C handler in main thread (before starting GUI thread)
786+
signal.signal(signal.SIGINT, _sigint_handler)
787+
756788
if is_chromium:
757789
init_storage()
758790

@@ -765,7 +797,13 @@ def create():
765797
thread = Thread(ThreadStart(create))
766798
thread.SetApartmentState(ApartmentState.STA)
767799
thread.Start()
768-
thread.Join()
800+
801+
# Don't use thread.Join() as it blocks the main thread indefinitely,
802+
# preventing signal handlers from being processed. Instead, periodically
803+
# check if the thread is still alive, which allows the Python interpreter
804+
# to process pending signals (like SIGINT from Ctrl+C)
805+
while thread.IsAlive:
806+
thread.Join(500)
769807

770808
else:
771809
_main_window_created.wait()

0 commit comments

Comments
 (0)