@@ -303,29 +303,41 @@ def __init__(self):
303
303
# Use a deque instead of Queue, as we don't require
304
304
# synchronization between threads here.
305
305
self .__callbacks = deque ()
306
- # Set a 0-delay timer on itself, this will ensure that
307
- # timerEvent gets fired each time after window events are processed
308
- # See https://doc.qt.io/qt-6/qtimer.html#interval-prop
309
- self .__timerId = self .startTimer (0 )
306
+
307
+ # Keep track of the current timer.
308
+ # The queue can only have a single timer that services it.
309
+ # Once fired, all pending callbacks will be processed.
310
+ self .__timer_id = None
310
311
self .__stopped = False
311
312
self .__debug_enabled = False
312
313
313
314
def add_callback (self , handle ):
314
315
# handle must be an asyncio.Handle
315
316
self .__callbacks .append (handle )
316
317
self .__log_debug ("Registering call_soon handle %s" , id (handle ))
318
+
319
+ # Create a timer if it doesn't yet exist
320
+ if self .__timer_id is None :
321
+ # Set a 0-delay timer on itself, this will ensure thats
322
+ # it gets fired immediately after window events are processed the next time.
323
+ # See https://doc.qt.io/qt-6/qtimer.html#interval-prop
324
+ self .__timer_id = self .startTimer (0 )
325
+ self .__log_debug ("Registering call_soon timer %s" , self .__timer_id )
317
326
return handle
318
327
319
328
def timerEvent (self , event ):
320
329
timerId = event .timerId ()
321
- assert timerId == self .__timerId
330
+ # We should have only one timer active at the same time, so
331
+ # this assert will get hit only when something's very bad
332
+ assert timerId == self .__timer_id
322
333
323
334
# Stop timer if stopped
324
335
if self .__stopped :
325
- self .killTimer (timerId )
326
336
self .__log_debug ("call_soon queue stopped, clearing handles" )
327
337
# TODO: Do we need to del the handles or somehow invalidate them?
328
338
self .__callbacks .clear ()
339
+ self .killTimer (timerId )
340
+ self .__timer_id = None
329
341
return
330
342
331
343
# Iterate over pending callbacks
@@ -335,6 +347,15 @@ def timerEvent(self, event):
335
347
self .__log_debug ("Calling call_soon handle %s" , id (handle ))
336
348
handle ._run ()
337
349
350
+ # No more callbacks exist, we can dispose this timer.
351
+ # It will be recreated once a callback is registered again.
352
+ # It's should be safe to assume that another thread isn't calling
353
+ # add_callback during the lifetime of timerEvent
354
+ self .__log_debug ("Stopping call_soon timer %s" , timerId )
355
+ self .killTimer (timerId )
356
+ self .__timer_id = None
357
+ assert len (self .__callbacks ) == 0
358
+
338
359
def stop (self ):
339
360
self .__log_debug ("Stopping call_soon queue" )
340
361
self .__stopped = True
0 commit comments