Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e039d69

Browse files
authored
Merge pull request #20284 from QuLogic/gtk-app
Use a GtkApplication in GTK backend.
2 parents 7d50020 + 1368c6b commit e039d69

File tree

1 file changed

+55
-13
lines changed

1 file changed

+55
-13
lines changed

lib/matplotlib/backends/backend_gtk3.py

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,45 @@
4747
except 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()
5291
def _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

303340
class 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

Comments
 (0)