Skip to content

Commit f7a432a

Browse files
committed
Factor out some macosx gil handling for py-method calls from callbacks.
Also, explicitly checking for whether zoombutton/panbutton are non-null is unnecessary, as objc explicitly defines sending a message to null as a noop. Also, they should never be nil anyways...
1 parent c19cca7 commit f7a432a

File tree

1 file changed

+37
-118
lines changed

1 file changed

+37
-118
lines changed

src/_macosx.m

+37-118
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,20 @@ - (BOOL)acceptsFirstResponder;
252252

253253
/* ---------------------------- Python classes ---------------------------- */
254254

255+
// Acquire the GIL, call a method with no args, discarding the result and
256+
// printing any exception.
257+
static void gil_call_method(PyObject* obj, const char* name)
258+
{
259+
PyGILState_STATE gstate = PyGILState_Ensure();
260+
PyObject* result = PyObject_CallMethod(obj, name, NULL);
261+
if (result) {
262+
Py_DECREF(result);
263+
} else {
264+
PyErr_Print();
265+
}
266+
PyGILState_Release(gstate);
267+
}
268+
255269
static bool backend_inited = false;
256270

257271
static void lazy_init(void) {
@@ -837,13 +851,13 @@ static CGFloat _get_device_scale(CGContextRef cr)
837851
FigureManager_new, /* tp_new */
838852
};
839853

840-
@interface NavigationToolbar2Handler : NSObject
841-
{ PyObject* toolbar;
854+
@interface NavigationToolbar2Handler : NSObject {
855+
PyObject* toolbar;
842856
NSButton* panbutton;
843857
NSButton* zoombutton;
844858
}
845859
- (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)toolbar;
846-
- (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons;
860+
- (void)installCallbacks:(SEL[7])actions forButtons:(NSButton*[7])buttons;
847861
- (void)home:(id)sender;
848862
- (void)back:(id)sender;
849863
- (void)forward:(id)sender;
@@ -863,118 +877,43 @@ - (void)save_figure:(id)sender;
863877

864878
@implementation NavigationToolbar2Handler
865879
- (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)theToolbar
866-
{ [self init];
880+
{
881+
[self init];
867882
toolbar = theToolbar;
868883
return self;
869884
}
870885

871-
- (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons
886+
- (void)installCallbacks:(SEL[7])actions forButtons:(NSButton*[7])buttons
872887
{
873888
int i;
874-
for (i = 0; i < 7; i++)
875-
{
889+
for (i = 0; i < 7; i++) {
876890
SEL action = actions[i];
877891
NSButton* button = buttons[i];
878892
[button setTarget: self];
879893
[button setAction: action];
880-
if (action==@selector(pan:)) { panbutton = button; }
881-
if (action==@selector(zoom:)) { zoombutton = button; }
894+
if (action == @selector(pan:)) { panbutton = button; }
895+
if (action == @selector(zoom:)) { zoombutton = button; }
882896
}
883897
}
884898

885-
-(void)home:(id)sender
886-
{ PyObject* result;
887-
PyGILState_STATE gstate;
888-
gstate = PyGILState_Ensure();
889-
result = PyObject_CallMethod(toolbar, "home", "");
890-
if (result)
891-
Py_DECREF(result);
892-
else
893-
PyErr_Print();
894-
PyGILState_Release(gstate);
895-
}
896-
897-
-(void)back:(id)sender
898-
{ PyObject* result;
899-
PyGILState_STATE gstate;
900-
gstate = PyGILState_Ensure();
901-
result = PyObject_CallMethod(toolbar, "back", "");
902-
if (result)
903-
Py_DECREF(result);
904-
else
905-
PyErr_Print();
906-
PyGILState_Release(gstate);
907-
}
908-
909-
-(void)forward:(id)sender
910-
{ PyObject* result;
911-
PyGILState_STATE gstate;
912-
gstate = PyGILState_Ensure();
913-
result = PyObject_CallMethod(toolbar, "forward", "");
914-
if (result)
915-
Py_DECREF(result);
916-
else
917-
PyErr_Print();
918-
PyGILState_Release(gstate);
919-
}
899+
-(void)home:(id)sender { gil_call_method(toolbar, "home"); }
900+
-(void)back:(id)sender { gil_call_method(toolbar, "back"); }
901+
-(void)forward:(id)sender { gil_call_method(toolbar, "forward"); }
920902

921903
-(void)pan:(id)sender
922-
{ PyObject* result;
923-
PyGILState_STATE gstate;
924-
if ([sender state])
925-
{
926-
if (zoombutton) [zoombutton setState: NO];
927-
}
928-
gstate = PyGILState_Ensure();
929-
result = PyObject_CallMethod(toolbar, "pan", "");
930-
if (result)
931-
Py_DECREF(result);
932-
else
933-
PyErr_Print();
934-
PyGILState_Release(gstate);
904+
{
905+
if ([sender state]) { [zoombutton setState:NO]; }
906+
gil_call_method(toolbar, "pan");
935907
}
936908

937909
-(void)zoom:(id)sender
938-
{ PyObject* result;
939-
PyGILState_STATE gstate;
940-
if ([sender state])
941-
{
942-
if (panbutton) [panbutton setState: NO];
943-
}
944-
gstate = PyGILState_Ensure();
945-
result = PyObject_CallMethod(toolbar, "zoom", "");
946-
if (result)
947-
Py_DECREF(result);
948-
else
949-
PyErr_Print();
950-
PyGILState_Release(gstate);
951-
}
952-
953-
-(void)configure_subplots:(id)sender
954910
{
955-
PyObject* result;
956-
PyGILState_STATE gstate;
957-
gstate = PyGILState_Ensure();
958-
result = PyObject_CallMethod(toolbar, "configure_subplots", NULL);
959-
if (result) {
960-
Py_DECREF(result);
961-
} else {
962-
PyErr_Print();
963-
}
964-
PyGILState_Release(gstate);
911+
if ([sender state]) { [panbutton setState:NO]; }
912+
gil_call_method(toolbar, "zoom");
965913
}
966914

967-
-(void)save_figure:(id)sender
968-
{ PyObject* result;
969-
PyGILState_STATE gstate;
970-
gstate = PyGILState_Ensure();
971-
result = PyObject_CallMethod(toolbar, "save_figure", "");
972-
if (result)
973-
Py_DECREF(result);
974-
else
975-
PyErr_Print();
976-
PyGILState_Release(gstate);
977-
}
915+
-(void)configure_subplots:(id)sender { gil_call_method(toolbar, "configure_subplots"); }
916+
-(void)save_figure:(id)sender { gil_call_method(toolbar, "save_figure"); }
978917
@end
979918

980919
static PyObject*
@@ -1352,19 +1291,7 @@ - (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen
13521291
return suggested;
13531292
}
13541293

1355-
- (BOOL)closeButtonPressed
1356-
{
1357-
PyObject* result;
1358-
PyGILState_STATE gstate;
1359-
gstate = PyGILState_Ensure();
1360-
result = PyObject_CallMethod(manager, "close", "");
1361-
if (result)
1362-
Py_DECREF(result);
1363-
else
1364-
PyErr_Print();
1365-
PyGILState_Release(gstate);
1366-
return YES;
1367-
}
1294+
- (BOOL)closeButtonPressed { gil_call_method(manager, "close"); }
13681295

13691296
- (void)close
13701297
{
@@ -1966,15 +1893,7 @@ - (void)flagsChanged:(NSEvent*)event
19661893

19671894
static void timer_callback(CFRunLoopTimerRef timer, void* info)
19681895
{
1969-
PyObject* method = info;
1970-
PyGILState_STATE gstate = PyGILState_Ensure();
1971-
PyObject* result = PyObject_CallFunction(method, NULL);
1972-
if (result) {
1973-
Py_DECREF(result);
1974-
} else {
1975-
PyErr_Print();
1976-
}
1977-
PyGILState_Release(gstate);
1896+
gil_call_method(info, "_on_timer");
19781897
}
19791898

19801899
static void context_cleanup(const void* info)
@@ -2013,12 +1932,12 @@ static void context_cleanup(const void* info)
20131932
PyErr_SetString(PyExc_RuntimeError, "_on_timer should be a Python method");
20141933
goto exit;
20151934
}
2016-
Py_INCREF(py_on_timer);
1935+
Py_INCREF(self);
20171936
context.version = 0;
20181937
context.retain = NULL;
20191938
context.release = context_cleanup;
20201939
context.copyDescription = NULL;
2021-
context.info = py_on_timer;
1940+
context.info = self;
20221941
timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
20231942
firstFire,
20241943
interval,

0 commit comments

Comments
 (0)