Skip to content

Commit 139a4db

Browse files
committed
Move common GTK Backend code into a separate file.
1 parent 0b724bf commit 139a4db

File tree

3 files changed

+88
-115
lines changed

3 files changed

+88
-115
lines changed
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""
2+
Common code for GTK3 and GTK4 backends.
3+
"""
4+
5+
import logging
6+
7+
import matplotlib as mpl
8+
from matplotlib import cbook
9+
from matplotlib.backend_bases import (
10+
_Backend,
11+
)
12+
13+
# The GTK3/GTK4 backends will have already called `gi.require_version` to set
14+
# the desired GTK.
15+
from gi.repository import Gio, Gtk
16+
17+
18+
_log = logging.getLogger(__name__)
19+
20+
backend_version = "%s.%s.%s" % (
21+
Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version())
22+
23+
# Placeholder
24+
_application = None
25+
26+
27+
def _shutdown_application(app):
28+
# The application might prematurely shut down if Ctrl-C'd out of IPython,
29+
# so close all windows.
30+
for win in app.get_windows():
31+
win.destroy()
32+
# The PyGObject wrapper incorrectly thinks that None is not allowed, or we
33+
# would call this:
34+
# Gio.Application.set_default(None)
35+
# Instead, we set this property and ignore default applications with it:
36+
app._created_by_matplotlib = True
37+
global _application
38+
_application = None
39+
40+
41+
def _create_application():
42+
global _application
43+
44+
if _application is None:
45+
app = Gio.Application.get_default()
46+
if app is None or getattr(app, '_created_by_matplotlib'):
47+
# display_is_valid returns False only if on Linux and neither X11
48+
# nor Wayland display can be opened.
49+
if not mpl._c_internal_utils.display_is_valid():
50+
raise RuntimeError('Invalid DISPLAY variable')
51+
_application = Gtk.Application.new('org.matplotlib.Matplotlib3',
52+
Gio.ApplicationFlags.NON_UNIQUE)
53+
# The activate signal must be connected, but we don't care for
54+
# handling it, since we don't do any remote processing.
55+
_application.connect('activate', lambda *args, **kwargs: None)
56+
_application.connect('shutdown', _shutdown_application)
57+
_application.register()
58+
cbook._setup_new_guiapp()
59+
else:
60+
_application = app
61+
62+
return _application
63+
64+
65+
class _BackendGTK(_Backend):
66+
@staticmethod
67+
def mainloop():
68+
global _application
69+
if _application is None:
70+
return
71+
72+
try:
73+
_application.run() # Quits when all added windows close.
74+
finally:
75+
# Running after quit is undefined, so create a new one next time.
76+
_application = None

lib/matplotlib/backends/backend_gtk3.py

+6-58
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@
2929
raise ImportError from e
3030

3131
from gi.repository import Gio, GLib, GObject, Gtk, Gdk
32+
from ._backend_gtk import (
33+
_create_application, _shutdown_application,
34+
backend_version, _BackendGTK)
3235

3336

3437
_log = logging.getLogger(__name__)
3538

36-
backend_version = "%s.%s.%s" % (
37-
Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version())
38-
3939

4040
@_api.caching_module_getattr # module-level deprecations
4141
class __getattr__:
@@ -56,46 +56,6 @@ def cursord(self):
5656
return {}
5757

5858

59-
# Placeholder
60-
_application = None
61-
62-
63-
def _shutdown_application(app):
64-
# The application might prematurely shut down if Ctrl-C'd out of IPython,
65-
# so close all windows.
66-
for win in app.get_windows():
67-
win.destroy()
68-
# The PyGObject wrapper incorrectly thinks that None is not allowed, or we
69-
# would call this:
70-
# Gio.Application.set_default(None)
71-
# Instead, we set this property and ignore default applications with it:
72-
app._created_by_matplotlib = True
73-
global _application
74-
_application = None
75-
76-
77-
def _create_application():
78-
global _application
79-
80-
if _application is None:
81-
app = Gio.Application.get_default()
82-
if app is None or getattr(app, '_created_by_matplotlib'):
83-
# display_is_valid returns False only if on Linux and neither X11
84-
# nor Wayland display can be opened.
85-
if not mpl._c_internal_utils.display_is_valid():
86-
raise RuntimeError('Invalid DISPLAY variable')
87-
_application = Gtk.Application.new('org.matplotlib.Matplotlib3',
88-
Gio.ApplicationFlags.NON_UNIQUE)
89-
# The activate signal must be connected, but we don't care for
90-
# handling it, since we don't do any remote processing.
91-
_application.connect('activate', lambda *args, **kwargs: None)
92-
_application.connect('shutdown', _shutdown_application)
93-
_application.register()
94-
cbook._setup_new_guiapp()
95-
else:
96-
_application = app
97-
98-
9959
@functools.lru_cache()
10060
def _mpl_to_gtk_cursor(mpl_cursor):
10161
name = _api.check_getitem({
@@ -373,9 +333,9 @@ class FigureManagerGTK3(FigureManagerBase):
373333
374334
"""
375335
def __init__(self, canvas, num):
376-
_create_application()
336+
app = _create_application()
377337
self.window = Gtk.Window()
378-
_application.add_window(self.window)
338+
app.add_window(self.window)
379339
super().__init__(canvas, num)
380340

381341
self.window.set_wmclass("matplotlib", "Matplotlib")
@@ -868,18 +828,6 @@ def error_msg_gtk(msg, parent=None):
868828

869829

870830
@_Backend.export
871-
class _BackendGTK3(_Backend):
831+
class _BackendGTK3(_BackendGTK):
872832
FigureCanvas = FigureCanvasGTK3
873833
FigureManager = FigureManagerGTK3
874-
875-
@staticmethod
876-
def mainloop():
877-
global _application
878-
if _application is None:
879-
return
880-
881-
try:
882-
_application.run() # Quits when all added windows close.
883-
finally:
884-
# Running after quit is undefined, so create a new one next time.
885-
_application = None

lib/matplotlib/backends/backend_gtk4.py

+6-57
Original file line numberDiff line numberDiff line change
@@ -30,52 +30,13 @@
3030
raise ImportError from e
3131

3232
from gi.repository import Gio, GLib, GObject, Gtk, Gdk, GdkPixbuf
33+
from ._backend_gtk import (
34+
_create_application, _shutdown_application,
35+
backend_version, _BackendGTK)
3336

3437

3538
_log = logging.getLogger(__name__)
3639

37-
backend_version = "%s.%s.%s" % (
38-
Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version())
39-
40-
# Placeholder
41-
_application = None
42-
43-
44-
def _shutdown_application(app):
45-
# The application might prematurely shut down if Ctrl-C'd out of IPython,
46-
# so close all windows.
47-
for win in app.get_windows():
48-
win.destroy()
49-
# The PyGObject wrapper incorrectly thinks that None is not allowed, or we
50-
# would call this:
51-
# Gio.Application.set_default(None)
52-
# Instead, we set this property and ignore default applications with it:
53-
app._created_by_matplotlib = True
54-
global _application
55-
_application = None
56-
57-
58-
def _create_application():
59-
global _application
60-
61-
if _application is None:
62-
app = Gio.Application.get_default()
63-
if app is None or getattr(app, '_created_by_matplotlib'):
64-
# display_is_valid returns False only if on Linux and neither X11
65-
# nor Wayland display can be opened.
66-
if not mpl._c_internal_utils.display_is_valid():
67-
raise RuntimeError('Invalid DISPLAY variable')
68-
_application = Gtk.Application.new('org.matplotlib.Matplotlib3',
69-
Gio.ApplicationFlags.NON_UNIQUE)
70-
# The activate signal must be connected, but we don't care for
71-
# handling it, since we don't do any remote processing.
72-
_application.connect('activate', lambda *args, **kwargs: None)
73-
_application.connect('shutdown', _shutdown_application)
74-
_application.register()
75-
cbook._setup_new_guiapp()
76-
else:
77-
_application = app
78-
7940

8041
def _mpl_to_gtk_cursor(mpl_cursor):
8142
return _api.check_getitem({
@@ -330,9 +291,9 @@ class FigureManagerGTK4(FigureManagerBase):
330291
331292
"""
332293
def __init__(self, canvas, num):
333-
_create_application()
294+
app = _create_application()
334295
self.window = Gtk.Window()
335-
_application.add_window(self.window)
296+
app.add_window(self.window)
336297
super().__init__(canvas, num)
337298

338299
try:
@@ -815,18 +776,6 @@ def trigger(self, *args, **kwargs):
815776

816777

817778
@_Backend.export
818-
class _BackendGTK4(_Backend):
779+
class _BackendGTK4(_BackendGTK):
819780
FigureCanvas = FigureCanvasGTK4
820781
FigureManager = FigureManagerGTK4
821-
822-
@staticmethod
823-
def mainloop():
824-
global _application
825-
if _application is None:
826-
return
827-
828-
try:
829-
_application.run() # Quits when all added windows close.
830-
finally:
831-
# Running after quit is undefined, so create a new one next time.
832-
_application = None

0 commit comments

Comments
 (0)