aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/matplotlib/py2/src/_macosx.m
diff options
context:
space:
mode:
authormaxim-yurchuk <maxim-yurchuk@yandex-team.com>2024-10-09 12:29:46 +0300
committermaxim-yurchuk <maxim-yurchuk@yandex-team.com>2024-10-09 13:14:22 +0300
commit9731d8a4bb7ee2cc8554eaf133bb85498a4c7d80 (patch)
treea8fb3181d5947c0d78cf402aa56e686130179049 /contrib/python/matplotlib/py2/src/_macosx.m
parenta44b779cd359f06c3ebbef4ec98c6b38609d9d85 (diff)
downloadydb-9731d8a4bb7ee2cc8554eaf133bb85498a4c7d80.tar.gz
publishFullContrib: true for ydb
<HIDDEN_URL> commit_hash:c82a80ac4594723cebf2c7387dec9c60217f603e
Diffstat (limited to 'contrib/python/matplotlib/py2/src/_macosx.m')
-rw-r--r--contrib/python/matplotlib/py2/src/_macosx.m3174
1 files changed, 3174 insertions, 0 deletions
diff --git a/contrib/python/matplotlib/py2/src/_macosx.m b/contrib/python/matplotlib/py2/src/_macosx.m
new file mode 100644
index 0000000000..8f44f1eb0c
--- /dev/null
+++ b/contrib/python/matplotlib/py2/src/_macosx.m
@@ -0,0 +1,3174 @@
+#include <Cocoa/Cocoa.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <sys/socket.h>
+#include <Python.h>
+
+#define PYOSINPUTHOOK_REPETITIVE 1 /* Remove this once Python is fixed */
+
+#if PY_MAJOR_VERSION >= 3
+#define PY3K 1
+#else
+#define PY3K 0
+#endif
+
+/* Proper way to check for the OS X version we are compiling for, from
+ http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development */
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+#define COMPILING_FOR_10_6
+#endif
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+#define COMPILING_FOR_10_7
+#endif
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 10100
+#define COMPILING_FOR_10_10
+#endif
+
+
+/* CGFloat was defined in Mac OS X 10.5 */
+#ifndef CGFLOAT_DEFINED
+#define CGFloat float
+#endif
+
+
+/* Various NSApplicationDefined event subtypes */
+#define STOP_EVENT_LOOP 2
+#define WINDOW_CLOSING 3
+
+
+/* Keep track of number of windows present
+ Needed to know when to stop the NSApp */
+static long FigureWindowCount = 0;
+
+/* -------------------------- Helper function ---------------------------- */
+
+static void
+_stdin_callback(CFReadStreamRef stream, CFStreamEventType eventType, void* info)
+{
+ CFRunLoopRef runloop = info;
+ CFRunLoopStop(runloop);
+}
+
+static int sigint_fd = -1;
+
+static void _sigint_handler(int sig)
+{
+ const char c = 'i';
+ write(sigint_fd, &c, 1);
+}
+
+static void _sigint_callback(CFSocketRef s,
+ CFSocketCallBackType type,
+ CFDataRef address,
+ const void * data,
+ void *info)
+{
+ char c;
+ int* interrupted = info;
+ CFSocketNativeHandle handle = CFSocketGetNative(s);
+ CFRunLoopRef runloop = CFRunLoopGetCurrent();
+ read(handle, &c, 1);
+ *interrupted = 1;
+ CFRunLoopStop(runloop);
+}
+
+static CGEventRef _eventtap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
+{
+ CFRunLoopRef runloop = refcon;
+ CFRunLoopStop(runloop);
+ return event;
+}
+
+static int wait_for_stdin(void)
+{
+ int interrupted = 0;
+ const UInt8 buffer[] = "/dev/fd/0";
+ const CFIndex n = (CFIndex)strlen((char*)buffer);
+ CFRunLoopRef runloop = CFRunLoopGetCurrent();
+ CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ buffer,
+ n,
+ false);
+ CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
+ url);
+ CFRelease(url);
+
+ CFReadStreamOpen(stream);
+#ifdef PYOSINPUTHOOK_REPETITIVE
+ if (!CFReadStreamHasBytesAvailable(stream))
+ /* This is possible because of how PyOS_InputHook is called from Python */
+ {
+#endif
+ int error;
+ int channel[2];
+ CFSocketRef sigint_socket = NULL;
+ PyOS_sighandler_t py_sigint_handler = NULL;
+ CFStreamClientContext clientContext = {0, NULL, NULL, NULL, NULL};
+ clientContext.info = runloop;
+ CFReadStreamSetClient(stream,
+ kCFStreamEventHasBytesAvailable,
+ _stdin_callback,
+ &clientContext);
+ CFReadStreamScheduleWithRunLoop(stream, runloop, kCFRunLoopDefaultMode);
+ error = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
+ if (error==0)
+ {
+ CFSocketContext context;
+ context.version = 0;
+ context.info = &interrupted;
+ context.retain = NULL;
+ context.release = NULL;
+ context.copyDescription = NULL;
+ fcntl(channel[0], F_SETFL, O_WRONLY | O_NONBLOCK);
+ sigint_socket = CFSocketCreateWithNative(
+ kCFAllocatorDefault,
+ channel[1],
+ kCFSocketReadCallBack,
+ _sigint_callback,
+ &context);
+ if (sigint_socket)
+ {
+ CFRunLoopSourceRef source;
+ source = CFSocketCreateRunLoopSource(kCFAllocatorDefault,
+ sigint_socket,
+ 0);
+ CFRelease(sigint_socket);
+ if (source)
+ {
+ CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
+ CFRelease(source);
+ sigint_fd = channel[0];
+ py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler);
+ }
+ }
+ }
+
+ NSEvent* event;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ while (true) {
+ while (true) {
+ event = [NSApp nextEventMatchingMask: NSAnyEventMask
+ untilDate: [NSDate distantPast]
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+ if (!event) break;
+ [NSApp sendEvent: event];
+ }
+ CFRunLoopRun();
+ if (interrupted || CFReadStreamHasBytesAvailable(stream)) break;
+ }
+ [pool release];
+
+ if (py_sigint_handler) PyOS_setsig(SIGINT, py_sigint_handler);
+ CFReadStreamUnscheduleFromRunLoop(stream,
+ runloop,
+ kCFRunLoopCommonModes);
+ if (sigint_socket) CFSocketInvalidate(sigint_socket);
+ if (error==0) {
+ close(channel[0]);
+ close(channel[1]);
+ }
+#ifdef PYOSINPUTHOOK_REPETITIVE
+ }
+#endif
+ CFReadStreamClose(stream);
+ CFRelease(stream);
+ if (interrupted) {
+ errno = EINTR;
+ raise(SIGINT);
+ return -1;
+ }
+ return 1;
+}
+
+/* ---------------------------- Cocoa classes ---------------------------- */
+
+@interface WindowServerConnectionManager : NSObject
+{
+}
++ (WindowServerConnectionManager*)sharedManager;
+- (void)launch:(NSNotification*)notification;
+@end
+
+@interface Window : NSWindow
+{ PyObject* manager;
+}
+- (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;
+- (void)dealloc;
+@end
+
+@interface ToolWindow : NSWindow
+{
+}
+- (ToolWindow*)initWithContentRect:(NSRect)rect master:(NSWindow*)window;
+- (void)masterCloses:(NSNotification*)notification;
+- (void)close;
+@end
+
+#ifdef COMPILING_FOR_10_6
+@interface View : NSView <NSWindowDelegate>
+#else
+@interface View : NSView
+#endif
+{ PyObject* canvas;
+ NSRect rubberband;
+ BOOL inside;
+ NSTrackingRectTag tracking;
+ @public double device_scale;
+}
+- (void)dealloc;
+- (void)drawRect:(NSRect)rect;
+- (void)windowDidResize:(NSNotification*)notification;
+- (View*)initWithFrame:(NSRect)rect;
+- (void)setCanvas: (PyObject*)newCanvas;
+- (void)windowWillClose:(NSNotification*)notification;
+- (BOOL)windowShouldClose:(NSNotification*)notification;
+- (BOOL)isFlipped;
+- (void)mouseEntered:(NSEvent*)event;
+- (void)mouseExited:(NSEvent*)event;
+- (void)mouseDown:(NSEvent*)event;
+- (void)mouseUp:(NSEvent*)event;
+- (void)mouseDragged:(NSEvent*)event;
+- (void)mouseMoved:(NSEvent*)event;
+- (void)rightMouseDown:(NSEvent*)event;
+- (void)rightMouseUp:(NSEvent*)event;
+- (void)rightMouseDragged:(NSEvent*)event;
+- (void)otherMouseDown:(NSEvent*)event;
+- (void)otherMouseUp:(NSEvent*)event;
+- (void)otherMouseDragged:(NSEvent*)event;
+- (void)setRubberband:(NSRect)rect;
+- (void)removeRubberband;
+- (const char*)convertKeyEvent:(NSEvent*)event;
+- (void)keyDown:(NSEvent*)event;
+- (void)keyUp:(NSEvent*)event;
+- (void)scrollWheel:(NSEvent *)event;
+- (BOOL)acceptsFirstResponder;
+//- (void)flagsChanged:(NSEvent*)event;
+@end
+
+@interface ScrollableButton : NSButton
+{
+ SEL scrollWheelUpAction;
+ SEL scrollWheelDownAction;
+}
+- (void)setScrollWheelUpAction:(SEL)action;
+- (void)setScrollWheelDownAction:(SEL)action;
+- (void)scrollWheel:(NSEvent *)event;
+@end
+
+@interface MenuItem: NSMenuItem
+{ int index;
+}
++ (MenuItem*)menuItemWithTitle:(NSString*)title;
++ (MenuItem*)menuItemSelectAll;
++ (MenuItem*)menuItemInvertAll;
++ (MenuItem*)menuItemForAxis:(int)i;
+- (void)toggle:(id)sender;
+- (void)selectAll:(id)sender;
+- (void)invertAll:(id)sender;
+- (int)index;
+@end
+
+/* ---------------------------- Python classes ---------------------------- */
+
+static CGFloat _get_device_scale(CGContextRef cr)
+{
+ CGSize pixelSize = CGContextConvertSizeToDeviceSpace(cr, CGSizeMake(1, 1));
+ return pixelSize.width;
+}
+
+typedef struct {
+ PyObject_HEAD
+ View* view;
+} FigureCanvas;
+
+static PyObject*
+FigureCanvas_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ FigureCanvas *self = (FigureCanvas*)type->tp_alloc(type, 0);
+ if (!self) return NULL;
+ self->view = [View alloc];
+ return (PyObject*)self;
+}
+
+static int
+FigureCanvas_init(FigureCanvas *self, PyObject *args, PyObject *kwds)
+{
+ int width;
+ int height;
+ if(!self->view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return -1;
+ }
+
+ if(!PyArg_ParseTuple(args, "ii", &width, &height)) return -1;
+
+ NSRect rect = NSMakeRect(0.0, 0.0, width, height);
+ self->view = [self->view initWithFrame: rect];
+ [self->view setCanvas: (PyObject*)self];
+ return 0;
+}
+
+static void
+FigureCanvas_dealloc(FigureCanvas* self)
+{
+ if (self->view)
+ {
+ [self->view setCanvas: NULL];
+ [self->view release];
+ }
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject*
+FigureCanvas_repr(FigureCanvas* self)
+{
+#if PY3K
+ return PyUnicode_FromFormat("FigureCanvas object %p wrapping NSView %p",
+ (void*)self, (void*)(self->view));
+#else
+ return PyString_FromFormat("FigureCanvas object %p wrapping NSView %p",
+ (void*)self, (void*)(self->view));
+#endif
+}
+
+static PyObject*
+FigureCanvas_draw(FigureCanvas* self)
+{
+ View* view = self->view;
+
+ if(view) /* The figure may have been closed already */
+ {
+ /* Whereas drawRect creates its own autorelease pool, apparently
+ * [view display] also needs one. Create and release it here. */
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [view display];
+ [pool release];
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureCanvas_invalidate(FigureCanvas* self)
+{
+ View* view = self->view;
+ if(!view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return NULL;
+ }
+ [view setNeedsDisplay: YES];
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureCanvas_flush_events(FigureCanvas* self)
+{
+ View* view = self->view;
+ if(!view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return NULL;
+ }
+ [view displayIfNeeded];
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureCanvas_set_rubberband(FigureCanvas* self, PyObject *args)
+{
+ View* view = self->view;
+ int x0, y0, x1, y1;
+ NSRect rubberband;
+ if(!view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "iiii", &x0, &y0, &x1, &y1)) return NULL;
+
+ x0 /= view->device_scale;
+ x1 /= view->device_scale;
+ y0 /= view->device_scale;
+ y1 /= view->device_scale;
+
+ if (x1 > x0)
+ {
+ rubberband.origin.x = x0;
+ rubberband.size.width = x1 - x0;
+ }
+ else
+ {
+ rubberband.origin.x = x1;
+ rubberband.size.width = x0 - x1;
+ }
+ if (y1 > y0)
+ {
+ rubberband.origin.y = y0;
+ rubberband.size.height = y1 - y0;
+ }
+ else
+ {
+ rubberband.origin.y = y1;
+ rubberband.size.height = y0 - y1;
+ }
+
+ [view setRubberband: rubberband];
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureCanvas_remove_rubberband(FigureCanvas* self)
+{
+ View* view = self->view;
+ if(!view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return NULL;
+ }
+ [view removeRubberband];
+ Py_RETURN_NONE;
+}
+
+static NSImage* _read_ppm_image(PyObject* obj)
+{
+ int width;
+ int height;
+ const char* data;
+ int n;
+ int i;
+ NSBitmapImageRep* bitmap;
+ unsigned char* bitmapdata;
+
+ if (!obj) return NULL;
+ if (!PyTuple_Check(obj)) return NULL;
+ if (!PyArg_ParseTuple(obj, "iit#", &width, &height, &data, &n)) return NULL;
+ if (width*height*3 != n) return NULL; /* RGB image uses 3 colors / pixel */
+
+ bitmap = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes: NULL
+ pixelsWide: width
+ pixelsHigh: height
+ bitsPerSample: 8
+ samplesPerPixel: 3
+ hasAlpha: NO
+ isPlanar: NO
+ colorSpaceName: NSDeviceRGBColorSpace
+ bitmapFormat: 0
+ bytesPerRow: width*3
+ bitsPerPixel: 24];
+ if (!bitmap) return NULL;
+ bitmapdata = [bitmap bitmapData];
+ for (i = 0; i < n; i++) bitmapdata[i] = data[i];
+
+ NSSize size = NSMakeSize(width, height);
+ NSImage* image = [[NSImage alloc] initWithSize: size];
+ if (image) [image addRepresentation: bitmap];
+
+ [bitmap release];
+
+ return image;
+}
+
+static PyObject*
+FigureCanvas_start_event_loop(FigureCanvas* self, PyObject* args, PyObject* keywords)
+{
+ float timeout = 0.0;
+
+ static char* kwlist[] = {"timeout", NULL};
+ if(!PyArg_ParseTupleAndKeywords(args, keywords, "f", kwlist, &timeout))
+ return NULL;
+
+ int error;
+ int interrupted = 0;
+ int channel[2];
+ CFSocketRef sigint_socket = NULL;
+ PyOS_sighandler_t py_sigint_handler = NULL;
+
+ CFRunLoopRef runloop = CFRunLoopGetCurrent();
+
+ error = pipe(channel);
+ if (error==0)
+ {
+ CFSocketContext context = {0, NULL, NULL, NULL, NULL};
+ fcntl(channel[1], F_SETFL, O_WRONLY | O_NONBLOCK);
+
+ context.info = &interrupted;
+ sigint_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
+ channel[0],
+ kCFSocketReadCallBack,
+ _sigint_callback,
+ &context);
+ if (sigint_socket)
+ {
+ CFRunLoopSourceRef source;
+ source = CFSocketCreateRunLoopSource(kCFAllocatorDefault,
+ sigint_socket,
+ 0);
+ CFRelease(sigint_socket);
+ if (source)
+ {
+ CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
+ CFRelease(source);
+ sigint_fd = channel[1];
+ py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler);
+ }
+ }
+ else
+ close(channel[0]);
+ }
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSDate* date =
+ (timeout > 0.0) ? [NSDate dateWithTimeIntervalSinceNow: timeout]
+ : [NSDate distantFuture];
+ while (true)
+ { NSEvent* event = [NSApp nextEventMatchingMask: NSAnyEventMask
+ untilDate: date
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+ if (!event || [event type]==NSApplicationDefined) break;
+ [NSApp sendEvent: event];
+ }
+ [pool release];
+
+ if (py_sigint_handler) PyOS_setsig(SIGINT, py_sigint_handler);
+
+ if (sigint_socket) CFSocketInvalidate(sigint_socket);
+ if (error==0) close(channel[1]);
+ if (interrupted) raise(SIGINT);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureCanvas_stop_event_loop(FigureCanvas* self)
+{
+ NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
+ location: NSZeroPoint
+ modifierFlags: 0
+ timestamp: 0.0
+ windowNumber: 0
+ context: nil
+ subtype: STOP_EVENT_LOOP
+ data1: 0
+ data2: 0];
+ [NSApp postEvent: event atStart: true];
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef FigureCanvas_methods[] = {
+ {"draw",
+ (PyCFunction)FigureCanvas_draw,
+ METH_NOARGS,
+ "Draws the canvas."
+ },
+ {"invalidate",
+ (PyCFunction)FigureCanvas_invalidate,
+ METH_NOARGS,
+ "Invalidates the canvas."
+ },
+ {"flush_events",
+ (PyCFunction)FigureCanvas_flush_events,
+ METH_NOARGS,
+ "Flush the GUI events for the figure."
+ },
+ {"set_rubberband",
+ (PyCFunction)FigureCanvas_set_rubberband,
+ METH_VARARGS,
+ "Specifies a new rubberband rectangle and invalidates it."
+ },
+ {"remove_rubberband",
+ (PyCFunction)FigureCanvas_remove_rubberband,
+ METH_NOARGS,
+ "Removes the current rubberband rectangle."
+ },
+ {"start_event_loop",
+ (PyCFunction)FigureCanvas_start_event_loop,
+ METH_KEYWORDS | METH_VARARGS,
+ "Runs the event loop until the timeout or until stop_event_loop is called.\n",
+ },
+ {"stop_event_loop",
+ (PyCFunction)FigureCanvas_stop_event_loop,
+ METH_NOARGS,
+ "Stops the event loop that was started by start_event_loop.\n",
+ },
+ {NULL} /* Sentinel */
+};
+
+static char FigureCanvas_doc[] =
+"A FigureCanvas object wraps a Cocoa NSView object.\n";
+
+static PyTypeObject FigureCanvasType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_macosx.FigureCanvas", /*tp_name*/
+ sizeof(FigureCanvas), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)FigureCanvas_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)FigureCanvas_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ FigureCanvas_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ FigureCanvas_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FigureCanvas_init, /* tp_init */
+ 0, /* tp_alloc */
+ FigureCanvas_new, /* tp_new */
+};
+
+typedef struct {
+ PyObject_HEAD
+ Window* window;
+} FigureManager;
+
+static PyObject*
+FigureManager_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ Window* window = [Window alloc];
+ if (!window) return NULL;
+ FigureManager *self = (FigureManager*)type->tp_alloc(type, 0);
+ if (!self)
+ {
+ [window release];
+ return NULL;
+ }
+ self->window = window;
+ ++FigureWindowCount;
+ return (PyObject*)self;
+}
+
+static int
+FigureManager_init(FigureManager *self, PyObject *args, PyObject *kwds)
+{
+ NSRect rect;
+ Window* window;
+ View* view;
+ const char* title;
+ PyObject* size;
+ int width, height;
+ PyObject* obj;
+ FigureCanvas* canvas;
+
+ if(!self->window)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSWindow* is NULL");
+ return -1;
+ }
+
+ if(!PyArg_ParseTuple(args, "Os", &obj, &title)) return -1;
+
+ canvas = (FigureCanvas*)obj;
+ view = canvas->view;
+ if (!view) /* Something really weird going on */
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return -1;
+ }
+
+ size = PyObject_CallMethod(obj, "get_width_height", "");
+ if(!size) return -1;
+ if(!PyArg_ParseTuple(size, "ii", &width, &height))
+ { Py_DECREF(size);
+ return -1;
+ }
+ Py_DECREF(size);
+
+ rect.origin.x = 100;
+ rect.origin.y = 350;
+ rect.size.height = height;
+ rect.size.width = width;
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ self->window = [self->window initWithContentRect: rect
+ styleMask: NSTitledWindowMask
+ | NSClosableWindowMask
+ | NSResizableWindowMask
+ | NSMiniaturizableWindowMask
+ backing: NSBackingStoreBuffered
+ defer: YES
+ withManager: (PyObject*)self];
+ window = self->window;
+ [window setTitle: [NSString stringWithCString: title
+ encoding: NSASCIIStringEncoding]];
+
+ [window setAcceptsMouseMovedEvents: YES];
+ [window setDelegate: view];
+ [window makeFirstResponder: view];
+ [[window contentView] addSubview: view];
+
+ [pool release];
+ return 0;
+}
+
+static PyObject*
+FigureManager_repr(FigureManager* self)
+{
+#if PY3K
+ return PyUnicode_FromFormat("FigureManager object %p wrapping NSWindow %p",
+ (void*) self, (void*)(self->window));
+#else
+ return PyString_FromFormat("FigureManager object %p wrapping NSWindow %p",
+ (void*) self, (void*)(self->window));
+#endif
+}
+
+static void
+FigureManager_dealloc(FigureManager* self)
+{
+ Window* window = self->window;
+ if(window)
+ {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [window close];
+ [pool release];
+ }
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject*
+FigureManager_show(FigureManager* self)
+{
+ Window* window = self->window;
+ if(window)
+ {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [window makeKeyAndOrderFront: nil];
+ [window orderFrontRegardless];
+ [pool release];
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureManager_destroy(FigureManager* self)
+{
+ Window* window = self->window;
+ if(window)
+ {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [window close];
+ [pool release];
+ self->window = NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureManager_set_window_title(FigureManager* self,
+ PyObject *args, PyObject *kwds)
+{
+ char* title;
+ if(!PyArg_ParseTuple(args, "es", "UTF-8", &title))
+ return NULL;
+
+ Window* window = self->window;
+ if(window)
+ {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSString* ns_title = [[[NSString alloc]
+ initWithCString: title
+ encoding: NSUTF8StringEncoding] autorelease];
+ [window setTitle: ns_title];
+ [pool release];
+ }
+ PyMem_Free(title);
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+FigureManager_get_window_title(FigureManager* self)
+{
+ Window* window = self->window;
+ PyObject* result = NULL;
+ if(window)
+ {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSString* title = [window title];
+ if (title) {
+ const char* cTitle = [title UTF8String];
+ result = PyUnicode_FromString(cTitle);
+ }
+ [pool release];
+ }
+ if (result) {
+ return result;
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static PyMethodDef FigureManager_methods[] = {
+ {"show",
+ (PyCFunction)FigureManager_show,
+ METH_NOARGS,
+ "Shows the window associated with the figure manager."
+ },
+ {"destroy",
+ (PyCFunction)FigureManager_destroy,
+ METH_NOARGS,
+ "Closes the window associated with the figure manager."
+ },
+ {"set_window_title",
+ (PyCFunction)FigureManager_set_window_title,
+ METH_VARARGS,
+ "Sets the title of the window associated with the figure manager."
+ },
+ {"get_window_title",
+ (PyCFunction)FigureManager_get_window_title,
+ METH_NOARGS,
+ "Returns the title of the window associated with the figure manager."
+ },
+ {NULL} /* Sentinel */
+};
+
+static char FigureManager_doc[] =
+"A FigureManager object wraps a Cocoa NSWindow object.\n";
+
+static PyTypeObject FigureManagerType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_macosx.FigureManager", /*tp_name*/
+ sizeof(FigureManager), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)FigureManager_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)FigureManager_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ FigureManager_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ FigureManager_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FigureManager_init, /* tp_init */
+ 0, /* tp_alloc */
+ FigureManager_new, /* tp_new */
+};
+
+@interface NavigationToolbarHandler : NSObject
+{ PyObject* toolbar;
+}
+- (NavigationToolbarHandler*)initWithToolbar:(PyObject*)toolbar;
+-(void)left:(id)sender;
+-(void)right:(id)sender;
+-(void)up:(id)sender;
+-(void)down:(id)sender;
+-(void)zoominx:(id)sender;
+-(void)zoominy:(id)sender;
+-(void)zoomoutx:(id)sender;
+-(void)zoomouty:(id)sender;
+@end
+
+typedef struct {
+ PyObject_HEAD
+ NSPopUpButton* menu;
+ NavigationToolbarHandler* handler;
+} NavigationToolbar;
+
+@implementation NavigationToolbarHandler
+- (NavigationToolbarHandler*)initWithToolbar:(PyObject*)theToolbar
+{ [self init];
+ toolbar = theToolbar;
+ return self;
+}
+
+-(void)left:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "panx", "i", -1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)right:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "panx", "i", 1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)up:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "pany", "i", 1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)down:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "pany", "i", -1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)zoominx:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "zoomx", "i", 1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)zoomoutx:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "zoomx", "i", -1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)zoominy:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "zoomy", "i", 1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)zoomouty:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "zoomy", "i", -1);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)save_figure:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "save_figure", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+@end
+
+static PyObject*
+NavigationToolbar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ NavigationToolbarHandler* handler = [NavigationToolbarHandler alloc];
+ if (!handler) return NULL;
+ NavigationToolbar *self = (NavigationToolbar*)type->tp_alloc(type, 0);
+ if (!self)
+ { [handler release];
+ return NULL;
+ }
+ self->handler = handler;
+ return (PyObject*)self;
+}
+
+static int
+NavigationToolbar_init(NavigationToolbar *self, PyObject *args, PyObject *kwds)
+{
+ int i;
+ NSRect rect;
+
+ const float smallgap = 2;
+ const float biggap = 10;
+ const int height = 32;
+
+ PyObject* images;
+ PyObject* obj;
+
+ FigureCanvas* canvas;
+ View* view;
+
+ obj = PyObject_GetAttrString((PyObject*)self, "canvas");
+ if (obj==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Attempt to install toolbar for NULL canvas");
+ return -1;
+ }
+ Py_DECREF(obj); /* Don't increase the reference count */
+ if (!PyObject_IsInstance(obj, (PyObject*) &FigureCanvasType))
+ {
+ PyErr_SetString(PyExc_TypeError, "Attempt to install toolbar for object that is not a FigureCanvas");
+ return -1;
+ }
+ canvas = (FigureCanvas*)obj;
+ view = canvas->view;
+ if(!view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return -1;
+ }
+
+ if(!PyArg_ParseTuple(args, "O", &images)) return -1;
+ if(!PyDict_Check(images)) return -1;
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSRect bounds = [view bounds];
+ NSWindow* window = [view window];
+
+ bounds.origin.y += height;
+ [view setFrame: bounds];
+
+ bounds.size.height += height;
+ [window setContentSize: bounds.size];
+
+ char* imagenames[9] = {"stock_left",
+ "stock_right",
+ "stock_zoom-in",
+ "stock_zoom-out",
+ "stock_up",
+ "stock_down",
+ "stock_zoom-in",
+ "stock_zoom-out",
+ "stock_save_as"};
+
+ NSString* tooltips[9] = {
+ @"Pan left with click or wheel mouse (bidirectional)",
+ @"Pan right with click or wheel mouse (bidirectional)",
+ @"Zoom In X (shrink the x axis limits) with click or wheel mouse (bidirectional)",
+ @"Zoom Out X (expand the x axis limits) with click or wheel mouse (bidirectional)",
+ @"Pan up with click or wheel mouse (bidirectional)",
+ @"Pan down with click or wheel mouse (bidirectional)",
+ @"Zoom in Y (shrink the y axis limits) with click or wheel mouse (bidirectional)",
+ @"Zoom Out Y (expand the y axis limits) with click or wheel mouse (bidirectional)",
+ @"Save the figure"};
+
+ SEL actions[9] = {@selector(left:),
+ @selector(right:),
+ @selector(zoominx:),
+ @selector(zoomoutx:),
+ @selector(up:),
+ @selector(down:),
+ @selector(zoominy:),
+ @selector(zoomouty:),
+ @selector(save_figure:)};
+
+ SEL scroll_actions[9][2] = {{@selector(left:), @selector(right:)},
+ {@selector(left:), @selector(right:)},
+ {@selector(zoominx:), @selector(zoomoutx:)},
+ {@selector(zoominx:), @selector(zoomoutx:)},
+ {@selector(up:), @selector(down:)},
+ {@selector(up:), @selector(down:)},
+ {@selector(zoominy:), @selector(zoomouty:)},
+ {@selector(zoominy:), @selector(zoomouty:)},
+ {nil,nil},
+ };
+
+
+ rect.size.width = 120;
+ rect.size.height = 24;
+ rect.origin.x = biggap;
+ rect.origin.y = 0.5*(height - rect.size.height);
+ self->menu = [[NSPopUpButton alloc] initWithFrame: rect
+ pullsDown: YES];
+ [self->menu setAutoenablesItems: NO];
+ [[window contentView] addSubview: self->menu];
+ [self->menu release];
+ rect.origin.x += rect.size.width + biggap;
+ rect.size.width = 24;
+
+ self->handler = [self->handler initWithToolbar: (PyObject*)self];
+ for (i = 0; i < 9; i++)
+ {
+ NSButton* button;
+ SEL scrollWheelUpAction = scroll_actions[i][0];
+ SEL scrollWheelDownAction = scroll_actions[i][1];
+ if (scrollWheelUpAction && scrollWheelDownAction)
+ {
+ ScrollableButton* scrollable_button = [ScrollableButton alloc];
+ [scrollable_button initWithFrame: rect];
+ [scrollable_button setScrollWheelUpAction: scrollWheelUpAction];
+ [scrollable_button setScrollWheelDownAction: scrollWheelDownAction];
+ button = (NSButton*)scrollable_button;
+ }
+ else
+ {
+ button = [NSButton alloc];
+ [button initWithFrame: rect];
+ }
+ PyObject* imagedata = PyDict_GetItemString(images, imagenames[i]);
+ NSImage* image = _read_ppm_image(imagedata);
+ [button setBezelStyle: NSShadowlessSquareBezelStyle];
+ [button setButtonType: NSMomentaryLightButton];
+ if(image)
+ {
+ [button setImage: image];
+ [image release];
+ }
+ [button setToolTip: tooltips[i]];
+ [button setTarget: self->handler];
+ [button setAction: actions[i]];
+ [[window contentView] addSubview: button];
+ [button release];
+ rect.origin.x += rect.size.width + smallgap;
+ }
+ [[window contentView] display];
+ [pool release];
+
+ return 0;
+}
+
+static void
+NavigationToolbar_dealloc(NavigationToolbar *self)
+{
+ [self->handler release];
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject*
+NavigationToolbar_repr(NavigationToolbar* self)
+{
+#if PY3K
+ return PyUnicode_FromFormat("NavigationToolbar object %p", (void*)self);
+#else
+ return PyString_FromFormat("NavigationToolbar object %p", (void*)self);
+#endif
+}
+
+static char NavigationToolbar_doc[] =
+"NavigationToolbar\n";
+
+static PyObject*
+NavigationToolbar_update (NavigationToolbar* self)
+{
+ int n;
+ NSPopUpButton* button = self->menu;
+ if (!button)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Menu button is NULL");
+ return NULL;
+ }
+
+ PyObject* canvas = PyObject_GetAttrString((PyObject*)self, "canvas");
+ if (canvas==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Failed to find canvas");
+ return NULL;
+ }
+ Py_DECREF(canvas); /* Don't keep a reference here */
+ PyObject* figure = PyObject_GetAttrString(canvas, "figure");
+ if (figure==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Failed to find figure");
+ return NULL;
+ }
+ Py_DECREF(figure); /* Don't keep a reference here */
+ PyObject* axes = PyObject_GetAttrString(figure, "axes");
+ if (axes==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Failed to find figure axes");
+ return NULL;
+ }
+ Py_DECREF(axes); /* Don't keep a reference here */
+ if (!PyList_Check(axes))
+ {
+ PyErr_SetString(PyExc_TypeError, "Figure axes is not a list");
+ return NULL;
+ }
+ n = PyList_GET_SIZE(axes);
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [button removeAllItems];
+
+ NSMenu* menu = [button menu];
+ [menu addItem: [MenuItem menuItemWithTitle: @"Axes"]];
+
+ if (n==0)
+ {
+ [button setEnabled: NO];
+ }
+ else
+ {
+ int i;
+ [menu addItem: [MenuItem menuItemSelectAll]];
+ [menu addItem: [MenuItem menuItemInvertAll]];
+ [menu addItem: [NSMenuItem separatorItem]];
+ for (i = 0; i < n; i++)
+ {
+ [menu addItem: [MenuItem menuItemForAxis: i]];
+ }
+ [button setEnabled: YES];
+ }
+ [pool release];
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+NavigationToolbar_get_active (NavigationToolbar* self)
+{
+ NSPopUpButton* button = self->menu;
+ if (!button)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Menu button is NULL");
+ return NULL;
+ }
+ NSMenu* menu = [button menu];
+ NSArray* items = [menu itemArray];
+ size_t n = [items count];
+ int* states = calloc(n, sizeof(int));
+ if (!states)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "calloc failed");
+ return NULL;
+ }
+ int i;
+ unsigned int m = 0;
+ NSEnumerator* enumerator = [items objectEnumerator];
+ MenuItem* item;
+ while ((item = [enumerator nextObject]))
+ {
+ if ([item isSeparatorItem]) continue;
+ i = [item index];
+ if (i < 0) continue;
+ if ([item state]==NSOnState)
+ {
+ states[i] = 1;
+ m++;
+ }
+ }
+ Py_ssize_t list_index = 0;
+ PyObject* list = PyList_New(m);
+
+ size_t state_index;
+ for (state_index = 0; state_index < n; state_index++)
+ {
+ if(states[state_index]==1)
+ {
+ PyList_SET_ITEM(list, list_index++, PyLong_FromSize_t(state_index));
+ }
+ }
+ free(states);
+ return list;
+}
+
+static PyMethodDef NavigationToolbar_methods[] = {
+ {"update",
+ (PyCFunction)NavigationToolbar_update,
+ METH_NOARGS,
+ "Updates the toolbar menu."
+ },
+ {"get_active",
+ (PyCFunction)NavigationToolbar_get_active,
+ METH_NOARGS,
+ "Returns a list of integers identifying which items in the menu are selected."
+ },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject NavigationToolbarType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_macosx.NavigationToolbar", /*tp_name*/
+ sizeof(NavigationToolbar), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)NavigationToolbar_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)NavigationToolbar_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ NavigationToolbar_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NavigationToolbar_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)NavigationToolbar_init, /* tp_init */
+ 0, /* tp_alloc */
+ NavigationToolbar_new, /* tp_new */
+};
+
+@interface NavigationToolbar2Handler : NSObject
+{ PyObject* toolbar;
+ NSButton* panbutton;
+ NSButton* zoombutton;
+}
+- (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)toolbar;
+- (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons;
+- (void)home:(id)sender;
+- (void)back:(id)sender;
+- (void)forward:(id)sender;
+- (void)pan:(id)sender;
+- (void)zoom:(id)sender;
+- (void)configure_subplots:(id)sender;
+- (void)save_figure:(id)sender;
+@end
+
+typedef struct {
+ PyObject_HEAD
+ NSPopUpButton* menu;
+ NSText* messagebox;
+ NavigationToolbar2Handler* handler;
+} NavigationToolbar2;
+
+@implementation NavigationToolbar2Handler
+- (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)theToolbar
+{ [self init];
+ toolbar = theToolbar;
+ return self;
+}
+
+- (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons
+{
+ int i;
+ for (i = 0; i < 7; i++)
+ {
+ SEL action = actions[i];
+ NSButton* button = buttons[i];
+ [button setTarget: self];
+ [button setAction: action];
+ if (action==@selector(pan:)) panbutton = button;
+ if (action==@selector(zoom:)) zoombutton = button;
+ }
+}
+
+-(void)home:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "home", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)back:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "back", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)forward:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "forward", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)pan:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ if ([sender state])
+ {
+ if (zoombutton) [zoombutton setState: NO];
+ }
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "pan", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)zoom:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ if ([sender state])
+ {
+ if (panbutton) [panbutton setState: NO];
+ }
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "zoom", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+-(void)configure_subplots:(id)sender
+{ PyObject* canvas;
+ View* view;
+ PyObject* size;
+ NSRect rect;
+ int width, height;
+
+ rect.origin.x = 100;
+ rect.origin.y = 350;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* master = PyObject_GetAttrString(toolbar, "canvas");
+ if (master==nil)
+ {
+ PyErr_Print();
+ PyGILState_Release(gstate);
+ return;
+ }
+ canvas = PyObject_CallMethod(toolbar, "prepare_configure_subplots", "");
+ if(!canvas)
+ {
+ PyErr_Print();
+ Py_DECREF(master);
+ PyGILState_Release(gstate);
+ return;
+ }
+
+ view = ((FigureCanvas*)canvas)->view;
+ if (!view) /* Something really weird going on */
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ PyErr_Print();
+ Py_DECREF(canvas);
+ Py_DECREF(master);
+ PyGILState_Release(gstate);
+ return;
+ }
+
+ size = PyObject_CallMethod(canvas, "get_width_height", "");
+ Py_DECREF(canvas);
+ if(!size)
+ {
+ PyErr_Print();
+ Py_DECREF(master);
+ PyGILState_Release(gstate);
+ return;
+ }
+
+ int ok = PyArg_ParseTuple(size, "ii", &width, &height);
+ Py_DECREF(size);
+ if (!ok)
+ {
+ PyErr_Print();
+ Py_DECREF(master);
+ PyGILState_Release(gstate);
+ return;
+ }
+
+ NSWindow* mw = [((FigureCanvas*)master)->view window];
+ Py_DECREF(master);
+ PyGILState_Release(gstate);
+
+ rect.size.width = width;
+ rect.size.height = height;
+
+ ToolWindow* window = [ [ToolWindow alloc] initWithContentRect: rect
+ master: mw];
+ [window setContentView: view];
+ [view release];
+ [window makeKeyAndOrderFront: nil];
+}
+
+-(void)save_figure:(id)sender
+{ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(toolbar, "save_figure", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+@end
+
+static PyObject*
+NavigationToolbar2_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ NavigationToolbar2Handler* handler = [NavigationToolbar2Handler alloc];
+ if (!handler) return NULL;
+ NavigationToolbar2 *self = (NavigationToolbar2*)type->tp_alloc(type, 0);
+ if (!self)
+ {
+ [handler release];
+ return NULL;
+ }
+ self->handler = handler;
+ return (PyObject*)self;
+}
+
+static int
+NavigationToolbar2_init(NavigationToolbar2 *self, PyObject *args, PyObject *kwds)
+{
+ PyObject* obj;
+ FigureCanvas* canvas;
+ View* view;
+
+ int i;
+ NSRect rect;
+ NSSize size;
+ NSSize scale;
+
+ const float gap = 2;
+ const int height = 36;
+ const int imagesize = 24;
+
+ const char* basedir;
+
+ obj = PyObject_GetAttrString((PyObject*)self, "canvas");
+ if (obj==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Attempt to install toolbar for NULL canvas");
+ return -1;
+ }
+ Py_DECREF(obj); /* Don't increase the reference count */
+ if (!PyObject_IsInstance(obj, (PyObject*) &FigureCanvasType))
+ {
+ PyErr_SetString(PyExc_TypeError, "Attempt to install toolbar for object that is not a FigureCanvas");
+ return -1;
+ }
+ canvas = (FigureCanvas*)obj;
+ view = canvas->view;
+ if(!view)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL");
+ return -1;
+ }
+
+ if(!PyArg_ParseTuple(args, "s", &basedir)) return -1;
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSRect bounds = [view bounds];
+ NSWindow* window = [view window];
+
+ bounds.origin.y += height;
+ [view setFrame: bounds];
+
+ bounds.size.height += height;
+ [window setContentSize: bounds.size];
+
+ NSString* dir = [NSString stringWithCString: basedir
+ encoding: NSASCIIStringEncoding];
+
+ NSButton* buttons[7];
+
+ NSString* images[7] = {@"home.pdf",
+ @"back.pdf",
+ @"forward.pdf",
+ @"move.pdf",
+ @"zoom_to_rect.pdf",
+ @"subplots.pdf",
+ @"filesave.pdf"};
+
+ NSString* tooltips[7] = {@"Reset original view",
+ @"Back to previous view",
+ @"Forward to next view",
+ @"Pan axes with left mouse, zoom with right",
+ @"Zoom to rectangle",
+ @"Configure subplots",
+ @"Save the figure"};
+
+ SEL actions[7] = {@selector(home:),
+ @selector(back:),
+ @selector(forward:),
+ @selector(pan:),
+ @selector(zoom:),
+ @selector(configure_subplots:),
+ @selector(save_figure:)};
+
+ NSButtonType buttontypes[7] = {NSMomentaryLightButton,
+ NSMomentaryLightButton,
+ NSMomentaryLightButton,
+ NSPushOnPushOffButton,
+ NSPushOnPushOffButton,
+ NSMomentaryLightButton,
+ NSMomentaryLightButton};
+
+ rect.origin.x = 0;
+ rect.origin.y = 0;
+ rect.size.width = imagesize;
+ rect.size.height = imagesize;
+#ifdef COMPILING_FOR_10_7
+ rect = [window convertRectToBacking: rect];
+#endif
+ size = rect.size;
+ scale.width = imagesize / size.width;
+ scale.height = imagesize / size.height;
+
+ rect.size.width = 32;
+ rect.size.height = 32;
+ rect.origin.x = gap;
+ rect.origin.y = 0.5*(height - rect.size.height);
+
+ for (i = 0; i < 7; i++)
+ {
+ NSString* filename = [dir stringByAppendingPathComponent: images[i]];
+ NSImage* image = [[NSImage alloc] initWithContentsOfFile: filename];
+ buttons[i] = [[NSButton alloc] initWithFrame: rect];
+ [image setSize: size];
+ [buttons[i] setBezelStyle: NSShadowlessSquareBezelStyle];
+ [buttons[i] setButtonType: buttontypes[i]];
+ [buttons[i] setImage: image];
+ [buttons[i] scaleUnitSquareToSize: scale];
+ [buttons[i] setImagePosition: NSImageOnly];
+ [buttons[i] setToolTip: tooltips[i]];
+ [[window contentView] addSubview: buttons[i]];
+ [buttons[i] release];
+ [image release];
+ rect.origin.x += rect.size.width + gap;
+ }
+
+ self->handler = [self->handler initWithToolbar: (PyObject*)self];
+ [self->handler installCallbacks: actions forButtons: buttons];
+
+ NSFont* font = [NSFont systemFontOfSize: 0.0];
+ rect.size.width = 300;
+ rect.size.height = 0;
+ rect.origin.x += height;
+ NSText* messagebox = [[NSText alloc] initWithFrame: rect];
+ [messagebox setFont: font];
+ [messagebox setDrawsBackground: NO];
+ [messagebox setSelectable: NO];
+ /* if selectable, the messagebox can become first responder,
+ * which is not supposed to happen */
+ rect = [messagebox frame];
+ rect.origin.y = 0.5 * (height - rect.size.height);
+ [messagebox setFrameOrigin: rect.origin];
+ [[window contentView] addSubview: messagebox];
+ [messagebox release];
+ [[window contentView] display];
+
+ [pool release];
+
+ self->messagebox = messagebox;
+ return 0;
+}
+
+static void
+NavigationToolbar2_dealloc(NavigationToolbar2 *self)
+{
+ [self->handler release];
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject*
+NavigationToolbar2_repr(NavigationToolbar2* self)
+{
+#if PY3K
+ return PyUnicode_FromFormat("NavigationToolbar2 object %p", (void*)self);
+#else
+ return PyString_FromFormat("NavigationToolbar2 object %p", (void*)self);
+#endif
+}
+
+static char NavigationToolbar2_doc[] =
+"NavigationToolbar2\n";
+
+static PyObject*
+NavigationToolbar2_set_message(NavigationToolbar2 *self, PyObject* args)
+{
+ const char* message;
+
+#if PY3K
+ if(!PyArg_ParseTuple(args, "y", &message)) return NULL;
+#else
+ if(!PyArg_ParseTuple(args, "s", &message)) return NULL;
+#endif
+
+ NSText* messagebox = self->messagebox;
+
+ if (messagebox)
+ { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSString* text = [NSString stringWithUTF8String: message];
+ [messagebox setString: text];
+ [pool release];
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef NavigationToolbar2_methods[] = {
+ {"set_message",
+ (PyCFunction)NavigationToolbar2_set_message,
+ METH_VARARGS,
+ "Set the message to be displayed on the toolbar."
+ },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject NavigationToolbar2Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_macosx.NavigationToolbar2", /*tp_name*/
+ sizeof(NavigationToolbar2), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)NavigationToolbar2_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)NavigationToolbar2_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ NavigationToolbar2_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NavigationToolbar2_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)NavigationToolbar2_init, /* tp_init */
+ 0, /* tp_alloc */
+ NavigationToolbar2_new, /* tp_new */
+};
+
+static PyObject*
+choose_save_file(PyObject* unused, PyObject* args)
+{
+ int result;
+ const char* title;
+ char* default_filename;
+ if(!PyArg_ParseTuple(args, "ses", &title, "UTF-8", &default_filename))
+ return NULL;
+
+ NSSavePanel* panel = [NSSavePanel savePanel];
+ [panel setTitle: [NSString stringWithCString: title
+ encoding: NSASCIIStringEncoding]];
+ NSString* ns_default_filename =
+ [[NSString alloc]
+ initWithCString: default_filename
+ encoding: NSUTF8StringEncoding];
+ PyMem_Free(default_filename);
+#ifdef COMPILING_FOR_10_6
+ [panel setNameFieldStringValue: ns_default_filename];
+ result = [panel runModal];
+#else
+ result = [panel runModalForDirectory: nil file: ns_default_filename];
+#endif
+ [ns_default_filename release];
+#ifdef COMPILING_FOR_10_10
+ if (result == NSModalResponseOK)
+#else
+ if (result == NSOKButton)
+#endif
+ {
+#ifdef COMPILING_FOR_10_6
+ NSURL* url = [panel URL];
+ NSString* filename = [url path];
+ if (!filename) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to obtain filename");
+ return 0;
+ }
+#else
+ NSString* filename = [panel filename];
+#endif
+ unsigned int n = [filename length];
+ unichar* buffer = malloc(n*sizeof(unichar));
+ [filename getCharacters: buffer];
+#if PY3K
+ PyObject* string = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, buffer, n);
+#else
+ PyObject* string = PyUnicode_FromUnicode(buffer, n);
+#endif
+ free(buffer);
+ return string;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+set_cursor(PyObject* unused, PyObject* args)
+{
+ int i;
+ if(!PyArg_ParseTuple(args, "i", &i)) return NULL;
+ switch (i)
+ { case 0: [[NSCursor pointingHandCursor] set]; break;
+ case 1: [[NSCursor arrowCursor] set]; break;
+ case 2: [[NSCursor crosshairCursor] set]; break;
+ case 3: [[NSCursor openHandCursor] set]; break;
+ /* OSX handles busy state itself so no need to set a cursor here */
+ case 4: break;
+ default: return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+@implementation WindowServerConnectionManager
+static WindowServerConnectionManager *sharedWindowServerConnectionManager = nil;
+
++ (WindowServerConnectionManager *)sharedManager
+{
+ if (sharedWindowServerConnectionManager == nil)
+ {
+ sharedWindowServerConnectionManager = [[super allocWithZone:NULL] init];
+ }
+ return sharedWindowServerConnectionManager;
+}
+
++ (id)allocWithZone:(NSZone *)zone
+{
+ return [[self sharedManager] retain];
+}
+
++ (id)copyWithZone:(NSZone *)zone
+{
+ return self;
+}
+
++ (id)retain
+{
+ return self;
+}
+
+- (NSUInteger)retainCount
+{
+ return NSUIntegerMax; //denotes an object that cannot be released
+}
+
+- (oneway void)release
+{
+ // Don't release a singleton object
+}
+
+- (id)autorelease
+{
+ return self;
+}
+
+- (void)launch:(NSNotification*)notification
+{
+ CFRunLoopRef runloop;
+ CFMachPortRef port;
+ CFRunLoopSourceRef source;
+ NSDictionary* dictionary = [notification userInfo];
+ if (! [[dictionary valueForKey:@"NSApplicationName"]
+ isEqualToString:@"Python"])
+ return;
+ NSNumber* psnLow = [dictionary valueForKey: @"NSApplicationProcessSerialNumberLow"];
+ NSNumber* psnHigh = [dictionary valueForKey: @"NSApplicationProcessSerialNumberHigh"];
+ ProcessSerialNumber psn;
+ psn.highLongOfPSN = [psnHigh intValue];
+ psn.lowLongOfPSN = [psnLow intValue];
+ runloop = CFRunLoopGetCurrent();
+ port = CGEventTapCreateForPSN(&psn,
+ kCGHeadInsertEventTap,
+ kCGEventTapOptionListenOnly,
+ kCGEventMaskForAllEvents,
+ &_eventtap_callback,
+ runloop);
+ source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
+ port,
+ 0);
+ CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
+ CFRelease(port);
+}
+@end
+
+@implementation Window
+- (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager
+{
+ self = [super initWithContentRect: rect
+ styleMask: mask
+ backing: bufferingType
+ defer: deferCreation];
+ manager = theManager;
+ Py_INCREF(manager);
+ return self;
+}
+
+- (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen
+{
+ /* Allow window sizes larger than the screen */
+ NSRect suggested = [super constrainFrameRect: rect toScreen: screen];
+ const CGFloat difference = rect.size.height - suggested.size.height;
+ suggested.origin.y -= difference;
+ suggested.size.height += difference;
+ return suggested;
+}
+
+- (BOOL)closeButtonPressed
+{
+ PyObject* result;
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(manager, "close", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+ return YES;
+}
+
+- (void)close
+{
+ [super close];
+ --FigureWindowCount;
+ if (!FigureWindowCount) [NSApp stop: self];
+ /* This is needed for show(), which should exit from [NSApp run]
+ * after all windows are closed.
+ */
+}
+
+- (void)dealloc
+{
+ PyGILState_STATE gstate;
+ gstate = PyGILState_Ensure();
+ Py_DECREF(manager);
+ PyGILState_Release(gstate);
+ /* The reference count of the view that was added as a subview to the
+ * content view of this window was increased during the call to addSubview,
+ * and is decreased during the call to [super dealloc].
+ */
+ [super dealloc];
+}
+@end
+
+@implementation ToolWindow
+- (ToolWindow*)initWithContentRect:(NSRect)rect master:(NSWindow*)window
+{
+ [self initWithContentRect: rect
+ styleMask: NSTitledWindowMask
+ | NSClosableWindowMask
+ | NSResizableWindowMask
+ | NSMiniaturizableWindowMask
+ backing: NSBackingStoreBuffered
+ defer: YES];
+ [self setTitle: @"Subplot Configuration Tool"];
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(masterCloses:)
+ name: NSWindowWillCloseNotification
+ object: window];
+ return self;
+}
+
+- (void)masterCloses:(NSNotification*)notification
+{
+ [self close];
+}
+
+- (void)close
+{
+ [[NSNotificationCenter defaultCenter] removeObserver: self];
+ [super close];
+}
+@end
+
+@implementation View
+- (BOOL)isFlipped
+{
+ return NO;
+}
+
+- (View*)initWithFrame:(NSRect)rect
+{
+ self = [super initWithFrame: rect];
+ rubberband = NSZeroRect;
+ inside = false;
+ tracking = 0;
+ device_scale = 1;
+ return self;
+}
+
+- (void)dealloc
+{
+ FigureCanvas* fc = (FigureCanvas*)canvas;
+ if (fc) fc->view = NULL;
+ [self removeTrackingRect: tracking];
+ [super dealloc];
+}
+
+- (void)setCanvas: (PyObject*)newCanvas
+{
+ canvas = newCanvas;
+}
+
+static void _buffer_release(void* info, const void* data, size_t size) {
+ PyBuffer_Release((Py_buffer *)info);
+}
+
+static int _copy_agg_buffer(CGContextRef cr, PyObject *renderer)
+{
+ Py_buffer buffer;
+
+ if (PyObject_GetBuffer(renderer, &buffer, PyBUF_CONTIG_RO) == -1) {
+ PyErr_Print();
+ return 1;
+ }
+
+ if (buffer.ndim != 3 || buffer.shape[2] != 4) {
+ PyBuffer_Release(&buffer);
+ return 1;
+ }
+
+ const Py_ssize_t nrows = buffer.shape[0];
+ const Py_ssize_t ncols = buffer.shape[1];
+ const size_t bytesPerComponent = 1;
+ const size_t bitsPerComponent = 8 * bytesPerComponent;
+ const size_t nComponents = 4; /* red, green, blue, alpha */
+ const size_t bitsPerPixel = bitsPerComponent * nComponents;
+ const size_t bytesPerRow = nComponents * bytesPerComponent * ncols;
+
+ CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ if (!colorspace) {
+ PyBuffer_Release(&buffer);
+ return 1;
+ }
+
+ CGDataProviderRef provider = CGDataProviderCreateWithData(&buffer,
+ buffer.buf,
+ buffer.len,
+ _buffer_release);
+ if (!provider) {
+ PyBuffer_Release(&buffer);
+ CGColorSpaceRelease(colorspace);
+ return 1;
+ }
+
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaLast;
+ CGImageRef bitmap = CGImageCreate(ncols,
+ nrows,
+ bitsPerComponent,
+ bitsPerPixel,
+ bytesPerRow,
+ colorspace,
+ bitmapInfo,
+ provider,
+ NULL,
+ false,
+ kCGRenderingIntentDefault);
+ CGColorSpaceRelease(colorspace);
+ CGDataProviderRelease(provider);
+
+ if (!bitmap) {
+ PyBuffer_Release(&buffer);
+ return 1;
+ }
+
+ CGFloat deviceScale = _get_device_scale(cr);
+ CGContextSaveGState(cr);
+ CGContextDrawImage(cr, CGRectMake(0, 0, ncols/deviceScale, nrows/deviceScale), bitmap);
+ CGImageRelease(bitmap);
+ CGContextRestoreGState(cr);
+
+ return 0;
+}
+
+-(void)drawRect:(NSRect)rect
+{
+ PyObject* renderer = NULL;
+ PyObject* renderer_buffer = NULL;
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
+
+ CGContextRef cr = [[NSGraphicsContext currentContext] graphicsPort];
+
+ double new_device_scale = _get_device_scale(cr);
+
+ if (device_scale != new_device_scale) {
+ device_scale = new_device_scale;
+ if (!PyObject_CallMethod(canvas, "_set_device_scale", "d", device_scale, NULL)) {
+ PyErr_Print();
+ goto exit;
+ }
+ }
+
+ renderer = PyObject_CallMethod(canvas, "_draw", "", NULL);
+ if (!renderer)
+ {
+ PyErr_Print();
+ goto exit;
+ }
+
+ renderer_buffer = PyObject_GetAttrString(renderer, "_renderer");
+ if (!renderer_buffer) {
+ PyErr_Print();
+ goto exit;
+ }
+
+ if (_copy_agg_buffer(cr, renderer_buffer)) {
+ printf("copy_agg_buffer failed\n");
+ goto exit;
+ }
+
+
+ if (!NSIsEmptyRect(rubberband)) {
+ NSFrameRect(rubberband);
+ }
+
+ exit:
+ Py_XDECREF(renderer_buffer);
+ Py_XDECREF(renderer);
+
+ PyGILState_Release(gstate);
+}
+
+- (void)windowDidResize: (NSNotification*)notification
+{
+ int width, height;
+ Window* window = [notification object];
+ NSSize size = [[window contentView] frame].size;
+ NSRect rect = [self frame];
+
+ size.height -= rect.origin.y;
+ width = size.width;
+ height = size.height;
+
+ [self setFrameSize: size];
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallMethod(
+ canvas, "resize", "ii", width, height);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+ if (tracking) [self removeTrackingRect: tracking];
+ tracking = [self addTrackingRect: [self bounds]
+ owner: self
+ userData: nil
+ assumeInside: NO];
+ [self setNeedsDisplay: YES];
+}
+
+- (void)windowWillClose:(NSNotification*)notification
+{
+ PyGILState_STATE gstate;
+ PyObject* result;
+
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "close_event", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+- (BOOL)windowShouldClose:(NSNotification*)notification
+{
+ NSWindow* window = [self window];
+ NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
+ location: NSZeroPoint
+ modifierFlags: 0
+ timestamp: 0.0
+ windowNumber: 0
+ context: nil
+ subtype: WINDOW_CLOSING
+ data1: 0
+ data2: 0];
+ [NSApp postEvent: event atStart: true];
+ if ([window respondsToSelector: @selector(closeButtonPressed)])
+ { BOOL closed = [((Window*) window) closeButtonPressed];
+ /* If closed, the window has already been closed via the manager. */
+ if (closed) return NO;
+ }
+ return YES;
+}
+
+- (void)mouseEntered:(NSEvent *)event
+{
+ PyGILState_STATE gstate;
+ PyObject* result;
+ NSWindow* window = [self window];
+ if ([window isKeyWindow]==false) return;
+
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "enter_notify_event", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+
+ [window setAcceptsMouseMovedEvents: YES];
+ inside = true;
+}
+
+- (void)mouseExited:(NSEvent *)event
+{
+ PyGILState_STATE gstate;
+ PyObject* result;
+ NSWindow* window = [self window];
+ if ([window isKeyWindow]==false) return;
+
+ if (inside==false) return;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "leave_notify_event", "");
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+ PyGILState_Release(gstate);
+
+ [[self window] setAcceptsMouseMovedEvents: NO];
+ inside = false;
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+ int x, y;
+ int num;
+ int dblclick = 0;
+ PyObject* result;
+ PyGILState_STATE gstate;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ switch ([event type])
+ { case NSLeftMouseDown:
+ { unsigned int modifier = [event modifierFlags];
+ if (modifier & NSControlKeyMask)
+ /* emulate a right-button click */
+ num = 3;
+ else if (modifier & NSAlternateKeyMask)
+ /* emulate a middle-button click */
+ num = 2;
+ else
+ {
+ num = 1;
+ if ([NSCursor currentCursor]==[NSCursor openHandCursor])
+ [[NSCursor closedHandCursor] set];
+ }
+ break;
+ }
+ case NSOtherMouseDown: num = 2; break;
+ case NSRightMouseDown: num = 3; break;
+ default: return; /* Unknown mouse event */
+ }
+ if ([event clickCount] == 2) {
+ dblclick = 1;
+ }
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)mouseUp:(NSEvent *)event
+{
+ int num;
+ int x, y;
+ PyObject* result;
+ PyGILState_STATE gstate;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ switch ([event type])
+ { case NSLeftMouseUp:
+ num = 1;
+ if ([NSCursor currentCursor]==[NSCursor closedHandCursor])
+ [[NSCursor openHandCursor] set];
+ break;
+ case NSOtherMouseUp: num = 2; break;
+ case NSRightMouseUp: num = 3; break;
+ default: return; /* Unknown mouse event */
+ }
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)mouseMoved:(NSEvent *)event
+{
+ int x, y;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+ int x, y;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)rightMouseDown:(NSEvent *)event
+{
+ int x, y;
+ int num = 3;
+ int dblclick = 0;
+ PyObject* result;
+ PyGILState_STATE gstate;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ gstate = PyGILState_Ensure();
+ if ([event clickCount] == 2) {
+ dblclick = 1;
+ }
+ result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)rightMouseUp:(NSEvent *)event
+{
+ int x, y;
+ int num = 3;
+ PyObject* result;
+ PyGILState_STATE gstate;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)rightMouseDragged:(NSEvent *)event
+{
+ int x, y;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)otherMouseDown:(NSEvent *)event
+{
+ int x, y;
+ int num = 2;
+ int dblclick = 0;
+ PyObject* result;
+ PyGILState_STATE gstate;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ gstate = PyGILState_Ensure();
+ if ([event clickCount] == 2) {
+ dblclick = 1;
+ }
+ result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)otherMouseUp:(NSEvent *)event
+{
+ int x, y;
+ int num = 2;
+ PyObject* result;
+ PyGILState_STATE gstate;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)otherMouseDragged:(NSEvent *)event
+{
+ int x, y;
+ NSPoint location = [event locationInWindow];
+ location = [self convertPoint: location fromView: nil];
+ x = location.x * device_scale;
+ y = location.y * device_scale;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)setRubberband:(NSRect)rect
+{
+ if (!NSIsEmptyRect(rubberband)) [self setNeedsDisplayInRect: rubberband];
+ rubberband = rect;
+ [self setNeedsDisplayInRect: rubberband];
+}
+
+- (void)removeRubberband
+{
+ if (NSIsEmptyRect(rubberband)) return;
+ [self setNeedsDisplayInRect: rubberband];
+ rubberband = NSZeroRect;
+}
+
+
+
+- (const char*)convertKeyEvent:(NSEvent*)event
+{
+ NSDictionary* specialkeymappings = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"left", [NSNumber numberWithUnsignedLong:NSLeftArrowFunctionKey],
+ @"right", [NSNumber numberWithUnsignedLong:NSRightArrowFunctionKey],
+ @"up", [NSNumber numberWithUnsignedLong:NSUpArrowFunctionKey],
+ @"down", [NSNumber numberWithUnsignedLong:NSDownArrowFunctionKey],
+ @"f1", [NSNumber numberWithUnsignedLong:NSF1FunctionKey],
+ @"f2", [NSNumber numberWithUnsignedLong:NSF2FunctionKey],
+ @"f3", [NSNumber numberWithUnsignedLong:NSF3FunctionKey],
+ @"f4", [NSNumber numberWithUnsignedLong:NSF4FunctionKey],
+ @"f5", [NSNumber numberWithUnsignedLong:NSF5FunctionKey],
+ @"f6", [NSNumber numberWithUnsignedLong:NSF6FunctionKey],
+ @"f7", [NSNumber numberWithUnsignedLong:NSF7FunctionKey],
+ @"f8", [NSNumber numberWithUnsignedLong:NSF8FunctionKey],
+ @"f9", [NSNumber numberWithUnsignedLong:NSF9FunctionKey],
+ @"f10", [NSNumber numberWithUnsignedLong:NSF10FunctionKey],
+ @"f11", [NSNumber numberWithUnsignedLong:NSF11FunctionKey],
+ @"f12", [NSNumber numberWithUnsignedLong:NSF12FunctionKey],
+ @"f13", [NSNumber numberWithUnsignedLong:NSF13FunctionKey],
+ @"f14", [NSNumber numberWithUnsignedLong:NSF14FunctionKey],
+ @"f15", [NSNumber numberWithUnsignedLong:NSF15FunctionKey],
+ @"f16", [NSNumber numberWithUnsignedLong:NSF16FunctionKey],
+ @"f17", [NSNumber numberWithUnsignedLong:NSF17FunctionKey],
+ @"f18", [NSNumber numberWithUnsignedLong:NSF18FunctionKey],
+ @"f19", [NSNumber numberWithUnsignedLong:NSF19FunctionKey],
+ @"scroll_lock", [NSNumber numberWithUnsignedLong:NSScrollLockFunctionKey],
+ @"break", [NSNumber numberWithUnsignedLong:NSBreakFunctionKey],
+ @"insert", [NSNumber numberWithUnsignedLong:NSInsertFunctionKey],
+ @"delete", [NSNumber numberWithUnsignedLong:NSDeleteFunctionKey],
+ @"home", [NSNumber numberWithUnsignedLong:NSHomeFunctionKey],
+ @"end", [NSNumber numberWithUnsignedLong:NSEndFunctionKey],
+ @"pagedown", [NSNumber numberWithUnsignedLong:NSPageDownFunctionKey],
+ @"pageup", [NSNumber numberWithUnsignedLong:NSPageUpFunctionKey],
+ @"backspace", [NSNumber numberWithUnsignedLong:NSDeleteCharacter],
+ @"enter", [NSNumber numberWithUnsignedLong:NSEnterCharacter],
+ @"tab", [NSNumber numberWithUnsignedLong:NSTabCharacter],
+ @"enter", [NSNumber numberWithUnsignedLong:NSCarriageReturnCharacter],
+ @"backtab", [NSNumber numberWithUnsignedLong:NSBackTabCharacter],
+ @"escape", [NSNumber numberWithUnsignedLong:27],
+ nil
+ ];
+
+ NSMutableString* returnkey = [NSMutableString string];
+ if ([event modifierFlags] & NSControlKeyMask)
+ [returnkey appendString:@"ctrl+" ];
+ if ([event modifierFlags] & NSAlternateKeyMask)
+ [returnkey appendString:@"alt+" ];
+ if ([event modifierFlags] & NSCommandKeyMask)
+ [returnkey appendString:@"cmd+" ];
+
+ unichar uc = [[event charactersIgnoringModifiers] characterAtIndex:0];
+ NSString* specialchar = [specialkeymappings objectForKey:[NSNumber numberWithUnsignedLong:uc]];
+ if (specialchar){
+ if ([event modifierFlags] & NSShiftKeyMask)
+ [returnkey appendString:@"shift+" ];
+ [returnkey appendString:specialchar];
+ }
+ else
+ [returnkey appendString:[event charactersIgnoringModifiers]];
+
+ return [returnkey UTF8String];
+}
+
+- (void)keyDown:(NSEvent*)event
+{
+ PyObject* result;
+ const char* s = [self convertKeyEvent: event];
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ if (s==NULL)
+ {
+ result = PyObject_CallMethod(canvas, "key_press_event", "O", Py_None);
+ }
+ else
+ {
+ result = PyObject_CallMethod(canvas, "key_press_event", "s", s);
+ }
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)keyUp:(NSEvent*)event
+{
+ PyObject* result;
+ const char* s = [self convertKeyEvent: event];
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ if (s==NULL)
+ {
+ result = PyObject_CallMethod(canvas, "key_release_event", "O", Py_None);
+ }
+ else
+ {
+ result = PyObject_CallMethod(canvas, "key_release_event", "s", s);
+ }
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (void)scrollWheel:(NSEvent*)event
+{
+ int step;
+ float d = [event deltaY];
+ if (d > 0) step = 1;
+ else if (d < 0) step = -1;
+ else return;
+ NSPoint location = [event locationInWindow];
+ NSPoint point = [self convertPoint: location fromView: nil];
+ int x = (int)round(point.x * device_scale);
+ int y = (int)round(point.y * device_scale - 1);
+
+ PyObject* result;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ result = PyObject_CallMethod(canvas, "scroll_event", "iii", x, y, step);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+
+- (BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+/* This is all wrong. Address of pointer is being passed instead of pointer, keynames don't
+ match up with what the front-end and does the front-end even handle modifier keys by themselves?
+
+- (void)flagsChanged:(NSEvent*)event
+{
+ const char *s = NULL;
+ if (([event modifierFlags] & NSControlKeyMask) == NSControlKeyMask)
+ s = "control";
+ else if (([event modifierFlags] & NSShiftKeyMask) == NSShiftKeyMask)
+ s = "shift";
+ else if (([event modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask)
+ s = "alt";
+ else return;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallMethod(canvas, "key_press_event", "s", &s);
+ if(result)
+ Py_DECREF(result);
+ else
+ PyErr_Print();
+
+ PyGILState_Release(gstate);
+}
+ */
+@end
+
+@implementation ScrollableButton
+- (void)setScrollWheelUpAction:(SEL)action
+{
+ scrollWheelUpAction = action;
+}
+
+- (void)setScrollWheelDownAction:(SEL)action
+{
+ scrollWheelDownAction = action;
+}
+
+- (void)scrollWheel:(NSEvent*)event
+{
+ float d = [event deltaY];
+ Window* target = [self target];
+ if (d > 0)
+ [NSApp sendAction: scrollWheelUpAction to: target from: self];
+ else if (d < 0)
+ [NSApp sendAction: scrollWheelDownAction to: target from: self];
+}
+@end
+
+@implementation MenuItem
++ (MenuItem*)menuItemWithTitle: (NSString*)title
+{
+ MenuItem* item = [[MenuItem alloc] initWithTitle: title
+ action: nil
+ keyEquivalent: @""];
+ item->index = -1;
+ return [item autorelease];
+}
+
++ (MenuItem*)menuItemForAxis: (int)i
+{
+ NSString* title = [NSString stringWithFormat: @"Axis %d", i+1];
+ MenuItem* item = [[MenuItem alloc] initWithTitle: title
+ action: @selector(toggle:)
+ keyEquivalent: @""];
+ [item setTarget: item];
+ [item setState: NSOnState];
+ item->index = i;
+ return [item autorelease];
+}
+
++ (MenuItem*)menuItemSelectAll
+{
+ MenuItem* item = [[MenuItem alloc] initWithTitle: @"Select All"
+ action: @selector(selectAll:)
+ keyEquivalent: @""];
+ [item setTarget: item];
+ item->index = -1;
+ return [item autorelease];
+}
+
++ (MenuItem*)menuItemInvertAll
+{
+ MenuItem* item = [[MenuItem alloc] initWithTitle: @"Invert All"
+ action: @selector(invertAll:)
+ keyEquivalent: @""];
+ [item setTarget: item];
+ item->index = -1;
+ return [item autorelease];
+}
+
+- (void)toggle:(id)sender
+{
+ if ([self state]) [self setState: NSOffState];
+ else [self setState: NSOnState];
+}
+
+- (void)selectAll:(id)sender
+{
+ NSMenu* menu = [sender menu];
+ if(!menu) return; /* Weird */
+ NSArray* items = [menu itemArray];
+ NSEnumerator* enumerator = [items objectEnumerator];
+ MenuItem* item;
+ while ((item = [enumerator nextObject]))
+ {
+ if (item->index >= 0) [item setState: NSOnState];
+ }
+}
+
+- (void)invertAll:(id)sender
+{
+ NSMenu* menu = [sender menu];
+ if(!menu) return; /* Weird */
+ NSArray* items = [menu itemArray];
+ NSEnumerator* enumerator = [items objectEnumerator];
+ MenuItem* item;
+ while ((item = [enumerator nextObject]))
+ {
+ if (item->index < 0) continue;
+ if ([item state]==NSOffState) [item setState: NSOnState];
+ else [item setState: NSOffState];
+ }
+}
+
+- (int)index
+{
+ return self->index;
+}
+@end
+
+static PyObject*
+show(PyObject* self)
+{
+ [NSApp activateIgnoringOtherApps: YES];
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSArray *windowsArray = [NSApp windows];
+ NSEnumerator *enumerator = [windowsArray objectEnumerator];
+ NSWindow *window;
+ while ((window = [enumerator nextObject])) {
+ [window orderFront:nil];
+ }
+ [pool release];
+ Py_BEGIN_ALLOW_THREADS
+ [NSApp run];
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+typedef struct {
+ PyObject_HEAD
+ CFRunLoopTimerRef timer;
+} Timer;
+
+static PyObject*
+Timer_new(PyTypeObject* type, PyObject *args, PyObject *kwds)
+{
+ Timer* self = (Timer*)type->tp_alloc(type, 0);
+ if (!self) return NULL;
+ self->timer = NULL;
+ return (PyObject*) self;
+}
+
+static PyObject*
+Timer_repr(Timer* self)
+{
+#if PY3K
+ return PyUnicode_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p",
+ (void*) self, (void*)(self->timer));
+#else
+ return PyString_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p",
+ (void*) self, (void*)(self->timer));
+#endif
+}
+
+static char Timer_doc[] =
+"A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop.\n";
+
+static void timer_callback(CFRunLoopTimerRef timer, void* info)
+{
+ PyObject* method = info;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallFunction(method, NULL);
+ if (result) {
+ Py_DECREF(result);
+ } else {
+ PyErr_Print();
+ }
+ PyGILState_Release(gstate);
+}
+
+static void context_cleanup(const void* info)
+{
+ Py_DECREF((PyObject*)info);
+}
+
+static PyObject*
+Timer__timer_start(Timer* self, PyObject* args)
+{
+ CFRunLoopRef runloop;
+ CFRunLoopTimerRef timer;
+ CFRunLoopTimerContext context;
+ double milliseconds;
+ CFTimeInterval interval;
+ PyObject* attribute;
+ PyObject* failure;
+ runloop = CFRunLoopGetCurrent();
+ if (!runloop) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to obtain run loop");
+ return NULL;
+ }
+ attribute = PyObject_GetAttrString((PyObject*)self, "_interval");
+ if (attribute==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_interval'");
+ return NULL;
+ }
+ milliseconds = PyFloat_AsDouble(attribute);
+ failure = PyErr_Occurred();
+ Py_DECREF(attribute);
+ if (failure) return NULL;
+ attribute = PyObject_GetAttrString((PyObject*)self, "_single");
+ if (attribute==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_single'");
+ return NULL;
+ }
+ switch (PyObject_IsTrue(attribute)) {
+ case 1:
+ interval = 0;
+ break;
+ case 0:
+ interval = milliseconds / 1000.0;
+ break;
+ case -1:
+ default:
+ PyErr_SetString(PyExc_ValueError, "Cannot interpret _single attribute as True of False");
+ return NULL;
+ }
+ Py_DECREF(attribute);
+ attribute = PyObject_GetAttrString((PyObject*)self, "_on_timer");
+ if (attribute==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_on_timer'");
+ return NULL;
+ }
+ if (!PyMethod_Check(attribute)) {
+ PyErr_SetString(PyExc_RuntimeError, "_on_timer should be a Python method");
+ return NULL;
+ }
+ context.version = 0;
+ context.retain = NULL;
+ context.release = context_cleanup;
+ context.copyDescription = NULL;
+ context.info = attribute;
+ timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
+ 0,
+ interval,
+ 0,
+ 0,
+ timer_callback,
+ &context);
+ if (!timer) {
+ Py_DECREF(attribute);
+ PyErr_SetString(PyExc_RuntimeError, "Failed to create timer");
+ return NULL;
+ }
+ if (self->timer) {
+ CFRunLoopTimerInvalidate(self->timer);
+ CFRelease(self->timer);
+ }
+ CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes);
+ /* Don't release the timer here, since the run loop may be destroyed and
+ * the timer lost before we have a chance to decrease the reference count
+ * of the attribute */
+ self->timer = timer;
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+Timer__timer_stop(Timer* self)
+{
+ if (self->timer) {
+ CFRunLoopTimerInvalidate(self->timer);
+ CFRelease(self->timer);
+ self->timer = NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static void
+Timer_dealloc(Timer* self)
+{
+ Timer__timer_stop(self);
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyMethodDef Timer_methods[] = {
+ {"_timer_start",
+ (PyCFunction)Timer__timer_start,
+ METH_VARARGS,
+ "Initialize and start the timer."
+ },
+ {"_timer_stop",
+ (PyCFunction)Timer__timer_stop,
+ METH_NOARGS,
+ "Stop the timer."
+ },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject TimerType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_macosx.Timer", /*tp_name*/
+ sizeof(Timer), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Timer_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)Timer_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Timer_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Timer_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Timer_new, /* tp_new */
+};
+
+static bool verify_framework(void)
+{
+#ifdef COMPILING_FOR_10_6
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSRunningApplication* app = [NSRunningApplication currentApplication];
+ NSApplicationActivationPolicy activationPolicy = [app activationPolicy];
+ [pool release];
+ switch (activationPolicy) {
+ case NSApplicationActivationPolicyRegular:
+ case NSApplicationActivationPolicyAccessory:
+ return true;
+ case NSApplicationActivationPolicyProhibited:
+ break;
+ }
+#else
+ ProcessSerialNumber psn;
+ if (CGMainDisplayID()!=0
+ && GetCurrentProcess(&psn)==noErr
+ && SetFrontProcess(&psn)==noErr) return true;
+#endif
+ PyErr_SetString(PyExc_RuntimeError,
+ "Python is not installed as a framework. The Mac OS X backend will "
+ "not be able to function correctly if Python is not installed as a "
+ "framework. See the Python documentation for more information on "
+ "installing Python as a framework on Mac OS X. Please either reinstall "
+ "Python as a framework, or try one of the other backends. If you are "
+ "using (Ana)Conda please install python.app and replace the use of 'python' "
+ "with 'pythonw'. See 'Working with Matplotlib on OSX' "
+ "in the Matplotlib FAQ for more information.");
+ return false;
+}
+
+static struct PyMethodDef methods[] = {
+ {"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."
+ },
+ {"choose_save_file",
+ (PyCFunction)choose_save_file,
+ METH_VARARGS,
+ "Closes the window."
+ },
+ {"set_cursor",
+ (PyCFunction)set_cursor,
+ METH_VARARGS,
+ "Sets the active cursor."
+ },
+ {NULL, NULL, 0, NULL}/* sentinel */
+};
+
+#if PY3K
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "_macosx",
+ "Mac OS X native backend",
+ -1,
+ methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+PyObject* PyInit__macosx(void)
+
+#else
+
+void init_macosx(void)
+#endif
+{
+ PyObject *module;
+
+ if (PyType_Ready(&FigureCanvasType) < 0
+ || PyType_Ready(&FigureManagerType) < 0
+ || PyType_Ready(&NavigationToolbarType) < 0
+ || PyType_Ready(&NavigationToolbar2Type) < 0
+ || PyType_Ready(&TimerType) < 0)
+#if PY3K
+ return NULL;
+#else
+ return;
+#endif
+
+ NSApp = [NSApplication sharedApplication];
+
+ if (!verify_framework())
+#if PY3K
+ return NULL;
+#else
+ return;
+#endif
+
+#if PY3K
+ module = PyModule_Create(&moduledef);
+ if (module==NULL) return NULL;
+#else
+ module = Py_InitModule4("_macosx",
+ methods,
+ "Mac OS X native backend",
+ NULL,
+ PYTHON_API_VERSION);
+#endif
+
+ Py_INCREF(&FigureCanvasType);
+ Py_INCREF(&FigureManagerType);
+ Py_INCREF(&NavigationToolbarType);
+ Py_INCREF(&NavigationToolbar2Type);
+ Py_INCREF(&TimerType);
+ PyModule_AddObject(module, "FigureCanvas", (PyObject*) &FigureCanvasType);
+ PyModule_AddObject(module, "FigureManager", (PyObject*) &FigureManagerType);
+ PyModule_AddObject(module, "NavigationToolbar", (PyObject*) &NavigationToolbarType);
+ PyModule_AddObject(module, "NavigationToolbar2", (PyObject*) &NavigationToolbar2Type);
+ PyModule_AddObject(module, "Timer", (PyObject*) &TimerType);
+
+ PyOS_InputHook = wait_for_stdin;
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ WindowServerConnectionManager* connectionManager = [WindowServerConnectionManager sharedManager];
+ NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
+ NSNotificationCenter* notificationCenter = [workspace notificationCenter];
+ [notificationCenter addObserver: connectionManager
+ selector: @selector(launch:)
+ name: NSWorkspaceDidLaunchApplicationNotification
+ object: nil];
+ [pool release];
+#if PY3K
+ return module;
+#endif
+}