@@ -431,11 +431,12 @@ def __init__(self, canvas, num, window):
431431 # to store the DPI, which will be updated by the C code, and the trace
432432 # will handle it on the Python side.
433433 window_frame = int (window .wm_frame (), 16 )
434- window_dpi = tk .IntVar (master = window , value = 96 ,
435- name = f'window_dpi{ window_frame } ' )
434+ self ._window_dpi = tk .IntVar (master = window , value = 96 ,
435+ name = f'window_dpi{ window_frame } ' )
436+ self ._window_dpi_cbname = ''
436437 if _tkagg .enable_dpi_awareness (window_frame , window .tk .interpaddr ()):
437- self ._window_dpi = window_dpi # Prevent garbage collection.
438- window_dpi . trace_add ( 'write' , self ._update_window_dpi )
438+ self ._window_dpi_cbname = self . _window_dpi . trace_add (
439+ 'write' , self ._update_window_dpi )
439440
440441 self ._shown = False
441442
@@ -489,20 +490,26 @@ def destroy(self, *args):
489490 self .canvas ._tkcanvas .after_cancel (self .canvas ._idle_draw_id )
490491 if self .canvas ._event_loop_id :
491492 self .canvas ._tkcanvas .after_cancel (self .canvas ._event_loop_id )
493+ if self ._window_dpi_cbname :
494+ self ._window_dpi .trace_remove ('write' , self ._window_dpi_cbname )
492495
493496 # NOTE: events need to be flushed before issuing destroy (GH #9956),
494- # however, self.window.update() can break user code. This is the
495- # safest way to achieve a complete draining of the event queue,
496- # but it may require users to update() on their own to execute the
497- # completion in obscure corner cases .
497+ # however, self.window.update() can break user code. An async callback
498+ # is the safest way to achieve a complete draining of the event queue,
499+ # but it leaks if no tk event loop is running. Therefore we explicitly
500+ # check for an event loop and choose our best guess .
498501 def delayed_destroy ():
499502 self .window .destroy ()
500503
501504 if self ._owns_mainloop and not Gcf .get_num_fig_managers ():
502505 self .window .quit ()
503506
504- # "after idle after 0" avoids Tcl error/race (GH #19940)
505- self .window .after_idle (self .window .after , 0 , delayed_destroy )
507+ if cbook ._get_running_interactive_framework () == "tk" :
508+ # "after idle after 0" avoids Tcl error/race (GH #19940)
509+ self .window .after_idle (self .window .after , 0 , delayed_destroy )
510+ else :
511+ self .window .update ()
512+ delayed_destroy ()
506513
507514 def get_window_title (self ):
508515 return self .window .wm_title ()
0 commit comments