From f865c09b952029c6898a2b36f639829704409fbd Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 29 Dec 2017 15:52:00 -0800 Subject: [PATCH] Add detection of OSX NSApp event loop. --- lib/matplotlib/backends/__init__.py | 13 ++++++++++++- src/_macosx.m | 21 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/backends/__init__.py b/lib/matplotlib/backends/__init__.py index e7dee06f0c01..e8aabac04b9c 100644 --- a/lib/matplotlib/backends/__init__.py +++ b/lib/matplotlib/backends/__init__.py @@ -25,7 +25,8 @@ def _get_current_event_loop(): Returns ------- Optional[str] - A value in {"qt5", "qt4", "gtk3", "gtk2", "tk", "headless", None} + One of the following values: "qt5", "qt4", "gtk3", "gtk2", "tk", + "macosx", "headless", ``None``. """ QtWidgets = (sys.modules.get("PyQt5.QtWidgets") or sys.modules.get("PySide2.QtWidgets")) @@ -48,6 +49,16 @@ def _get_current_event_loop(): and frame.f_code.co_name == "mainloop" for frame in sys._current_frames().values()): return "tk" + try: + from matplotlib.backends import _macosx + except ImportError: + pass + else: + # Note that the NSApp event loop is also running when a non-native + # toolkit (e.g. Qt5) is active, but in that case we want to report the + # other toolkit; thus, this check comes after the other toolkits. + if _macosx.event_loop_is_running(): + return "macosx" if sys.platform.startswith("linux") and not os.environ.get("DISPLAY"): return "headless" diff --git a/src/_macosx.m b/src/_macosx.m index 6ac728ae57d1..57762f2b2226 100644 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -2818,6 +2818,16 @@ - (int)index } @end +static PyObject* +event_loop_is_running(PyObject* self) +{ + if ([NSApp isRunning]) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + static PyObject* show(PyObject* self) { @@ -3072,10 +3082,17 @@ static bool verify_framework(void) } static struct PyMethodDef methods[] = { + {"event_loop_is_running", + (PyCFunction)event_loop_is_running, + METH_NOARGS, + "Return whether the NSApp main event loop is currently running." + }, {"show", (PyCFunction)show, METH_NOARGS, - "Show all the figures and enter the main loop.\nThis function does not return until all Matplotlib windows are closed,\nand is normally not needed in interactive sessions." + "Show all the figures and enter the main loop.\n" + "This function does not return until all Matplotlib windows are closed,\n" + "and is normally not needed in interactive sessions." }, {"choose_save_file", (PyCFunction)choose_save_file, @@ -3087,7 +3104,7 @@ static bool verify_framework(void) METH_VARARGS, "Sets the active cursor." }, - {NULL, NULL, 0, NULL}/* sentinel */ + {NULL, NULL, 0, NULL} /* sentinel */ }; #if PY3K