From b70fde792262053f7ad9b580b6fa470eeca1f9a1 Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Wed, 18 Feb 2026 14:47:35 +0100 Subject: [PATCH 1/5] feat: added methods for managing window size and position of macos backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FigureManager_init (line 611–616) — now uses PyArg_ParseTupleAndKeywords with optional x (default 100) and y (default 350) float kwargs, passed through to NSMakeRect. 5 new C functions (lines 813–873), inserted just before FigureManagerType: ┌────────────────────────────────────┬────────────────────────────────────────────────────────────────┐ │ Function │ NSWindow/NSScreen call │ ├────────────────────────────────────┼────────────────────────────────────────────────────────────────┤ │ FigureManager_get_window_frame │ [window frame] → (x, y, w, h) as 4 doubles │ ├────────────────────────────────────┼────────────────────────────────────────────────────────────────┤ │ FigureManager_set_window_frame │ [window setFrame: NSMakeRect(...) display: YES] │ ├────────────────────────────────────┼────────────────────────────────────────────────────────────────┤ │ FigureManager_get_screen_frame │ [[window screen] frame] → (x, y, w, h) │ ├────────────────────────────────────┼────────────────────────────────────────────────────────────────┤ │ FigureManager_get_window_screen_id │ NSScreenNumber from deviceDescription → CGDirectDisplayID │ ├────────────────────────────────────┼────────────────────────────────────────────────────────────────┤ │ FigureManager_set_window_level │ [window setLevel: NSFloatingWindowLevel / NSNormalWin dowLevel] │ └────────────────────────────────────┴────────────────────────────────────────────────────────────────┘ tp_methods table (lines 917–931) — 5 new entries added. lib/matplotlib/backends/_macosx.pyi Full type stubs for FigureManager covering all existing and new methods. lib/matplotlib/backends/backend_macosx.py FigureManagerMac.__init__ now accepts *, x=None, y=None and forwards them to the C __init__ when provided. --- lib/matplotlib/backends/_macosx.pyi | 17 +++++ lib/matplotlib/backends/backend_macosx.py | 9 ++- src/_macosx.m | 84 ++++++++++++++++++++++- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/_macosx.pyi b/lib/matplotlib/backends/_macosx.pyi index e69de29bb2d1..1936460f07f1 100644 --- a/lib/matplotlib/backends/_macosx.pyi +++ b/lib/matplotlib/backends/_macosx.pyi @@ -0,0 +1,17 @@ +class FigureManager: + def __init__(self, canvas: object, x: float = ..., y: float = ...) -> None: ... + def _show(self) -> None: ... + def _raise(self) -> None: ... + def destroy(self) -> None: ... + def _set_window_mode(self, mode: str) -> None: ... + @staticmethod + def set_icon(filename: str) -> None: ... + def set_window_title(self, title: str) -> None: ... + def get_window_title(self) -> str | None: ... + def resize(self, width: int, height: int) -> None: ... + def full_screen_toggle(self) -> None: ... + def get_window_frame(self) -> tuple[float, float, float, float]: ... + def set_window_frame(self, x: float, y: float, w: float, h: float) -> None: ... + def get_screen_frame(self) -> tuple[float, float, float, float]: ... + def get_window_screen_id(self) -> int: ... + def set_window_level(self, floating: bool) -> None: ... diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index 6ea437a90ca1..585fc2b312f7 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -148,9 +148,14 @@ def save_figure(self, *args): class FigureManagerMac(_macosx.FigureManager, FigureManagerBase): _toolbar2_class = NavigationToolbar2Mac - def __init__(self, canvas, num): + def __init__(self, canvas, num, *, x=None, y=None): self._shown = False - _macosx.FigureManager.__init__(self, canvas) + kwargs = {} + if x is not None: + kwargs['x'] = x + if y is not None: + kwargs['y'] = y + _macosx.FigureManager.__init__(self, canvas, **kwargs) icon_path = str(cbook._get_data_path('images/matplotlib.pdf')) _macosx.FigureManager.set_icon(icon_path) FigureManagerBase.__init__(self, canvas, num) diff --git a/src/_macosx.m b/src/_macosx.m index 0de0540018a7..3af1e91a56ef 100755 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -703,7 +703,10 @@ bool mpl_check_modifier(bool present, PyObject* list, char const* name) { BEGIN_OBJC_ENTRY PyObject* canvas; - if (!PyArg_ParseTuple(args, "O", &canvas)) { + double x = 100., y = 350.; + static char *kwlist[] = {"canvas", "x", "y", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|dd", kwlist, + &canvas, &x, &y)) { return -1; } @@ -721,7 +724,7 @@ bool mpl_check_modifier(bool present, PyObject* list, char const* name) } Py_DECREF(size); - NSRect rect = NSMakeRect( /* x */ 100, /* y */ 350, width, height); + NSRect rect = NSMakeRect(x, y, width, height); self->window = [self->window initWithContentRect: rect styleMask: NSWindowStyleMaskTitled @@ -924,6 +927,68 @@ bool mpl_check_modifier(bool present, PyObject* list, char const* name) RETURN_NULL_OR_NONE } +static PyObject* +FigureManager_get_window_frame(FigureManager* self) +{ + NSRect frame = [self->window frame]; + return Py_BuildValue("dddd", + frame.origin.x, frame.origin.y, + frame.size.width, frame.size.height); +} + +static PyObject* +FigureManager_set_window_frame(FigureManager* self, PyObject* args) +{ + double x, y, w, h; + if (!PyArg_ParseTuple(args, "dddd", &x, &y, &w, &h)) { + return NULL; + } + [self->window setFrame: NSMakeRect(x, y, w, h) display: YES]; + Py_RETURN_NONE; +} + +static PyObject* +FigureManager_get_screen_frame(FigureManager* self) +{ + NSScreen* screen = [self->window screen]; + if (!screen) { + PyErr_SetString(PyExc_RuntimeError, + "Window is not associated with any screen"); + return NULL; + } + NSRect frame = [screen frame]; + return Py_BuildValue("dddd", + frame.origin.x, frame.origin.y, + frame.size.width, frame.size.height); +} + +static PyObject* +FigureManager_get_window_screen_id(FigureManager* self) +{ + NSScreen* screen = [self->window screen]; + if (!screen) { + PyErr_SetString(PyExc_RuntimeError, + "Window is not associated with any screen"); + return NULL; + } + CGDirectDisplayID displayID = + [[[screen deviceDescription] objectForKey: @"NSScreenNumber"] + unsignedIntValue]; + return PyLong_FromUnsignedLong((unsigned long)displayID); +} + +static PyObject* +FigureManager_set_window_level(FigureManager* self, PyObject* args) +{ + int floating; + if (!PyArg_ParseTuple(args, "p", &floating)) { + return NULL; + } + [self->window setLevel: floating ? NSFloatingWindowLevel + : NSNormalWindowLevel]; + Py_RETURN_NONE; +} + static PyTypeObject FigureManagerType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "matplotlib.backends._macosx.FigureManager", @@ -966,6 +1031,21 @@ bool mpl_check_modifier(bool present, PyObject* list, char const* name) {"full_screen_toggle", (PyCFunction)FigureManager_full_screen_toggle, METH_NOARGS}, + {"get_window_frame", + (PyCFunction)FigureManager_get_window_frame, + METH_NOARGS}, + {"set_window_frame", + (PyCFunction)FigureManager_set_window_frame, + METH_VARARGS}, + {"get_screen_frame", + (PyCFunction)FigureManager_get_screen_frame, + METH_NOARGS}, + {"get_window_screen_id", + (PyCFunction)FigureManager_get_window_screen_id, + METH_NOARGS}, + {"set_window_level", + (PyCFunction)FigureManager_set_window_level, + METH_VARARGS}, {} // sentinel }, }; From ec85a82aa1aafff1b0567d3607a0c925d4e0116b Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Wed, 18 Feb 2026 15:41:46 +0100 Subject: [PATCH 2/5] feat: six new methods on FigureManagerMac: mpl_connect, mpl_disconnect, _window_resize_event, _window_move_event, _focus_in_event, _focus_out_event. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit src/_macosx.m @interface Window — added - (PyObject*)pyManager; declaration. @interface View — added declarations for windowDidMove:, windowDidBecomeKey:, windowDidResignKey:. @implementation Window — added pyManager accessor (lines 1261–1264) between closeButtonPressed and close. windowDidResize: — augmented with a second PyObject_CallMethod on [window pyManager] calling _window_resize_event with (width, height), reusing the already-acquired GIL. Three new delegate methods added after windowDidResize:: - windowDidMove: — calls _window_move_event(x, y) with the window's new Cocoa origin - windowDidBecomeKey: — calls _focus_in_event() via gil_call_method - windowDidResignKey: — calls _focus_out_event() via gil_call_method backend_macosx.py FigureManagerMac.__init__ — initialises self._window_event_callbacks = cbook.CallbackRegistry(). Six new methods on FigureManagerMac: mpl_connect, mpl_disconnect, _window_resize_event, _window_move_event, _focus_in_event, _focus_out_event. --- lib/matplotlib/backends/backend_macosx.py | 40 +++++++++++++++++++++++ src/_macosx.m | 40 +++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index 585fc2b312f7..eae6cfc3d029 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -150,6 +150,7 @@ class FigureManagerMac(_macosx.FigureManager, FigureManagerBase): def __init__(self, canvas, num, *, x=None, y=None): self._shown = False + self._window_event_callbacks = cbook.CallbackRegistry() kwargs = {} if x is not None: kwargs['x'] = x @@ -170,6 +171,45 @@ def _close_button_pressed(self): Gcf.destroy(self) self.canvas.flush_events() + def mpl_connect(self, event_name, callback): + """Register *callback* to be called on a window event. + + Parameters + ---------- + event_name : str + One of ``'window_resize_event'``, ``'window_move_event'``, + ``'focus_in_event'``, ``'focus_out_event'``. + callback : callable + - ``'window_resize_event'``: called with ``(width, height)`` + in logical pixels. + - ``'window_move_event'``: called with ``(x, y)`` in Cocoa + screen coordinates (origin at bottom-left of primary screen). + - ``'focus_in_event'``, ``'focus_out_event'``: called with + no arguments. + + Returns + ------- + int + A callback id that can be passed to `mpl_disconnect`. + """ + return self._window_event_callbacks.connect(event_name, callback) + + def mpl_disconnect(self, cid): + """Remove a callback previously registered with `mpl_connect`.""" + self._window_event_callbacks.disconnect(cid) + + def _window_resize_event(self, width, height): + self._window_event_callbacks.process('window_resize_event', width, height) + + def _window_move_event(self, x, y): + self._window_event_callbacks.process('window_move_event', x, y) + + def _focus_in_event(self): + self._window_event_callbacks.process('focus_in_event') + + def _focus_out_event(self): + self._window_event_callbacks.process('focus_out_event') + def destroy(self): # We need to clear any pending timers that never fired, otherwise # we get a memory leak from the timer callbacks holding a reference diff --git a/src/_macosx.m b/src/_macosx.m index 3af1e91a56ef..561ff002bcc4 100755 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -180,6 +180,7 @@ @interface Window : NSWindow - (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager; - (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen; - (BOOL)closeButtonPressed; +- (PyObject*)pyManager; @end @interface View : NSView @@ -192,6 +193,9 @@ - (void)drawRect:(NSRect)rect; - (void)updateDevicePixelRatio:(double)scale; - (void)windowDidChangeBackingProperties:(NSNotification*)notification; - (void)windowDidResize:(NSNotification*)notification; +- (void)windowDidMove:(NSNotification*)notification; +- (void)windowDidBecomeKey:(NSNotification*)notification; +- (void)windowDidResignKey:(NSNotification*)notification; - (View*)initWithFrame:(NSRect)rect; - (void)setCanvas: (PyObject*)newCanvas; - (void)windowWillClose:(NSNotification*)notification; @@ -1391,6 +1395,11 @@ - (BOOL)closeButtonPressed return YES; } +- (PyObject*)pyManager +{ + return manager; +} + - (void)close { [super close]; @@ -1589,10 +1598,41 @@ - (void)windowDidResize: (NSNotification*)notification Py_DECREF(result); else PyErr_Print(); + result = PyObject_CallMethod( + [window pyManager], "_window_resize_event", "ii", width, height); + if (result) + Py_DECREF(result); + else + PyErr_Print(); PyGILState_Release(gstate); [self setNeedsDisplay: YES]; } +- (void)windowDidMove:(NSNotification*)notification +{ + Window* window = (Window*)[self window]; + NSRect frame = [window frame]; + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject* result = PyObject_CallMethod( + [window pyManager], "_window_move_event", "dd", + frame.origin.x, frame.origin.y); + if (result) + Py_DECREF(result); + else + PyErr_Print(); + PyGILState_Release(gstate); +} + +- (void)windowDidBecomeKey:(NSNotification*)notification +{ + gil_call_method([(Window*)[self window] pyManager], "_focus_in_event"); +} + +- (void)windowDidResignKey:(NSNotification*)notification +{ + gil_call_method([(Window*)[self window] pyManager], "_focus_out_event"); +} + - (void)windowWillClose:(NSNotification*)notification { process_event( From 32c90318f028a9c7734f51ccdf463722737c4885 Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Wed, 18 Feb 2026 16:19:57 +0100 Subject: [PATCH 3/5] feat: added two new dispatcher methods for macos backend: _window_resize_end_event and _window_move_end_event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_macosx.m @interface View — two new ivars (BOOL _in_move, id _move_monitor) and windowDidEndLiveResize: declaration. initWithFrame: — initialises both to NO / nil. dealloc — safety cleanup: if a monitor is still installed when the View is deallocated (e.g. window closed during a drag), it is removed and released before [super dealloc]. windowDidMove: — on the first call (flag is NO), installs a local NSEventTypeLeftMouseUp monitor. The block uses __block View* blockSelf (not retained in MRC, avoiding a permanent retain cycle) and __block id monitor (so the block can reference the monitor to remove it). When the mouse-up fires, the block fires _window_move_end_event, removes and releases the monitor, and clears the flag. windowDidEndLiveResize: (new) — single gil_call_method call to _window_resize_end_event. No flag needed since macOS provides this natively. backend_macosx.py Two new dispatcher methods: _window_resize_end_event and _window_move_end_event. The mpl_connect docstring updated to document all six event names and their callback signatures. --- To test, after rebuilding: mgr.mpl_connect('window_resize_end_event', lambda: print("resize ended — final frame:", mgr.get_window_frame())) mgr.mpl_connect('window_move_end_event', lambda: print("move ended — final pos:", mgr.get_window_frame()[:2])) --- lib/matplotlib/backends/backend_macosx.py | 18 ++++++++++--- src/_macosx.m | 33 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index eae6cfc3d029..381c4890f86f 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -177,13 +177,19 @@ def mpl_connect(self, event_name, callback): Parameters ---------- event_name : str - One of ``'window_resize_event'``, ``'window_move_event'``, + One of ``'window_resize_event'``, ``'window_resize_end_event'``, + ``'window_move_event'``, ``'window_move_end_event'``, ``'focus_in_event'``, ``'focus_out_event'``. callback : callable - ``'window_resize_event'``: called with ``(width, height)`` - in logical pixels. + in logical pixels; fires continuously while resizing. + - ``'window_resize_end_event'``: called with no arguments; + fires once when the user releases the mouse after resizing. - ``'window_move_event'``: called with ``(x, y)`` in Cocoa - screen coordinates (origin at bottom-left of primary screen). + screen coordinates (origin at bottom-left of primary screen); + fires continuously while moving. + - ``'window_move_end_event'``: called with no arguments; + fires once when the user releases the mouse after moving. - ``'focus_in_event'``, ``'focus_out_event'``: called with no arguments. @@ -201,9 +207,15 @@ def mpl_disconnect(self, cid): def _window_resize_event(self, width, height): self._window_event_callbacks.process('window_resize_event', width, height) + def _window_resize_end_event(self): + self._window_event_callbacks.process('window_resize_end_event') + def _window_move_event(self, x, y): self._window_event_callbacks.process('window_move_event', x, y) + def _window_move_end_event(self): + self._window_event_callbacks.process('window_move_end_event') + def _focus_in_event(self): self._window_event_callbacks.process('focus_in_event') diff --git a/src/_macosx.m b/src/_macosx.m index 561ff002bcc4..dde4937db791 100755 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -187,6 +187,8 @@ @interface View : NSView { PyObject* canvas; NSRect rubberband; @public double device_scale; + BOOL _in_move; + id _move_monitor; } - (void)dealloc; - (void)drawRect:(NSRect)rect; @@ -194,6 +196,7 @@ - (void)updateDevicePixelRatio:(double)scale; - (void)windowDidChangeBackingProperties:(NSNotification*)notification; - (void)windowDidResize:(NSNotification*)notification; - (void)windowDidMove:(NSNotification*)notification; +- (void)windowDidEndLiveResize:(NSNotification*)notification; - (void)windowDidBecomeKey:(NSNotification*)notification; - (void)windowDidResignKey:(NSNotification*)notification; - (View*)initWithFrame:(NSRect)rect; @@ -1420,11 +1423,18 @@ - (View*)initWithFrame:(NSRect)rect self = [super initWithFrame: rect]; rubberband = NSZeroRect; device_scale = 1; + _in_move = NO; + _move_monitor = nil; return self; } - (void)dealloc { + if (_move_monitor) { + [NSEvent removeMonitor: _move_monitor]; + [_move_monitor release]; + _move_monitor = nil; + } FigureCanvas* fc = (FigureCanvas*)canvas; if (fc) { fc->view = NULL; } [super dealloc]; @@ -1621,6 +1631,29 @@ - (void)windowDidMove:(NSNotification*)notification else PyErr_Print(); PyGILState_Release(gstate); + + if (!_in_move) { + _in_move = YES; + __block id monitor; + __block View* blockSelf = self; + monitor = [[NSEvent + addLocalMonitorForEventsMatchingMask: NSEventMaskLeftMouseUp + handler: ^NSEvent*(NSEvent* event) { + blockSelf->_in_move = NO; + blockSelf->_move_monitor = nil; + [NSEvent removeMonitor: monitor]; + [monitor release]; + gil_call_method([(Window*)[blockSelf window] pyManager], + "_window_move_end_event"); + return event; + }] retain]; + _move_monitor = monitor; + } +} + +- (void)windowDidEndLiveResize:(NSNotification*)notification +{ + gil_call_method([(Window*)[self window] pyManager], "_window_resize_end_event"); } - (void)windowDidBecomeKey:(NSNotification*)notification From 21286e072dd1aee5411d4970cd2b67d0fe865769 Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Wed, 18 Feb 2026 17:51:33 +0100 Subject: [PATCH 4/5] feat: added a way to enumerate all screens and their global frames Currently get_screen_frame() only tells you about the screen the window is already on. You need the frames of all screens before deciding where to place the window. The fix is to add a module-level function (not a method on FigureManager, since it doesn't depend on any window). --- lib/matplotlib/backends/_macosx.pyi | 2 ++ src/_macosx.m | 32 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lib/matplotlib/backends/_macosx.pyi b/lib/matplotlib/backends/_macosx.pyi index 1936460f07f1..a8f4aef4db97 100644 --- a/lib/matplotlib/backends/_macosx.pyi +++ b/lib/matplotlib/backends/_macosx.pyi @@ -1,3 +1,5 @@ +def get_screens() -> list[tuple[int, float, float, float, float]]: ... + class FigureManager: def __init__(self, canvas: object, x: float = ..., y: float = ...) -> None: ... def _show(self) -> None: ... diff --git a/src/_macosx.m b/src/_macosx.m index dde4937db791..b157d142c3ec 100755 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -2188,6 +2188,31 @@ - (void)flagsChanged:(NSEvent *)event }, }; +static PyObject* +get_screens(PyObject* unused, PyObject* noargs) +{ + NSArray* screens = [NSScreen screens]; + PyObject* list = PyList_New([screens count]); + if (!list) { return NULL; } + for (NSUInteger i = 0; i < [screens count]; i++) { + NSScreen* screen = screens[i]; + CGDirectDisplayID displayID = + [[[screen deviceDescription] objectForKey: @"NSScreenNumber"] + unsignedIntValue]; + NSRect frame = [screen frame]; + PyObject* item = Py_BuildValue("(kdddd)", + (unsigned long)displayID, + frame.origin.x, frame.origin.y, + frame.size.width, frame.size.height); + if (!item) { + Py_DECREF(list); + return NULL; + } + PyList_SET_ITEM(list, i, item); + } + return list; +} + static struct PyModuleDef moduledef = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_macosx", @@ -2221,6 +2246,13 @@ - (void)flagsChanged:(NSEvent *)event (PyCFunction)choose_save_file, METH_VARARGS, PyDoc_STR("Query the user for a location where to save a file.")}, + {"get_screens", + (PyCFunction)get_screens, + METH_NOARGS, + PyDoc_STR( + "Return a list of (display_id, x, y, width, height) for every\n" + "connected screen, in Cocoa screen coordinates (origin at\n" + "bottom-left of the primary screen).")}, {} /* Sentinel */ }, }; From 29573057d9fd6d1dc0e88615a3c367c9bb486916 Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Wed, 18 Feb 2026 23:59:18 +0100 Subject: [PATCH 5/5] feat: add get_window_level() getter to macos backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addendum to b1629448. Adds the missing getter counterpart to set_window_level() — returns True if the window is at NSFloatingWindowLevel (always on top), False if at NSNormalWindowLevel. - FigureManager_get_window_level in _macosx.m - Corresponding entry in tp_methods table - Type stub in _macosx.pyi --- lib/matplotlib/backends/_macosx.pyi | 1 + src/_macosx.m | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/lib/matplotlib/backends/_macosx.pyi b/lib/matplotlib/backends/_macosx.pyi index a8f4aef4db97..61a77ee0de26 100644 --- a/lib/matplotlib/backends/_macosx.pyi +++ b/lib/matplotlib/backends/_macosx.pyi @@ -17,3 +17,4 @@ class FigureManager: def get_screen_frame(self) -> tuple[float, float, float, float]: ... def get_window_screen_id(self) -> int: ... def set_window_level(self, floating: bool) -> None: ... + def get_window_level(self) -> bool: ... diff --git a/src/_macosx.m b/src/_macosx.m index b157d142c3ec..1ecdf3c18e7c 100755 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -996,6 +996,12 @@ bool mpl_check_modifier(bool present, PyObject* list, char const* name) Py_RETURN_NONE; } +static PyObject* +FigureManager_get_window_level(FigureManager* self) +{ + return PyBool_FromLong([self->window level] == NSFloatingWindowLevel); +} + static PyTypeObject FigureManagerType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "matplotlib.backends._macosx.FigureManager", @@ -1053,6 +1059,9 @@ bool mpl_check_modifier(bool present, PyObject* list, char const* name) {"set_window_level", (PyCFunction)FigureManager_set_window_level, METH_VARARGS}, + {"get_window_level", + (PyCFunction)FigureManager_get_window_level, + METH_NOARGS}, {} // sentinel }, };