4747except TypeError as exc :
4848 cursord = {} # deprecated in Matplotlib 3.5.
4949
50+ # Placeholder
51+ _application = None
52+
53+
54+ def _shutdown_application (app ):
55+ # The application might prematurely shut down if Ctrl-C'd out of IPython,
56+ # so close all windows.
57+ for win in app .get_windows ():
58+ win .destroy ()
59+ # The PyGObject wrapper incorrectly thinks that None is not allowed, or we
60+ # would call this:
61+ # Gio.Application.set_default(None)
62+ # Instead, we set this property and ignore default applications with it:
63+ app ._created_by_matplotlib = True
64+ global _application
65+ _application = None
66+
67+
68+ def _create_application ():
69+ global _application
70+
71+ if _application is None :
72+ app = Gio .Application .get_default ()
73+ if app is None or getattr (app , '_created_by_matplotlib' ):
74+ # display_is_valid returns False only if on Linux and neither X11
75+ # nor Wayland display can be opened.
76+ if not mpl ._c_internal_utils .display_is_valid ():
77+ raise RuntimeError ('Invalid DISPLAY variable' )
78+ _application = Gtk .Application .new ('org.matplotlib.Matplotlib3' ,
79+ Gio .ApplicationFlags .NON_UNIQUE )
80+ # The activate signal must be connected, but we don't care for
81+ # handling it, since we don't do any remote processing.
82+ _application .connect ('activate' , lambda * args , ** kwargs : None )
83+ _application .connect ('shutdown' , _shutdown_application )
84+ _application .register ()
85+ cbook ._setup_new_guiapp ()
86+ else :
87+ _application = app
88+
5089
5190@functools .lru_cache ()
5291def _mpl_to_gtk_cursor (mpl_cursor ):
@@ -293,11 +332,9 @@ def idle_draw(*args):
293332
294333 def flush_events (self ):
295334 # docstring inherited
296- Gdk .threads_enter ()
297- while Gtk .events_pending ():
298- Gtk .main_iteration ()
299- Gdk .flush ()
300- Gdk .threads_leave ()
335+ context = GLib .MainContext .default ()
336+ while context .pending ():
337+ context .iteration (True )
301338
302339
303340class FigureManagerGTK3 (FigureManagerBase ):
@@ -317,7 +354,9 @@ class FigureManagerGTK3(FigureManagerBase):
317354
318355 """
319356 def __init__ (self , canvas , num ):
357+ _create_application ()
320358 self .window = Gtk .Window ()
359+ _application .add_window (self .window )
321360 super ().__init__ (canvas , num )
322361
323362 self .window .set_wmclass ("matplotlib" , "Matplotlib" )
@@ -379,10 +418,6 @@ def destroy(self, *args):
379418 if self .toolbar :
380419 self .toolbar .destroy ()
381420
382- if (Gcf .get_num_fig_managers () == 0 and not mpl .is_interactive () and
383- Gtk .main_level () >= 1 ):
384- Gtk .main_quit ()
385-
386421 def show (self ):
387422 # show the figure window
388423 self .window .show ()
@@ -499,7 +534,8 @@ def set_cursor(self, cursor):
499534 window = self .canvas .get_property ("window" )
500535 if window is not None :
501536 window .set_cursor (_mpl_to_gtk_cursor (cursor ))
502- Gtk .main_iteration ()
537+ context = GLib .MainContext .default ()
538+ context .iteration (True )
503539
504540 def draw_rubberband (self , event , x0 , y0 , x1 , y1 ):
505541 height = self .canvas .figure .bbox .height
@@ -826,6 +862,12 @@ class _BackendGTK3(_Backend):
826862
827863 @staticmethod
828864 def mainloop ():
829- if Gtk .main_level () == 0 :
830- cbook ._setup_new_guiapp ()
831- Gtk .main ()
865+ global _application
866+ if _application is None :
867+ return
868+
869+ try :
870+ _application .run () # Quits when all added windows close.
871+ finally :
872+ # Running after quit is undefined, so create a new one next time.
873+ _application = None
0 commit comments