1 | #include <Cocoa/Cocoa.h> |
---|
2 | #include <ApplicationServices/ApplicationServices.h> |
---|
3 | #ifndef kCTForegroundColorFromContextAttributeName |
---|
4 | extern const CFStringRef kCTForegroundColorFromContextAttributeName AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; |
---|
5 | #endif |
---|
6 | #include <sys/socket.h> |
---|
7 | #include <Python.h> |
---|
8 | |
---|
9 | #define PYOSINPUTHOOK_REPETITIVE 1 /* Remove this once Python is fixed */ |
---|
10 | |
---|
11 | #if PY_MAJOR_VERSION >= 3 |
---|
12 | #define PY3K 1 |
---|
13 | #else |
---|
14 | #define PY3K 0 |
---|
15 | #endif |
---|
16 | |
---|
17 | /* Proper way to check for the OS X version we are compiling for, from |
---|
18 | http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development */ |
---|
19 | #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 |
---|
20 | #define COMPILING_FOR_10_6 |
---|
21 | #endif |
---|
22 | #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 |
---|
23 | #define COMPILING_FOR_10_7 |
---|
24 | #endif |
---|
25 | #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 10100 |
---|
26 | #define COMPILING_FOR_10_10 |
---|
27 | #endif |
---|
28 | |
---|
29 | |
---|
30 | /* CGFloat was defined in Mac OS X 10.5 */ |
---|
31 | #ifndef CGFLOAT_DEFINED |
---|
32 | #define CGFloat float |
---|
33 | #endif |
---|
34 | |
---|
35 | |
---|
36 | /* Various NSApplicationDefined event subtypes */ |
---|
37 | #define STOP_EVENT_LOOP 2 |
---|
38 | #define WINDOW_CLOSING 3 |
---|
39 | |
---|
40 | |
---|
41 | /* Keep track of number of windows present |
---|
42 | Needed to know when to stop the NSApp */ |
---|
43 | static long FigureWindowCount = 0; |
---|
44 | |
---|
45 | /* -------------------------- Helper function ---------------------------- */ |
---|
46 | |
---|
47 | static void |
---|
48 | _stdin_callback(CFReadStreamRef stream, CFStreamEventType eventType, void* info) |
---|
49 | { |
---|
50 | CFRunLoopRef runloop = info; |
---|
51 | CFRunLoopStop(runloop); |
---|
52 | } |
---|
53 | |
---|
54 | static int sigint_fd = -1; |
---|
55 | |
---|
56 | static void _sigint_handler(int sig) |
---|
57 | { |
---|
58 | const char c = 'i'; |
---|
59 | write(sigint_fd, &c, 1); |
---|
60 | } |
---|
61 | |
---|
62 | static void _sigint_callback(CFSocketRef s, |
---|
63 | CFSocketCallBackType type, |
---|
64 | CFDataRef address, |
---|
65 | const void * data, |
---|
66 | void *info) |
---|
67 | { |
---|
68 | char c; |
---|
69 | int* interrupted = info; |
---|
70 | CFSocketNativeHandle handle = CFSocketGetNative(s); |
---|
71 | CFRunLoopRef runloop = CFRunLoopGetCurrent(); |
---|
72 | read(handle, &c, 1); |
---|
73 | *interrupted = 1; |
---|
74 | CFRunLoopStop(runloop); |
---|
75 | } |
---|
76 | |
---|
77 | static CGEventRef _eventtap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) |
---|
78 | { |
---|
79 | CFRunLoopRef runloop = refcon; |
---|
80 | CFRunLoopStop(runloop); |
---|
81 | return event; |
---|
82 | } |
---|
83 | |
---|
84 | static int wait_for_stdin(void) |
---|
85 | { |
---|
86 | int interrupted = 0; |
---|
87 | const UInt8 buffer[] = "/dev/fd/0"; |
---|
88 | const CFIndex n = (CFIndex)strlen((char*)buffer); |
---|
89 | CFRunLoopRef runloop = CFRunLoopGetCurrent(); |
---|
90 | CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, |
---|
91 | buffer, |
---|
92 | n, |
---|
93 | false); |
---|
94 | CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, |
---|
95 | url); |
---|
96 | CFRelease(url); |
---|
97 | |
---|
98 | CFReadStreamOpen(stream); |
---|
99 | #ifdef PYOSINPUTHOOK_REPETITIVE |
---|
100 | if (!CFReadStreamHasBytesAvailable(stream)) |
---|
101 | /* This is possible because of how PyOS_InputHook is called from Python */ |
---|
102 | { |
---|
103 | #endif |
---|
104 | int error; |
---|
105 | int channel[2]; |
---|
106 | CFSocketRef sigint_socket = NULL; |
---|
107 | PyOS_sighandler_t py_sigint_handler = NULL; |
---|
108 | CFStreamClientContext clientContext = {0, NULL, NULL, NULL, NULL}; |
---|
109 | clientContext.info = runloop; |
---|
110 | CFReadStreamSetClient(stream, |
---|
111 | kCFStreamEventHasBytesAvailable, |
---|
112 | _stdin_callback, |
---|
113 | &clientContext); |
---|
114 | CFReadStreamScheduleWithRunLoop(stream, runloop, kCFRunLoopDefaultMode); |
---|
115 | error = socketpair(AF_UNIX, SOCK_STREAM, 0, channel); |
---|
116 | if (error==0) |
---|
117 | { |
---|
118 | CFSocketContext context; |
---|
119 | context.version = 0; |
---|
120 | context.info = &interrupted; |
---|
121 | context.retain = NULL; |
---|
122 | context.release = NULL; |
---|
123 | context.copyDescription = NULL; |
---|
124 | fcntl(channel[0], F_SETFL, O_WRONLY | O_NONBLOCK); |
---|
125 | sigint_socket = CFSocketCreateWithNative( |
---|
126 | kCFAllocatorDefault, |
---|
127 | channel[1], |
---|
128 | kCFSocketReadCallBack, |
---|
129 | _sigint_callback, |
---|
130 | &context); |
---|
131 | if (sigint_socket) |
---|
132 | { |
---|
133 | CFRunLoopSourceRef source; |
---|
134 | source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, |
---|
135 | sigint_socket, |
---|
136 | 0); |
---|
137 | CFRelease(sigint_socket); |
---|
138 | if (source) |
---|
139 | { |
---|
140 | CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode); |
---|
141 | CFRelease(source); |
---|
142 | sigint_fd = channel[0]; |
---|
143 | py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler); |
---|
144 | } |
---|
145 | } |
---|
146 | } |
---|
147 | |
---|
148 | NSEvent* event; |
---|
149 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
150 | while (true) { |
---|
151 | while (true) { |
---|
152 | event = [NSApp nextEventMatchingMask: NSAnyEventMask |
---|
153 | untilDate: [NSDate distantPast] |
---|
154 | inMode: NSDefaultRunLoopMode |
---|
155 | dequeue: YES]; |
---|
156 | if (!event) break; |
---|
157 | [NSApp sendEvent: event]; |
---|
158 | } |
---|
159 | CFRunLoopRun(); |
---|
160 | if (interrupted || CFReadStreamHasBytesAvailable(stream)) break; |
---|
161 | } |
---|
162 | [pool release]; |
---|
163 | |
---|
164 | if (py_sigint_handler) PyOS_setsig(SIGINT, py_sigint_handler); |
---|
165 | CFReadStreamUnscheduleFromRunLoop(stream, |
---|
166 | runloop, |
---|
167 | kCFRunLoopCommonModes); |
---|
168 | if (sigint_socket) CFSocketInvalidate(sigint_socket); |
---|
169 | if (error==0) { |
---|
170 | close(channel[0]); |
---|
171 | close(channel[1]); |
---|
172 | } |
---|
173 | #ifdef PYOSINPUTHOOK_REPETITIVE |
---|
174 | } |
---|
175 | #endif |
---|
176 | CFReadStreamClose(stream); |
---|
177 | CFRelease(stream); |
---|
178 | if (interrupted) { |
---|
179 | errno = EINTR; |
---|
180 | raise(SIGINT); |
---|
181 | return -1; |
---|
182 | } |
---|
183 | return 1; |
---|
184 | } |
---|
185 | |
---|
186 | /* ---------------------------- Cocoa classes ---------------------------- */ |
---|
187 | |
---|
188 | @interface WindowServerConnectionManager : NSObject |
---|
189 | { |
---|
190 | } |
---|
191 | + (WindowServerConnectionManager*)sharedManager; |
---|
192 | - (void)launch:(NSNotification*)notification; |
---|
193 | @end |
---|
194 | |
---|
195 | @interface Window : NSWindow |
---|
196 | { PyObject* manager; |
---|
197 | } |
---|
198 | - (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager; |
---|
199 | - (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen; |
---|
200 | - (BOOL)closeButtonPressed; |
---|
201 | - (void)dealloc; |
---|
202 | @end |
---|
203 | |
---|
204 | @interface ToolWindow : NSWindow |
---|
205 | { |
---|
206 | } |
---|
207 | - (ToolWindow*)initWithContentRect:(NSRect)rect master:(NSWindow*)window; |
---|
208 | - (void)masterCloses:(NSNotification*)notification; |
---|
209 | - (void)close; |
---|
210 | @end |
---|
211 | |
---|
212 | #ifdef COMPILING_FOR_10_6 |
---|
213 | @interface View : NSView <NSWindowDelegate> |
---|
214 | #else |
---|
215 | @interface View : NSView |
---|
216 | #endif |
---|
217 | { PyObject* canvas; |
---|
218 | NSRect rubberband; |
---|
219 | BOOL inside; |
---|
220 | NSTrackingRectTag tracking; |
---|
221 | @public double device_scale; |
---|
222 | } |
---|
223 | - (void)dealloc; |
---|
224 | - (void)drawRect:(NSRect)rect; |
---|
225 | - (void)windowDidResize:(NSNotification*)notification; |
---|
226 | - (View*)initWithFrame:(NSRect)rect; |
---|
227 | - (void)setCanvas: (PyObject*)newCanvas; |
---|
228 | - (void)windowWillClose:(NSNotification*)notification; |
---|
229 | - (BOOL)windowShouldClose:(NSNotification*)notification; |
---|
230 | - (BOOL)isFlipped; |
---|
231 | - (void)mouseEntered:(NSEvent*)event; |
---|
232 | - (void)mouseExited:(NSEvent*)event; |
---|
233 | - (void)mouseDown:(NSEvent*)event; |
---|
234 | - (void)mouseUp:(NSEvent*)event; |
---|
235 | - (void)mouseDragged:(NSEvent*)event; |
---|
236 | - (void)mouseMoved:(NSEvent*)event; |
---|
237 | - (void)rightMouseDown:(NSEvent*)event; |
---|
238 | - (void)rightMouseUp:(NSEvent*)event; |
---|
239 | - (void)rightMouseDragged:(NSEvent*)event; |
---|
240 | - (void)otherMouseDown:(NSEvent*)event; |
---|
241 | - (void)otherMouseUp:(NSEvent*)event; |
---|
242 | - (void)otherMouseDragged:(NSEvent*)event; |
---|
243 | - (void)setRubberband:(NSRect)rect; |
---|
244 | - (void)removeRubberband; |
---|
245 | - (const char*)convertKeyEvent:(NSEvent*)event; |
---|
246 | - (void)keyDown:(NSEvent*)event; |
---|
247 | - (void)keyUp:(NSEvent*)event; |
---|
248 | - (void)scrollWheel:(NSEvent *)event; |
---|
249 | - (BOOL)acceptsFirstResponder; |
---|
250 | //- (void)flagsChanged:(NSEvent*)event; |
---|
251 | @end |
---|
252 | |
---|
253 | @interface ScrollableButton : NSButton |
---|
254 | { |
---|
255 | SEL scrollWheelUpAction; |
---|
256 | SEL scrollWheelDownAction; |
---|
257 | } |
---|
258 | - (void)setScrollWheelUpAction:(SEL)action; |
---|
259 | - (void)setScrollWheelDownAction:(SEL)action; |
---|
260 | - (void)scrollWheel:(NSEvent *)event; |
---|
261 | @end |
---|
262 | |
---|
263 | @interface MenuItem: NSMenuItem |
---|
264 | { int index; |
---|
265 | } |
---|
266 | + (MenuItem*)menuItemWithTitle:(NSString*)title; |
---|
267 | + (MenuItem*)menuItemSelectAll; |
---|
268 | + (MenuItem*)menuItemInvertAll; |
---|
269 | + (MenuItem*)menuItemForAxis:(int)i; |
---|
270 | - (void)toggle:(id)sender; |
---|
271 | - (void)selectAll:(id)sender; |
---|
272 | - (void)invertAll:(id)sender; |
---|
273 | - (int)index; |
---|
274 | @end |
---|
275 | |
---|
276 | /* ---------------------------- Python classes ---------------------------- */ |
---|
277 | |
---|
278 | static CGFloat _get_device_scale(CGContextRef cr) |
---|
279 | { |
---|
280 | CGSize pixelSize = CGContextConvertSizeToDeviceSpace(cr, CGSizeMake(1, 1)); |
---|
281 | return pixelSize.width; |
---|
282 | } |
---|
283 | |
---|
284 | typedef struct { |
---|
285 | PyObject_HEAD |
---|
286 | View* view; |
---|
287 | } FigureCanvas; |
---|
288 | |
---|
289 | static PyObject* |
---|
290 | FigureCanvas_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
---|
291 | { |
---|
292 | FigureCanvas *self = (FigureCanvas*)type->tp_alloc(type, 0); |
---|
293 | if (!self) return NULL; |
---|
294 | self->view = [View alloc]; |
---|
295 | return (PyObject*)self; |
---|
296 | } |
---|
297 | |
---|
298 | static int |
---|
299 | FigureCanvas_init(FigureCanvas *self, PyObject *args, PyObject *kwds) |
---|
300 | { |
---|
301 | int width; |
---|
302 | int height; |
---|
303 | if(!self->view) |
---|
304 | { |
---|
305 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
306 | return -1; |
---|
307 | } |
---|
308 | |
---|
309 | if(!PyArg_ParseTuple(args, "ii", &width, &height)) return -1; |
---|
310 | |
---|
311 | NSRect rect = NSMakeRect(0.0, 0.0, width, height); |
---|
312 | self->view = [self->view initWithFrame: rect]; |
---|
313 | [self->view setCanvas: (PyObject*)self]; |
---|
314 | return 0; |
---|
315 | } |
---|
316 | |
---|
317 | static void |
---|
318 | FigureCanvas_dealloc(FigureCanvas* self) |
---|
319 | { |
---|
320 | if (self->view) |
---|
321 | { |
---|
322 | [self->view setCanvas: NULL]; |
---|
323 | [self->view release]; |
---|
324 | } |
---|
325 | Py_TYPE(self)->tp_free((PyObject*)self); |
---|
326 | } |
---|
327 | |
---|
328 | static PyObject* |
---|
329 | FigureCanvas_repr(FigureCanvas* self) |
---|
330 | { |
---|
331 | #if PY3K |
---|
332 | return PyUnicode_FromFormat("FigureCanvas object %p wrapping NSView %p", |
---|
333 | (void*)self, (void*)(self->view)); |
---|
334 | #else |
---|
335 | return PyString_FromFormat("FigureCanvas object %p wrapping NSView %p", |
---|
336 | (void*)self, (void*)(self->view)); |
---|
337 | #endif |
---|
338 | } |
---|
339 | |
---|
340 | static PyObject* |
---|
341 | FigureCanvas_draw(FigureCanvas* self) |
---|
342 | { |
---|
343 | View* view = self->view; |
---|
344 | |
---|
345 | if(view) /* The figure may have been closed already */ |
---|
346 | { |
---|
347 | /* Whereas drawRect creates its own autorelease pool, apparently |
---|
348 | * [view display] also needs one. Create and release it here. */ |
---|
349 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
350 | [view display]; |
---|
351 | [pool release]; |
---|
352 | } |
---|
353 | |
---|
354 | Py_RETURN_NONE; |
---|
355 | } |
---|
356 | |
---|
357 | static PyObject* |
---|
358 | FigureCanvas_invalidate(FigureCanvas* self) |
---|
359 | { |
---|
360 | View* view = self->view; |
---|
361 | if(!view) |
---|
362 | { |
---|
363 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
364 | return NULL; |
---|
365 | } |
---|
366 | [view setNeedsDisplay: YES]; |
---|
367 | Py_RETURN_NONE; |
---|
368 | } |
---|
369 | |
---|
370 | static PyObject* |
---|
371 | FigureCanvas_flush_events(FigureCanvas* self) |
---|
372 | { |
---|
373 | View* view = self->view; |
---|
374 | if(!view) |
---|
375 | { |
---|
376 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
377 | return NULL; |
---|
378 | } |
---|
379 | [view displayIfNeeded]; |
---|
380 | Py_RETURN_NONE; |
---|
381 | } |
---|
382 | |
---|
383 | static PyObject* |
---|
384 | FigureCanvas_set_rubberband(FigureCanvas* self, PyObject *args) |
---|
385 | { |
---|
386 | View* view = self->view; |
---|
387 | int x0, y0, x1, y1; |
---|
388 | NSRect rubberband; |
---|
389 | if(!view) |
---|
390 | { |
---|
391 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
392 | return NULL; |
---|
393 | } |
---|
394 | if(!PyArg_ParseTuple(args, "iiii", &x0, &y0, &x1, &y1)) return NULL; |
---|
395 | |
---|
396 | x0 /= view->device_scale; |
---|
397 | x1 /= view->device_scale; |
---|
398 | y0 /= view->device_scale; |
---|
399 | y1 /= view->device_scale; |
---|
400 | |
---|
401 | if (x1 > x0) |
---|
402 | { |
---|
403 | rubberband.origin.x = x0; |
---|
404 | rubberband.size.width = x1 - x0; |
---|
405 | } |
---|
406 | else |
---|
407 | { |
---|
408 | rubberband.origin.x = x1; |
---|
409 | rubberband.size.width = x0 - x1; |
---|
410 | } |
---|
411 | if (y1 > y0) |
---|
412 | { |
---|
413 | rubberband.origin.y = y0; |
---|
414 | rubberband.size.height = y1 - y0; |
---|
415 | } |
---|
416 | else |
---|
417 | { |
---|
418 | rubberband.origin.y = y1; |
---|
419 | rubberband.size.height = y0 - y1; |
---|
420 | } |
---|
421 | |
---|
422 | [view setRubberband: rubberband]; |
---|
423 | Py_RETURN_NONE; |
---|
424 | } |
---|
425 | |
---|
426 | static PyObject* |
---|
427 | FigureCanvas_remove_rubberband(FigureCanvas* self) |
---|
428 | { |
---|
429 | View* view = self->view; |
---|
430 | if(!view) |
---|
431 | { |
---|
432 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
433 | return NULL; |
---|
434 | } |
---|
435 | [view removeRubberband]; |
---|
436 | Py_RETURN_NONE; |
---|
437 | } |
---|
438 | |
---|
439 | static NSImage* _read_ppm_image(PyObject* obj) |
---|
440 | { |
---|
441 | int width; |
---|
442 | int height; |
---|
443 | const char* data; |
---|
444 | int n; |
---|
445 | int i; |
---|
446 | NSBitmapImageRep* bitmap; |
---|
447 | unsigned char* bitmapdata; |
---|
448 | |
---|
449 | if (!obj) return NULL; |
---|
450 | if (!PyTuple_Check(obj)) return NULL; |
---|
451 | if (!PyArg_ParseTuple(obj, "iit#", &width, &height, &data, &n)) return NULL; |
---|
452 | if (width*height*3 != n) return NULL; /* RGB image uses 3 colors / pixel */ |
---|
453 | |
---|
454 | bitmap = [[NSBitmapImageRep alloc] |
---|
455 | initWithBitmapDataPlanes: NULL |
---|
456 | pixelsWide: width |
---|
457 | pixelsHigh: height |
---|
458 | bitsPerSample: 8 |
---|
459 | samplesPerPixel: 3 |
---|
460 | hasAlpha: NO |
---|
461 | isPlanar: NO |
---|
462 | colorSpaceName: NSDeviceRGBColorSpace |
---|
463 | bitmapFormat: 0 |
---|
464 | bytesPerRow: width*3 |
---|
465 | bitsPerPixel: 24]; |
---|
466 | if (!bitmap) return NULL; |
---|
467 | bitmapdata = [bitmap bitmapData]; |
---|
468 | for (i = 0; i < n; i++) bitmapdata[i] = data[i]; |
---|
469 | |
---|
470 | NSSize size = NSMakeSize(width, height); |
---|
471 | NSImage* image = [[NSImage alloc] initWithSize: size]; |
---|
472 | if (image) [image addRepresentation: bitmap]; |
---|
473 | |
---|
474 | [bitmap release]; |
---|
475 | |
---|
476 | return image; |
---|
477 | } |
---|
478 | |
---|
479 | static PyObject* |
---|
480 | FigureCanvas_start_event_loop(FigureCanvas* self, PyObject* args, PyObject* keywords) |
---|
481 | { |
---|
482 | float timeout = 0.0; |
---|
483 | |
---|
484 | static char* kwlist[] = {"timeout", NULL}; |
---|
485 | if(!PyArg_ParseTupleAndKeywords(args, keywords, "f", kwlist, &timeout)) |
---|
486 | return NULL; |
---|
487 | |
---|
488 | int error; |
---|
489 | int interrupted = 0; |
---|
490 | int channel[2]; |
---|
491 | CFSocketRef sigint_socket = NULL; |
---|
492 | PyOS_sighandler_t py_sigint_handler = NULL; |
---|
493 | |
---|
494 | CFRunLoopRef runloop = CFRunLoopGetCurrent(); |
---|
495 | |
---|
496 | error = pipe(channel); |
---|
497 | if (error==0) |
---|
498 | { |
---|
499 | CFSocketContext context = {0, NULL, NULL, NULL, NULL}; |
---|
500 | fcntl(channel[1], F_SETFL, O_WRONLY | O_NONBLOCK); |
---|
501 | |
---|
502 | context.info = &interrupted; |
---|
503 | sigint_socket = CFSocketCreateWithNative(kCFAllocatorDefault, |
---|
504 | channel[0], |
---|
505 | kCFSocketReadCallBack, |
---|
506 | _sigint_callback, |
---|
507 | &context); |
---|
508 | if (sigint_socket) |
---|
509 | { |
---|
510 | CFRunLoopSourceRef source; |
---|
511 | source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, |
---|
512 | sigint_socket, |
---|
513 | 0); |
---|
514 | CFRelease(sigint_socket); |
---|
515 | if (source) |
---|
516 | { |
---|
517 | CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode); |
---|
518 | CFRelease(source); |
---|
519 | sigint_fd = channel[1]; |
---|
520 | py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler); |
---|
521 | } |
---|
522 | } |
---|
523 | else |
---|
524 | close(channel[0]); |
---|
525 | } |
---|
526 | |
---|
527 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
528 | NSDate* date = |
---|
529 | (timeout > 0.0) ? [NSDate dateWithTimeIntervalSinceNow: timeout] |
---|
530 | : [NSDate distantFuture]; |
---|
531 | while (true) |
---|
532 | { NSEvent* event = [NSApp nextEventMatchingMask: NSAnyEventMask |
---|
533 | untilDate: date |
---|
534 | inMode: NSDefaultRunLoopMode |
---|
535 | dequeue: YES]; |
---|
536 | if (!event || [event type]==NSApplicationDefined) break; |
---|
537 | [NSApp sendEvent: event]; |
---|
538 | } |
---|
539 | [pool release]; |
---|
540 | |
---|
541 | if (py_sigint_handler) PyOS_setsig(SIGINT, py_sigint_handler); |
---|
542 | |
---|
543 | if (sigint_socket) CFSocketInvalidate(sigint_socket); |
---|
544 | if (error==0) close(channel[1]); |
---|
545 | if (interrupted) raise(SIGINT); |
---|
546 | |
---|
547 | Py_RETURN_NONE; |
---|
548 | } |
---|
549 | |
---|
550 | static PyObject* |
---|
551 | FigureCanvas_stop_event_loop(FigureCanvas* self) |
---|
552 | { |
---|
553 | NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined |
---|
554 | location: NSZeroPoint |
---|
555 | modifierFlags: 0 |
---|
556 | timestamp: 0.0 |
---|
557 | windowNumber: 0 |
---|
558 | context: nil |
---|
559 | subtype: STOP_EVENT_LOOP |
---|
560 | data1: 0 |
---|
561 | data2: 0]; |
---|
562 | [NSApp postEvent: event atStart: true]; |
---|
563 | Py_RETURN_NONE; |
---|
564 | } |
---|
565 | |
---|
566 | static PyMethodDef FigureCanvas_methods[] = { |
---|
567 | {"draw", |
---|
568 | (PyCFunction)FigureCanvas_draw, |
---|
569 | METH_NOARGS, |
---|
570 | "Draws the canvas." |
---|
571 | }, |
---|
572 | {"invalidate", |
---|
573 | (PyCFunction)FigureCanvas_invalidate, |
---|
574 | METH_NOARGS, |
---|
575 | "Invalidates the canvas." |
---|
576 | }, |
---|
577 | {"flush_events", |
---|
578 | (PyCFunction)FigureCanvas_flush_events, |
---|
579 | METH_NOARGS, |
---|
580 | "Flush the GUI events for the figure." |
---|
581 | }, |
---|
582 | {"set_rubberband", |
---|
583 | (PyCFunction)FigureCanvas_set_rubberband, |
---|
584 | METH_VARARGS, |
---|
585 | "Specifies a new rubberband rectangle and invalidates it." |
---|
586 | }, |
---|
587 | {"remove_rubberband", |
---|
588 | (PyCFunction)FigureCanvas_remove_rubberband, |
---|
589 | METH_NOARGS, |
---|
590 | "Removes the current rubberband rectangle." |
---|
591 | }, |
---|
592 | {"start_event_loop", |
---|
593 | (PyCFunction)FigureCanvas_start_event_loop, |
---|
594 | METH_KEYWORDS | METH_VARARGS, |
---|
595 | "Runs the event loop until the timeout or until stop_event_loop is called.\n", |
---|
596 | }, |
---|
597 | {"stop_event_loop", |
---|
598 | (PyCFunction)FigureCanvas_stop_event_loop, |
---|
599 | METH_NOARGS, |
---|
600 | "Stops the event loop that was started by start_event_loop.\n", |
---|
601 | }, |
---|
602 | {NULL} /* Sentinel */ |
---|
603 | }; |
---|
604 | |
---|
605 | static char FigureCanvas_doc[] = |
---|
606 | "A FigureCanvas object wraps a Cocoa NSView object.\n"; |
---|
607 | |
---|
608 | static PyTypeObject FigureCanvasType = { |
---|
609 | PyVarObject_HEAD_INIT(NULL, 0) |
---|
610 | "_macosx.FigureCanvas", /*tp_name*/ |
---|
611 | sizeof(FigureCanvas), /*tp_basicsize*/ |
---|
612 | 0, /*tp_itemsize*/ |
---|
613 | (destructor)FigureCanvas_dealloc, /*tp_dealloc*/ |
---|
614 | 0, /*tp_print*/ |
---|
615 | 0, /*tp_getattr*/ |
---|
616 | 0, /*tp_setattr*/ |
---|
617 | 0, /*tp_compare*/ |
---|
618 | (reprfunc)FigureCanvas_repr, /*tp_repr*/ |
---|
619 | 0, /*tp_as_number*/ |
---|
620 | 0, /*tp_as_sequence*/ |
---|
621 | 0, /*tp_as_mapping*/ |
---|
622 | 0, /*tp_hash */ |
---|
623 | 0, /*tp_call*/ |
---|
624 | 0, /*tp_str*/ |
---|
625 | 0, /*tp_getattro*/ |
---|
626 | 0, /*tp_setattro*/ |
---|
627 | 0, /*tp_as_buffer*/ |
---|
628 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
629 | FigureCanvas_doc, /* tp_doc */ |
---|
630 | 0, /* tp_traverse */ |
---|
631 | 0, /* tp_clear */ |
---|
632 | 0, /* tp_richcompare */ |
---|
633 | 0, /* tp_weaklistoffset */ |
---|
634 | 0, /* tp_iter */ |
---|
635 | 0, /* tp_iternext */ |
---|
636 | FigureCanvas_methods, /* tp_methods */ |
---|
637 | 0, /* tp_members */ |
---|
638 | 0, /* tp_getset */ |
---|
639 | 0, /* tp_base */ |
---|
640 | 0, /* tp_dict */ |
---|
641 | 0, /* tp_descr_get */ |
---|
642 | 0, /* tp_descr_set */ |
---|
643 | 0, /* tp_dictoffset */ |
---|
644 | (initproc)FigureCanvas_init, /* tp_init */ |
---|
645 | 0, /* tp_alloc */ |
---|
646 | FigureCanvas_new, /* tp_new */ |
---|
647 | }; |
---|
648 | |
---|
649 | typedef struct { |
---|
650 | PyObject_HEAD |
---|
651 | Window* window; |
---|
652 | } FigureManager; |
---|
653 | |
---|
654 | static PyObject* |
---|
655 | FigureManager_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
---|
656 | { |
---|
657 | Window* window = [Window alloc]; |
---|
658 | if (!window) return NULL; |
---|
659 | FigureManager *self = (FigureManager*)type->tp_alloc(type, 0); |
---|
660 | if (!self) |
---|
661 | { |
---|
662 | [window release]; |
---|
663 | return NULL; |
---|
664 | } |
---|
665 | self->window = window; |
---|
666 | ++FigureWindowCount; |
---|
667 | return (PyObject*)self; |
---|
668 | } |
---|
669 | |
---|
670 | static int |
---|
671 | FigureManager_init(FigureManager *self, PyObject *args, PyObject *kwds) |
---|
672 | { |
---|
673 | NSRect rect; |
---|
674 | Window* window; |
---|
675 | View* view; |
---|
676 | const char* title; |
---|
677 | PyObject* size; |
---|
678 | int width, height; |
---|
679 | PyObject* obj; |
---|
680 | FigureCanvas* canvas; |
---|
681 | |
---|
682 | if(!self->window) |
---|
683 | { |
---|
684 | PyErr_SetString(PyExc_RuntimeError, "NSWindow* is NULL"); |
---|
685 | return -1; |
---|
686 | } |
---|
687 | |
---|
688 | if(!PyArg_ParseTuple(args, "Os", &obj, &title)) return -1; |
---|
689 | |
---|
690 | canvas = (FigureCanvas*)obj; |
---|
691 | view = canvas->view; |
---|
692 | if (!view) /* Something really weird going on */ |
---|
693 | { |
---|
694 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
695 | return -1; |
---|
696 | } |
---|
697 | |
---|
698 | size = PyObject_CallMethod(obj, "get_width_height", ""); |
---|
699 | if(!size) return -1; |
---|
700 | if(!PyArg_ParseTuple(size, "ii", &width, &height)) |
---|
701 | { Py_DECREF(size); |
---|
702 | return -1; |
---|
703 | } |
---|
704 | Py_DECREF(size); |
---|
705 | |
---|
706 | rect.origin.x = 100; |
---|
707 | rect.origin.y = 350; |
---|
708 | rect.size.height = height; |
---|
709 | rect.size.width = width; |
---|
710 | |
---|
711 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
712 | self->window = [self->window initWithContentRect: rect |
---|
713 | styleMask: NSTitledWindowMask |
---|
714 | | NSClosableWindowMask |
---|
715 | | NSResizableWindowMask |
---|
716 | | NSMiniaturizableWindowMask |
---|
717 | backing: NSBackingStoreBuffered |
---|
718 | defer: YES |
---|
719 | withManager: (PyObject*)self]; |
---|
720 | window = self->window; |
---|
721 | [window setTitle: [NSString stringWithCString: title |
---|
722 | encoding: NSASCIIStringEncoding]]; |
---|
723 | |
---|
724 | [window setAcceptsMouseMovedEvents: YES]; |
---|
725 | [window setDelegate: view]; |
---|
726 | [window makeFirstResponder: view]; |
---|
727 | [[window contentView] addSubview: view]; |
---|
728 | |
---|
729 | [pool release]; |
---|
730 | return 0; |
---|
731 | } |
---|
732 | |
---|
733 | static PyObject* |
---|
734 | FigureManager_repr(FigureManager* self) |
---|
735 | { |
---|
736 | #if PY3K |
---|
737 | return PyUnicode_FromFormat("FigureManager object %p wrapping NSWindow %p", |
---|
738 | (void*) self, (void*)(self->window)); |
---|
739 | #else |
---|
740 | return PyString_FromFormat("FigureManager object %p wrapping NSWindow %p", |
---|
741 | (void*) self, (void*)(self->window)); |
---|
742 | #endif |
---|
743 | } |
---|
744 | |
---|
745 | static void |
---|
746 | FigureManager_dealloc(FigureManager* self) |
---|
747 | { |
---|
748 | Window* window = self->window; |
---|
749 | if(window) |
---|
750 | { |
---|
751 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
752 | [window close]; |
---|
753 | [pool release]; |
---|
754 | } |
---|
755 | Py_TYPE(self)->tp_free((PyObject*)self); |
---|
756 | } |
---|
757 | |
---|
758 | static PyObject* |
---|
759 | FigureManager_show(FigureManager* self) |
---|
760 | { |
---|
761 | Window* window = self->window; |
---|
762 | if(window) |
---|
763 | { |
---|
764 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
765 | [window makeKeyAndOrderFront: nil]; |
---|
766 | [window orderFrontRegardless]; |
---|
767 | [pool release]; |
---|
768 | } |
---|
769 | Py_RETURN_NONE; |
---|
770 | } |
---|
771 | |
---|
772 | static PyObject* |
---|
773 | FigureManager_destroy(FigureManager* self) |
---|
774 | { |
---|
775 | Window* window = self->window; |
---|
776 | if(window) |
---|
777 | { |
---|
778 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
779 | [window close]; |
---|
780 | [pool release]; |
---|
781 | self->window = NULL; |
---|
782 | } |
---|
783 | Py_RETURN_NONE; |
---|
784 | } |
---|
785 | |
---|
786 | static PyObject* |
---|
787 | FigureManager_set_window_title(FigureManager* self, |
---|
788 | PyObject *args, PyObject *kwds) |
---|
789 | { |
---|
790 | char* title; |
---|
791 | if(!PyArg_ParseTuple(args, "es", "UTF-8", &title)) |
---|
792 | return NULL; |
---|
793 | |
---|
794 | Window* window = self->window; |
---|
795 | if(window) |
---|
796 | { |
---|
797 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
798 | NSString* ns_title = [[[NSString alloc] |
---|
799 | initWithCString: title |
---|
800 | encoding: NSUTF8StringEncoding] autorelease]; |
---|
801 | [window setTitle: ns_title]; |
---|
802 | [pool release]; |
---|
803 | } |
---|
804 | PyMem_Free(title); |
---|
805 | Py_RETURN_NONE; |
---|
806 | } |
---|
807 | |
---|
808 | static PyObject* |
---|
809 | FigureManager_get_window_title(FigureManager* self) |
---|
810 | { |
---|
811 | Window* window = self->window; |
---|
812 | PyObject* result = NULL; |
---|
813 | if(window) |
---|
814 | { |
---|
815 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
816 | NSString* title = [window title]; |
---|
817 | if (title) { |
---|
818 | const char* cTitle = [title UTF8String]; |
---|
819 | result = PyUnicode_FromString(cTitle); |
---|
820 | } |
---|
821 | [pool release]; |
---|
822 | } |
---|
823 | if (result) { |
---|
824 | return result; |
---|
825 | } else { |
---|
826 | Py_RETURN_NONE; |
---|
827 | } |
---|
828 | } |
---|
829 | |
---|
830 | static PyMethodDef FigureManager_methods[] = { |
---|
831 | {"show", |
---|
832 | (PyCFunction)FigureManager_show, |
---|
833 | METH_NOARGS, |
---|
834 | "Shows the window associated with the figure manager." |
---|
835 | }, |
---|
836 | {"destroy", |
---|
837 | (PyCFunction)FigureManager_destroy, |
---|
838 | METH_NOARGS, |
---|
839 | "Closes the window associated with the figure manager." |
---|
840 | }, |
---|
841 | {"set_window_title", |
---|
842 | (PyCFunction)FigureManager_set_window_title, |
---|
843 | METH_VARARGS, |
---|
844 | "Sets the title of the window associated with the figure manager." |
---|
845 | }, |
---|
846 | {"get_window_title", |
---|
847 | (PyCFunction)FigureManager_get_window_title, |
---|
848 | METH_NOARGS, |
---|
849 | "Returns the title of the window associated with the figure manager." |
---|
850 | }, |
---|
851 | {NULL} /* Sentinel */ |
---|
852 | }; |
---|
853 | |
---|
854 | static char FigureManager_doc[] = |
---|
855 | "A FigureManager object wraps a Cocoa NSWindow object.\n"; |
---|
856 | |
---|
857 | static PyTypeObject FigureManagerType = { |
---|
858 | PyVarObject_HEAD_INIT(NULL, 0) |
---|
859 | "_macosx.FigureManager", /*tp_name*/ |
---|
860 | sizeof(FigureManager), /*tp_basicsize*/ |
---|
861 | 0, /*tp_itemsize*/ |
---|
862 | (destructor)FigureManager_dealloc, /*tp_dealloc*/ |
---|
863 | 0, /*tp_print*/ |
---|
864 | 0, /*tp_getattr*/ |
---|
865 | 0, /*tp_setattr*/ |
---|
866 | 0, /*tp_compare*/ |
---|
867 | (reprfunc)FigureManager_repr, /*tp_repr*/ |
---|
868 | 0, /*tp_as_number*/ |
---|
869 | 0, /*tp_as_sequence*/ |
---|
870 | 0, /*tp_as_mapping*/ |
---|
871 | 0, /*tp_hash */ |
---|
872 | 0, /*tp_call*/ |
---|
873 | 0, /*tp_str*/ |
---|
874 | 0, /*tp_getattro*/ |
---|
875 | 0, /*tp_setattro*/ |
---|
876 | 0, /*tp_as_buffer*/ |
---|
877 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
878 | FigureManager_doc, /* tp_doc */ |
---|
879 | 0, /* tp_traverse */ |
---|
880 | 0, /* tp_clear */ |
---|
881 | 0, /* tp_richcompare */ |
---|
882 | 0, /* tp_weaklistoffset */ |
---|
883 | 0, /* tp_iter */ |
---|
884 | 0, /* tp_iternext */ |
---|
885 | FigureManager_methods, /* tp_methods */ |
---|
886 | 0, /* tp_members */ |
---|
887 | 0, /* tp_getset */ |
---|
888 | 0, /* tp_base */ |
---|
889 | 0, /* tp_dict */ |
---|
890 | 0, /* tp_descr_get */ |
---|
891 | 0, /* tp_descr_set */ |
---|
892 | 0, /* tp_dictoffset */ |
---|
893 | (initproc)FigureManager_init, /* tp_init */ |
---|
894 | 0, /* tp_alloc */ |
---|
895 | FigureManager_new, /* tp_new */ |
---|
896 | }; |
---|
897 | |
---|
898 | @interface NavigationToolbarHandler : NSObject |
---|
899 | { PyObject* toolbar; |
---|
900 | } |
---|
901 | - (NavigationToolbarHandler*)initWithToolbar:(PyObject*)toolbar; |
---|
902 | -(void)left:(id)sender; |
---|
903 | -(void)right:(id)sender; |
---|
904 | -(void)up:(id)sender; |
---|
905 | -(void)down:(id)sender; |
---|
906 | -(void)zoominx:(id)sender; |
---|
907 | -(void)zoominy:(id)sender; |
---|
908 | -(void)zoomoutx:(id)sender; |
---|
909 | -(void)zoomouty:(id)sender; |
---|
910 | @end |
---|
911 | |
---|
912 | typedef struct { |
---|
913 | PyObject_HEAD |
---|
914 | NSPopUpButton* menu; |
---|
915 | NavigationToolbarHandler* handler; |
---|
916 | } NavigationToolbar; |
---|
917 | |
---|
918 | @implementation NavigationToolbarHandler |
---|
919 | - (NavigationToolbarHandler*)initWithToolbar:(PyObject*)theToolbar |
---|
920 | { [self init]; |
---|
921 | toolbar = theToolbar; |
---|
922 | return self; |
---|
923 | } |
---|
924 | |
---|
925 | -(void)left:(id)sender |
---|
926 | { PyObject* result; |
---|
927 | PyGILState_STATE gstate; |
---|
928 | gstate = PyGILState_Ensure(); |
---|
929 | result = PyObject_CallMethod(toolbar, "panx", "i", -1); |
---|
930 | if(result) |
---|
931 | Py_DECREF(result); |
---|
932 | else |
---|
933 | PyErr_Print(); |
---|
934 | PyGILState_Release(gstate); |
---|
935 | } |
---|
936 | |
---|
937 | -(void)right:(id)sender |
---|
938 | { PyObject* result; |
---|
939 | PyGILState_STATE gstate; |
---|
940 | gstate = PyGILState_Ensure(); |
---|
941 | result = PyObject_CallMethod(toolbar, "panx", "i", 1); |
---|
942 | if(result) |
---|
943 | Py_DECREF(result); |
---|
944 | else |
---|
945 | PyErr_Print(); |
---|
946 | PyGILState_Release(gstate); |
---|
947 | } |
---|
948 | |
---|
949 | -(void)up:(id)sender |
---|
950 | { PyObject* result; |
---|
951 | PyGILState_STATE gstate; |
---|
952 | gstate = PyGILState_Ensure(); |
---|
953 | result = PyObject_CallMethod(toolbar, "pany", "i", 1); |
---|
954 | if(result) |
---|
955 | Py_DECREF(result); |
---|
956 | else |
---|
957 | PyErr_Print(); |
---|
958 | PyGILState_Release(gstate); |
---|
959 | } |
---|
960 | |
---|
961 | -(void)down:(id)sender |
---|
962 | { PyObject* result; |
---|
963 | PyGILState_STATE gstate; |
---|
964 | gstate = PyGILState_Ensure(); |
---|
965 | result = PyObject_CallMethod(toolbar, "pany", "i", -1); |
---|
966 | if(result) |
---|
967 | Py_DECREF(result); |
---|
968 | else |
---|
969 | PyErr_Print(); |
---|
970 | PyGILState_Release(gstate); |
---|
971 | } |
---|
972 | |
---|
973 | -(void)zoominx:(id)sender |
---|
974 | { PyObject* result; |
---|
975 | PyGILState_STATE gstate; |
---|
976 | gstate = PyGILState_Ensure(); |
---|
977 | result = PyObject_CallMethod(toolbar, "zoomx", "i", 1); |
---|
978 | if(result) |
---|
979 | Py_DECREF(result); |
---|
980 | else |
---|
981 | PyErr_Print(); |
---|
982 | PyGILState_Release(gstate); |
---|
983 | } |
---|
984 | |
---|
985 | -(void)zoomoutx:(id)sender |
---|
986 | { PyObject* result; |
---|
987 | PyGILState_STATE gstate; |
---|
988 | gstate = PyGILState_Ensure(); |
---|
989 | result = PyObject_CallMethod(toolbar, "zoomx", "i", -1); |
---|
990 | if(result) |
---|
991 | Py_DECREF(result); |
---|
992 | else |
---|
993 | PyErr_Print(); |
---|
994 | PyGILState_Release(gstate); |
---|
995 | } |
---|
996 | |
---|
997 | -(void)zoominy:(id)sender |
---|
998 | { PyObject* result; |
---|
999 | PyGILState_STATE gstate; |
---|
1000 | gstate = PyGILState_Ensure(); |
---|
1001 | result = PyObject_CallMethod(toolbar, "zoomy", "i", 1); |
---|
1002 | if(result) |
---|
1003 | Py_DECREF(result); |
---|
1004 | else |
---|
1005 | PyErr_Print(); |
---|
1006 | PyGILState_Release(gstate); |
---|
1007 | } |
---|
1008 | |
---|
1009 | -(void)zoomouty:(id)sender |
---|
1010 | { PyObject* result; |
---|
1011 | PyGILState_STATE gstate; |
---|
1012 | gstate = PyGILState_Ensure(); |
---|
1013 | result = PyObject_CallMethod(toolbar, "zoomy", "i", -1); |
---|
1014 | if(result) |
---|
1015 | Py_DECREF(result); |
---|
1016 | else |
---|
1017 | PyErr_Print(); |
---|
1018 | PyGILState_Release(gstate); |
---|
1019 | } |
---|
1020 | |
---|
1021 | -(void)save_figure:(id)sender |
---|
1022 | { PyObject* result; |
---|
1023 | PyGILState_STATE gstate; |
---|
1024 | gstate = PyGILState_Ensure(); |
---|
1025 | result = PyObject_CallMethod(toolbar, "save_figure", ""); |
---|
1026 | if(result) |
---|
1027 | Py_DECREF(result); |
---|
1028 | else |
---|
1029 | PyErr_Print(); |
---|
1030 | PyGILState_Release(gstate); |
---|
1031 | } |
---|
1032 | @end |
---|
1033 | |
---|
1034 | static PyObject* |
---|
1035 | NavigationToolbar_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
---|
1036 | { |
---|
1037 | NavigationToolbarHandler* handler = [NavigationToolbarHandler alloc]; |
---|
1038 | if (!handler) return NULL; |
---|
1039 | NavigationToolbar *self = (NavigationToolbar*)type->tp_alloc(type, 0); |
---|
1040 | if (!self) |
---|
1041 | { [handler release]; |
---|
1042 | return NULL; |
---|
1043 | } |
---|
1044 | self->handler = handler; |
---|
1045 | return (PyObject*)self; |
---|
1046 | } |
---|
1047 | |
---|
1048 | static int |
---|
1049 | NavigationToolbar_init(NavigationToolbar *self, PyObject *args, PyObject *kwds) |
---|
1050 | { |
---|
1051 | int i; |
---|
1052 | NSRect rect; |
---|
1053 | |
---|
1054 | const float smallgap = 2; |
---|
1055 | const float biggap = 10; |
---|
1056 | const int height = 32; |
---|
1057 | |
---|
1058 | PyObject* images; |
---|
1059 | PyObject* obj; |
---|
1060 | |
---|
1061 | FigureCanvas* canvas; |
---|
1062 | View* view; |
---|
1063 | |
---|
1064 | obj = PyObject_GetAttrString((PyObject*)self, "canvas"); |
---|
1065 | if (obj==NULL) |
---|
1066 | { |
---|
1067 | PyErr_SetString(PyExc_AttributeError, "Attempt to install toolbar for NULL canvas"); |
---|
1068 | return -1; |
---|
1069 | } |
---|
1070 | Py_DECREF(obj); /* Don't increase the reference count */ |
---|
1071 | if (!PyObject_IsInstance(obj, (PyObject*) &FigureCanvasType)) |
---|
1072 | { |
---|
1073 | PyErr_SetString(PyExc_TypeError, "Attempt to install toolbar for object that is not a FigureCanvas"); |
---|
1074 | return -1; |
---|
1075 | } |
---|
1076 | canvas = (FigureCanvas*)obj; |
---|
1077 | view = canvas->view; |
---|
1078 | if(!view) |
---|
1079 | { |
---|
1080 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
1081 | return -1; |
---|
1082 | } |
---|
1083 | |
---|
1084 | if(!PyArg_ParseTuple(args, "O", &images)) return -1; |
---|
1085 | if(!PyDict_Check(images)) return -1; |
---|
1086 | |
---|
1087 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
1088 | NSRect bounds = [view bounds]; |
---|
1089 | NSWindow* window = [view window]; |
---|
1090 | |
---|
1091 | bounds.origin.y += height; |
---|
1092 | [view setFrame: bounds]; |
---|
1093 | |
---|
1094 | bounds.size.height += height; |
---|
1095 | [window setContentSize: bounds.size]; |
---|
1096 | |
---|
1097 | char* imagenames[9] = {"stock_left", |
---|
1098 | "stock_right", |
---|
1099 | "stock_zoom-in", |
---|
1100 | "stock_zoom-out", |
---|
1101 | "stock_up", |
---|
1102 | "stock_down", |
---|
1103 | "stock_zoom-in", |
---|
1104 | "stock_zoom-out", |
---|
1105 | "stock_save_as"}; |
---|
1106 | |
---|
1107 | NSString* tooltips[9] = { |
---|
1108 | @"Pan left with click or wheel mouse (bidirectional)", |
---|
1109 | @"Pan right with click or wheel mouse (bidirectional)", |
---|
1110 | @"Zoom In X (shrink the x axis limits) with click or wheel mouse (bidirectional)", |
---|
1111 | @"Zoom Out X (expand the x axis limits) with click or wheel mouse (bidirectional)", |
---|
1112 | @"Pan up with click or wheel mouse (bidirectional)", |
---|
1113 | @"Pan down with click or wheel mouse (bidirectional)", |
---|
1114 | @"Zoom in Y (shrink the y axis limits) with click or wheel mouse (bidirectional)", |
---|
1115 | @"Zoom Out Y (expand the y axis limits) with click or wheel mouse (bidirectional)", |
---|
1116 | @"Save the figure"}; |
---|
1117 | |
---|
1118 | SEL actions[9] = {@selector(left:), |
---|
1119 | @selector(right:), |
---|
1120 | @selector(zoominx:), |
---|
1121 | @selector(zoomoutx:), |
---|
1122 | @selector(up:), |
---|
1123 | @selector(down:), |
---|
1124 | @selector(zoominy:), |
---|
1125 | @selector(zoomouty:), |
---|
1126 | @selector(save_figure:)}; |
---|
1127 | |
---|
1128 | SEL scroll_actions[9][2] = {{@selector(left:), @selector(right:)}, |
---|
1129 | {@selector(left:), @selector(right:)}, |
---|
1130 | {@selector(zoominx:), @selector(zoomoutx:)}, |
---|
1131 | {@selector(zoominx:), @selector(zoomoutx:)}, |
---|
1132 | {@selector(up:), @selector(down:)}, |
---|
1133 | {@selector(up:), @selector(down:)}, |
---|
1134 | {@selector(zoominy:), @selector(zoomouty:)}, |
---|
1135 | {@selector(zoominy:), @selector(zoomouty:)}, |
---|
1136 | {nil,nil}, |
---|
1137 | }; |
---|
1138 | |
---|
1139 | |
---|
1140 | rect.size.width = 120; |
---|
1141 | rect.size.height = 24; |
---|
1142 | rect.origin.x = biggap; |
---|
1143 | rect.origin.y = 0.5*(height - rect.size.height); |
---|
1144 | self->menu = [[NSPopUpButton alloc] initWithFrame: rect |
---|
1145 | pullsDown: YES]; |
---|
1146 | [self->menu setAutoenablesItems: NO]; |
---|
1147 | [[window contentView] addSubview: self->menu]; |
---|
1148 | [self->menu release]; |
---|
1149 | rect.origin.x += rect.size.width + biggap; |
---|
1150 | rect.size.width = 24; |
---|
1151 | |
---|
1152 | self->handler = [self->handler initWithToolbar: (PyObject*)self]; |
---|
1153 | for (i = 0; i < 9; i++) |
---|
1154 | { |
---|
1155 | NSButton* button; |
---|
1156 | SEL scrollWheelUpAction = scroll_actions[i][0]; |
---|
1157 | SEL scrollWheelDownAction = scroll_actions[i][1]; |
---|
1158 | if (scrollWheelUpAction && scrollWheelDownAction) |
---|
1159 | { |
---|
1160 | ScrollableButton* scrollable_button = [ScrollableButton alloc]; |
---|
1161 | [scrollable_button initWithFrame: rect]; |
---|
1162 | [scrollable_button setScrollWheelUpAction: scrollWheelUpAction]; |
---|
1163 | [scrollable_button setScrollWheelDownAction: scrollWheelDownAction]; |
---|
1164 | button = (NSButton*)scrollable_button; |
---|
1165 | } |
---|
1166 | else |
---|
1167 | { |
---|
1168 | button = [NSButton alloc]; |
---|
1169 | [button initWithFrame: rect]; |
---|
1170 | } |
---|
1171 | PyObject* imagedata = PyDict_GetItemString(images, imagenames[i]); |
---|
1172 | NSImage* image = _read_ppm_image(imagedata); |
---|
1173 | [button setBezelStyle: NSShadowlessSquareBezelStyle]; |
---|
1174 | [button setButtonType: NSMomentaryLightButton]; |
---|
1175 | if(image) |
---|
1176 | { |
---|
1177 | [button setImage: image]; |
---|
1178 | [image release]; |
---|
1179 | } |
---|
1180 | [button setToolTip: tooltips[i]]; |
---|
1181 | [button setTarget: self->handler]; |
---|
1182 | [button setAction: actions[i]]; |
---|
1183 | [[window contentView] addSubview: button]; |
---|
1184 | [button release]; |
---|
1185 | rect.origin.x += rect.size.width + smallgap; |
---|
1186 | } |
---|
1187 | [[window contentView] display]; |
---|
1188 | [pool release]; |
---|
1189 | |
---|
1190 | return 0; |
---|
1191 | } |
---|
1192 | |
---|
1193 | static void |
---|
1194 | NavigationToolbar_dealloc(NavigationToolbar *self) |
---|
1195 | { |
---|
1196 | [self->handler release]; |
---|
1197 | Py_TYPE(self)->tp_free((PyObject*)self); |
---|
1198 | } |
---|
1199 | |
---|
1200 | static PyObject* |
---|
1201 | NavigationToolbar_repr(NavigationToolbar* self) |
---|
1202 | { |
---|
1203 | #if PY3K |
---|
1204 | return PyUnicode_FromFormat("NavigationToolbar object %p", (void*)self); |
---|
1205 | #else |
---|
1206 | return PyString_FromFormat("NavigationToolbar object %p", (void*)self); |
---|
1207 | #endif |
---|
1208 | } |
---|
1209 | |
---|
1210 | static char NavigationToolbar_doc[] = |
---|
1211 | "NavigationToolbar\n"; |
---|
1212 | |
---|
1213 | static PyObject* |
---|
1214 | NavigationToolbar_update (NavigationToolbar* self) |
---|
1215 | { |
---|
1216 | int n; |
---|
1217 | NSPopUpButton* button = self->menu; |
---|
1218 | if (!button) |
---|
1219 | { |
---|
1220 | PyErr_SetString(PyExc_RuntimeError, "Menu button is NULL"); |
---|
1221 | return NULL; |
---|
1222 | } |
---|
1223 | |
---|
1224 | PyObject* canvas = PyObject_GetAttrString((PyObject*)self, "canvas"); |
---|
1225 | if (canvas==NULL) |
---|
1226 | { |
---|
1227 | PyErr_SetString(PyExc_AttributeError, "Failed to find canvas"); |
---|
1228 | return NULL; |
---|
1229 | } |
---|
1230 | Py_DECREF(canvas); /* Don't keep a reference here */ |
---|
1231 | PyObject* figure = PyObject_GetAttrString(canvas, "figure"); |
---|
1232 | if (figure==NULL) |
---|
1233 | { |
---|
1234 | PyErr_SetString(PyExc_AttributeError, "Failed to find figure"); |
---|
1235 | return NULL; |
---|
1236 | } |
---|
1237 | Py_DECREF(figure); /* Don't keep a reference here */ |
---|
1238 | PyObject* axes = PyObject_GetAttrString(figure, "axes"); |
---|
1239 | if (axes==NULL) |
---|
1240 | { |
---|
1241 | PyErr_SetString(PyExc_AttributeError, "Failed to find figure axes"); |
---|
1242 | return NULL; |
---|
1243 | } |
---|
1244 | Py_DECREF(axes); /* Don't keep a reference here */ |
---|
1245 | if (!PyList_Check(axes)) |
---|
1246 | { |
---|
1247 | PyErr_SetString(PyExc_TypeError, "Figure axes is not a list"); |
---|
1248 | return NULL; |
---|
1249 | } |
---|
1250 | n = PyList_GET_SIZE(axes); |
---|
1251 | |
---|
1252 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
1253 | [button removeAllItems]; |
---|
1254 | |
---|
1255 | NSMenu* menu = [button menu]; |
---|
1256 | [menu addItem: [MenuItem menuItemWithTitle: @"Axes"]]; |
---|
1257 | |
---|
1258 | if (n==0) |
---|
1259 | { |
---|
1260 | [button setEnabled: NO]; |
---|
1261 | } |
---|
1262 | else |
---|
1263 | { |
---|
1264 | int i; |
---|
1265 | [menu addItem: [MenuItem menuItemSelectAll]]; |
---|
1266 | [menu addItem: [MenuItem menuItemInvertAll]]; |
---|
1267 | [menu addItem: [NSMenuItem separatorItem]]; |
---|
1268 | for (i = 0; i < n; i++) |
---|
1269 | { |
---|
1270 | [menu addItem: [MenuItem menuItemForAxis: i]]; |
---|
1271 | } |
---|
1272 | [button setEnabled: YES]; |
---|
1273 | } |
---|
1274 | [pool release]; |
---|
1275 | Py_RETURN_NONE; |
---|
1276 | } |
---|
1277 | |
---|
1278 | static PyObject* |
---|
1279 | NavigationToolbar_get_active (NavigationToolbar* self) |
---|
1280 | { |
---|
1281 | NSPopUpButton* button = self->menu; |
---|
1282 | if (!button) |
---|
1283 | { |
---|
1284 | PyErr_SetString(PyExc_RuntimeError, "Menu button is NULL"); |
---|
1285 | return NULL; |
---|
1286 | } |
---|
1287 | NSMenu* menu = [button menu]; |
---|
1288 | NSArray* items = [menu itemArray]; |
---|
1289 | size_t n = [items count]; |
---|
1290 | int* states = calloc(n, sizeof(int)); |
---|
1291 | if (!states) |
---|
1292 | { |
---|
1293 | PyErr_SetString(PyExc_RuntimeError, "calloc failed"); |
---|
1294 | return NULL; |
---|
1295 | } |
---|
1296 | int i; |
---|
1297 | unsigned int m = 0; |
---|
1298 | NSEnumerator* enumerator = [items objectEnumerator]; |
---|
1299 | MenuItem* item; |
---|
1300 | while ((item = [enumerator nextObject])) |
---|
1301 | { |
---|
1302 | if ([item isSeparatorItem]) continue; |
---|
1303 | i = [item index]; |
---|
1304 | if (i < 0) continue; |
---|
1305 | if ([item state]==NSOnState) |
---|
1306 | { |
---|
1307 | states[i] = 1; |
---|
1308 | m++; |
---|
1309 | } |
---|
1310 | } |
---|
1311 | Py_ssize_t list_index = 0; |
---|
1312 | PyObject* list = PyList_New(m); |
---|
1313 | size_t state_index; |
---|
1314 | for (state_index = 0; state_index < n; state_index++) |
---|
1315 | { |
---|
1316 | if(states[state_index]==1) |
---|
1317 | { |
---|
1318 | PyList_SET_ITEM(list, list_index++, PyLong_FromSize_t(state_index)); |
---|
1319 | } |
---|
1320 | } |
---|
1321 | free(states); |
---|
1322 | return list; |
---|
1323 | } |
---|
1324 | |
---|
1325 | static PyMethodDef NavigationToolbar_methods[] = { |
---|
1326 | {"update", |
---|
1327 | (PyCFunction)NavigationToolbar_update, |
---|
1328 | METH_NOARGS, |
---|
1329 | "Updates the toolbar menu." |
---|
1330 | }, |
---|
1331 | {"get_active", |
---|
1332 | (PyCFunction)NavigationToolbar_get_active, |
---|
1333 | METH_NOARGS, |
---|
1334 | "Returns a list of integers identifying which items in the menu are selected." |
---|
1335 | }, |
---|
1336 | {NULL} /* Sentinel */ |
---|
1337 | }; |
---|
1338 | |
---|
1339 | static PyTypeObject NavigationToolbarType = { |
---|
1340 | PyVarObject_HEAD_INIT(NULL, 0) |
---|
1341 | "_macosx.NavigationToolbar", /*tp_name*/ |
---|
1342 | sizeof(NavigationToolbar), /*tp_basicsize*/ |
---|
1343 | 0, /*tp_itemsize*/ |
---|
1344 | (destructor)NavigationToolbar_dealloc, /*tp_dealloc*/ |
---|
1345 | 0, /*tp_print*/ |
---|
1346 | 0, /*tp_getattr*/ |
---|
1347 | 0, /*tp_setattr*/ |
---|
1348 | 0, /*tp_compare*/ |
---|
1349 | (reprfunc)NavigationToolbar_repr, /*tp_repr*/ |
---|
1350 | 0, /*tp_as_number*/ |
---|
1351 | 0, /*tp_as_sequence*/ |
---|
1352 | 0, /*tp_as_mapping*/ |
---|
1353 | 0, /*tp_hash */ |
---|
1354 | 0, /*tp_call*/ |
---|
1355 | 0, /*tp_str*/ |
---|
1356 | 0, /*tp_getattro*/ |
---|
1357 | 0, /*tp_setattro*/ |
---|
1358 | 0, /*tp_as_buffer*/ |
---|
1359 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
1360 | NavigationToolbar_doc, /* tp_doc */ |
---|
1361 | 0, /* tp_traverse */ |
---|
1362 | 0, /* tp_clear */ |
---|
1363 | 0, /* tp_richcompare */ |
---|
1364 | 0, /* tp_weaklistoffset */ |
---|
1365 | 0, /* tp_iter */ |
---|
1366 | 0, /* tp_iternext */ |
---|
1367 | NavigationToolbar_methods, /* tp_methods */ |
---|
1368 | 0, /* tp_members */ |
---|
1369 | 0, /* tp_getset */ |
---|
1370 | 0, /* tp_base */ |
---|
1371 | 0, /* tp_dict */ |
---|
1372 | 0, /* tp_descr_get */ |
---|
1373 | 0, /* tp_descr_set */ |
---|
1374 | 0, /* tp_dictoffset */ |
---|
1375 | (initproc)NavigationToolbar_init, /* tp_init */ |
---|
1376 | 0, /* tp_alloc */ |
---|
1377 | NavigationToolbar_new, /* tp_new */ |
---|
1378 | }; |
---|
1379 | |
---|
1380 | @interface NavigationToolbar2Handler : NSObject |
---|
1381 | { PyObject* toolbar; |
---|
1382 | NSButton* panbutton; |
---|
1383 | NSButton* zoombutton; |
---|
1384 | } |
---|
1385 | - (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)toolbar; |
---|
1386 | - (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons; |
---|
1387 | - (void)home:(id)sender; |
---|
1388 | - (void)back:(id)sender; |
---|
1389 | - (void)forward:(id)sender; |
---|
1390 | - (void)pan:(id)sender; |
---|
1391 | - (void)zoom:(id)sender; |
---|
1392 | - (void)configure_subplots:(id)sender; |
---|
1393 | - (void)save_figure:(id)sender; |
---|
1394 | @end |
---|
1395 | |
---|
1396 | typedef struct { |
---|
1397 | PyObject_HEAD |
---|
1398 | NSPopUpButton* menu; |
---|
1399 | NSText* messagebox; |
---|
1400 | NavigationToolbar2Handler* handler; |
---|
1401 | } NavigationToolbar2; |
---|
1402 | |
---|
1403 | @implementation NavigationToolbar2Handler |
---|
1404 | - (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)theToolbar |
---|
1405 | { [self init]; |
---|
1406 | toolbar = theToolbar; |
---|
1407 | return self; |
---|
1408 | } |
---|
1409 | |
---|
1410 | - (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons |
---|
1411 | { |
---|
1412 | int i; |
---|
1413 | for (i = 0; i < 7; i++) |
---|
1414 | { |
---|
1415 | SEL action = actions[i]; |
---|
1416 | NSButton* button = buttons[i]; |
---|
1417 | [button setTarget: self]; |
---|
1418 | [button setAction: action]; |
---|
1419 | if (action==@selector(pan:)) panbutton = button; |
---|
1420 | if (action==@selector(zoom:)) zoombutton = button; |
---|
1421 | } |
---|
1422 | } |
---|
1423 | |
---|
1424 | -(void)home:(id)sender |
---|
1425 | { PyObject* result; |
---|
1426 | PyGILState_STATE gstate; |
---|
1427 | gstate = PyGILState_Ensure(); |
---|
1428 | result = PyObject_CallMethod(toolbar, "home", ""); |
---|
1429 | if(result) |
---|
1430 | Py_DECREF(result); |
---|
1431 | else |
---|
1432 | PyErr_Print(); |
---|
1433 | PyGILState_Release(gstate); |
---|
1434 | } |
---|
1435 | |
---|
1436 | -(void)back:(id)sender |
---|
1437 | { PyObject* result; |
---|
1438 | PyGILState_STATE gstate; |
---|
1439 | gstate = PyGILState_Ensure(); |
---|
1440 | result = PyObject_CallMethod(toolbar, "back", ""); |
---|
1441 | if(result) |
---|
1442 | Py_DECREF(result); |
---|
1443 | else |
---|
1444 | PyErr_Print(); |
---|
1445 | PyGILState_Release(gstate); |
---|
1446 | } |
---|
1447 | |
---|
1448 | -(void)forward:(id)sender |
---|
1449 | { PyObject* result; |
---|
1450 | PyGILState_STATE gstate; |
---|
1451 | gstate = PyGILState_Ensure(); |
---|
1452 | result = PyObject_CallMethod(toolbar, "forward", ""); |
---|
1453 | if(result) |
---|
1454 | Py_DECREF(result); |
---|
1455 | else |
---|
1456 | PyErr_Print(); |
---|
1457 | PyGILState_Release(gstate); |
---|
1458 | } |
---|
1459 | |
---|
1460 | -(void)pan:(id)sender |
---|
1461 | { PyObject* result; |
---|
1462 | PyGILState_STATE gstate; |
---|
1463 | if ([sender state]) |
---|
1464 | { |
---|
1465 | if (zoombutton) [zoombutton setState: NO]; |
---|
1466 | } |
---|
1467 | gstate = PyGILState_Ensure(); |
---|
1468 | result = PyObject_CallMethod(toolbar, "pan", ""); |
---|
1469 | if(result) |
---|
1470 | Py_DECREF(result); |
---|
1471 | else |
---|
1472 | PyErr_Print(); |
---|
1473 | PyGILState_Release(gstate); |
---|
1474 | } |
---|
1475 | |
---|
1476 | -(void)zoom:(id)sender |
---|
1477 | { PyObject* result; |
---|
1478 | PyGILState_STATE gstate; |
---|
1479 | if ([sender state]) |
---|
1480 | { |
---|
1481 | if (panbutton) [panbutton setState: NO]; |
---|
1482 | } |
---|
1483 | gstate = PyGILState_Ensure(); |
---|
1484 | result = PyObject_CallMethod(toolbar, "zoom", ""); |
---|
1485 | if(result) |
---|
1486 | Py_DECREF(result); |
---|
1487 | else |
---|
1488 | PyErr_Print(); |
---|
1489 | PyGILState_Release(gstate); |
---|
1490 | } |
---|
1491 | |
---|
1492 | -(void)configure_subplots:(id)sender |
---|
1493 | { PyObject* canvas; |
---|
1494 | View* view; |
---|
1495 | PyObject* size; |
---|
1496 | NSRect rect; |
---|
1497 | int width, height; |
---|
1498 | |
---|
1499 | rect.origin.x = 100; |
---|
1500 | rect.origin.y = 350; |
---|
1501 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
1502 | PyObject* master = PyObject_GetAttrString(toolbar, "canvas"); |
---|
1503 | if (master==nil) |
---|
1504 | { |
---|
1505 | PyErr_Print(); |
---|
1506 | PyGILState_Release(gstate); |
---|
1507 | return; |
---|
1508 | } |
---|
1509 | canvas = PyObject_CallMethod(toolbar, "prepare_configure_subplots", ""); |
---|
1510 | if(!canvas) |
---|
1511 | { |
---|
1512 | PyErr_Print(); |
---|
1513 | Py_DECREF(master); |
---|
1514 | PyGILState_Release(gstate); |
---|
1515 | return; |
---|
1516 | } |
---|
1517 | |
---|
1518 | view = ((FigureCanvas*)canvas)->view; |
---|
1519 | if (!view) /* Something really weird going on */ |
---|
1520 | { |
---|
1521 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
1522 | PyErr_Print(); |
---|
1523 | Py_DECREF(canvas); |
---|
1524 | Py_DECREF(master); |
---|
1525 | PyGILState_Release(gstate); |
---|
1526 | return; |
---|
1527 | } |
---|
1528 | |
---|
1529 | size = PyObject_CallMethod(canvas, "get_width_height", ""); |
---|
1530 | Py_DECREF(canvas); |
---|
1531 | if(!size) |
---|
1532 | { |
---|
1533 | PyErr_Print(); |
---|
1534 | Py_DECREF(master); |
---|
1535 | PyGILState_Release(gstate); |
---|
1536 | return; |
---|
1537 | } |
---|
1538 | |
---|
1539 | int ok = PyArg_ParseTuple(size, "ii", &width, &height); |
---|
1540 | Py_DECREF(size); |
---|
1541 | if (!ok) |
---|
1542 | { |
---|
1543 | PyErr_Print(); |
---|
1544 | Py_DECREF(master); |
---|
1545 | PyGILState_Release(gstate); |
---|
1546 | return; |
---|
1547 | } |
---|
1548 | |
---|
1549 | NSWindow* mw = [((FigureCanvas*)master)->view window]; |
---|
1550 | Py_DECREF(master); |
---|
1551 | PyGILState_Release(gstate); |
---|
1552 | |
---|
1553 | rect.size.width = width; |
---|
1554 | rect.size.height = height; |
---|
1555 | |
---|
1556 | ToolWindow* window = [ [ToolWindow alloc] initWithContentRect: rect |
---|
1557 | master: mw]; |
---|
1558 | [window setContentView: view]; |
---|
1559 | [view release]; |
---|
1560 | [window makeKeyAndOrderFront: nil]; |
---|
1561 | } |
---|
1562 | |
---|
1563 | -(void)save_figure:(id)sender |
---|
1564 | { PyObject* result; |
---|
1565 | PyGILState_STATE gstate; |
---|
1566 | gstate = PyGILState_Ensure(); |
---|
1567 | result = PyObject_CallMethod(toolbar, "save_figure", ""); |
---|
1568 | if(result) |
---|
1569 | Py_DECREF(result); |
---|
1570 | else |
---|
1571 | PyErr_Print(); |
---|
1572 | PyGILState_Release(gstate); |
---|
1573 | } |
---|
1574 | @end |
---|
1575 | |
---|
1576 | static PyObject* |
---|
1577 | NavigationToolbar2_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
---|
1578 | { |
---|
1579 | NavigationToolbar2Handler* handler = [NavigationToolbar2Handler alloc]; |
---|
1580 | if (!handler) return NULL; |
---|
1581 | NavigationToolbar2 *self = (NavigationToolbar2*)type->tp_alloc(type, 0); |
---|
1582 | if (!self) |
---|
1583 | { |
---|
1584 | [handler release]; |
---|
1585 | return NULL; |
---|
1586 | } |
---|
1587 | self->handler = handler; |
---|
1588 | return (PyObject*)self; |
---|
1589 | } |
---|
1590 | |
---|
1591 | static int |
---|
1592 | NavigationToolbar2_init(NavigationToolbar2 *self, PyObject *args, PyObject *kwds) |
---|
1593 | { |
---|
1594 | PyObject* obj; |
---|
1595 | FigureCanvas* canvas; |
---|
1596 | View* view; |
---|
1597 | |
---|
1598 | int i; |
---|
1599 | NSRect rect; |
---|
1600 | NSSize size; |
---|
1601 | NSSize scale; |
---|
1602 | |
---|
1603 | const float gap = 2; |
---|
1604 | const int height = 36; |
---|
1605 | const int imagesize = 24; |
---|
1606 | |
---|
1607 | const char* basedir; |
---|
1608 | |
---|
1609 | obj = PyObject_GetAttrString((PyObject*)self, "canvas"); |
---|
1610 | if (obj==NULL) |
---|
1611 | { |
---|
1612 | PyErr_SetString(PyExc_AttributeError, "Attempt to install toolbar for NULL canvas"); |
---|
1613 | return -1; |
---|
1614 | } |
---|
1615 | Py_DECREF(obj); /* Don't increase the reference count */ |
---|
1616 | if (!PyObject_IsInstance(obj, (PyObject*) &FigureCanvasType)) |
---|
1617 | { |
---|
1618 | PyErr_SetString(PyExc_TypeError, "Attempt to install toolbar for object that is not a FigureCanvas"); |
---|
1619 | return -1; |
---|
1620 | } |
---|
1621 | canvas = (FigureCanvas*)obj; |
---|
1622 | view = canvas->view; |
---|
1623 | if(!view) |
---|
1624 | { |
---|
1625 | PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); |
---|
1626 | return -1; |
---|
1627 | } |
---|
1628 | |
---|
1629 | if(!PyArg_ParseTuple(args, "s", &basedir)) return -1; |
---|
1630 | |
---|
1631 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
1632 | NSRect bounds = [view bounds]; |
---|
1633 | NSWindow* window = [view window]; |
---|
1634 | |
---|
1635 | bounds.origin.y += height; |
---|
1636 | [view setFrame: bounds]; |
---|
1637 | |
---|
1638 | bounds.size.height += height; |
---|
1639 | [window setContentSize: bounds.size]; |
---|
1640 | |
---|
1641 | NSString* dir = [NSString stringWithCString: basedir |
---|
1642 | encoding: NSASCIIStringEncoding]; |
---|
1643 | |
---|
1644 | NSButton* buttons[7]; |
---|
1645 | |
---|
1646 | NSString* images[7] = {@"home.pdf", |
---|
1647 | @"back.pdf", |
---|
1648 | @"forward.pdf", |
---|
1649 | @"move.pdf", |
---|
1650 | @"zoom_to_rect.pdf", |
---|
1651 | @"subplots.pdf", |
---|
1652 | @"filesave.pdf"}; |
---|
1653 | |
---|
1654 | NSString* tooltips[7] = {@"Reset original view", |
---|
1655 | @"Back to previous view", |
---|
1656 | @"Forward to next view", |
---|
1657 | @"Pan axes with left mouse, zoom with right", |
---|
1658 | @"Zoom to rectangle", |
---|
1659 | @"Configure subplots", |
---|
1660 | @"Save the figure"}; |
---|
1661 | |
---|
1662 | SEL actions[7] = {@selector(home:), |
---|
1663 | @selector(back:), |
---|
1664 | @selector(forward:), |
---|
1665 | @selector(pan:), |
---|
1666 | @selector(zoom:), |
---|
1667 | @selector(configure_subplots:), |
---|
1668 | @selector(save_figure:)}; |
---|
1669 | |
---|
1670 | NSButtonType buttontypes[7] = {NSMomentaryLightButton, |
---|
1671 | NSMomentaryLightButton, |
---|
1672 | NSMomentaryLightButton, |
---|
1673 | NSPushOnPushOffButton, |
---|
1674 | NSPushOnPushOffButton, |
---|
1675 | NSMomentaryLightButton, |
---|
1676 | NSMomentaryLightButton}; |
---|
1677 | |
---|
1678 | rect.origin.x = 0; |
---|
1679 | rect.origin.y = 0; |
---|
1680 | rect.size.width = imagesize; |
---|
1681 | rect.size.height = imagesize; |
---|
1682 | #ifdef COMPILING_FOR_10_7 |
---|
1683 | rect = [window convertRectToBacking: rect]; |
---|
1684 | #endif |
---|
1685 | size = rect.size; |
---|
1686 | scale.width = imagesize / size.width; |
---|
1687 | scale.height = imagesize / size.height; |
---|
1688 | |
---|
1689 | rect.size.width = 32; |
---|
1690 | rect.size.height = 32; |
---|
1691 | rect.origin.x = gap; |
---|
1692 | rect.origin.y = 0.5*(height - rect.size.height); |
---|
1693 | |
---|
1694 | for (i = 0; i < 7; i++) |
---|
1695 | { |
---|
1696 | NSString* filename = [dir stringByAppendingPathComponent: images[i]]; |
---|
1697 | NSImage* image = [[NSImage alloc] initWithContentsOfFile: filename]; |
---|
1698 | buttons[i] = [[NSButton alloc] initWithFrame: rect]; |
---|
1699 | [image setSize: size]; |
---|
1700 | [buttons[i] setBezelStyle: NSShadowlessSquareBezelStyle]; |
---|
1701 | [buttons[i] setButtonType: buttontypes[i]]; |
---|
1702 | [buttons[i] setImage: image]; |
---|
1703 | [buttons[i] scaleUnitSquareToSize: scale]; |
---|
1704 | [buttons[i] setImagePosition: NSImageOnly]; |
---|
1705 | [buttons[i] setToolTip: tooltips[i]]; |
---|
1706 | [[window contentView] addSubview: buttons[i]]; |
---|
1707 | [buttons[i] release]; |
---|
1708 | [image release]; |
---|
1709 | rect.origin.x += rect.size.width + gap; |
---|
1710 | } |
---|
1711 | |
---|
1712 | self->handler = [self->handler initWithToolbar: (PyObject*)self]; |
---|
1713 | [self->handler installCallbacks: actions forButtons: buttons]; |
---|
1714 | |
---|
1715 | NSFont* font = [NSFont systemFontOfSize: 0.0]; |
---|
1716 | rect.size.width = 300; |
---|
1717 | rect.size.height = 0; |
---|
1718 | rect.origin.x += height; |
---|
1719 | NSText* messagebox = [[NSText alloc] initWithFrame: rect]; |
---|
1720 | [messagebox setFont: font]; |
---|
1721 | [messagebox setDrawsBackground: NO]; |
---|
1722 | [messagebox setSelectable: NO]; |
---|
1723 | /* if selectable, the messagebox can become first responder, |
---|
1724 | * which is not supposed to happen */ |
---|
1725 | rect = [messagebox frame]; |
---|
1726 | rect.origin.y = 0.5 * (height - rect.size.height); |
---|
1727 | [messagebox setFrameOrigin: rect.origin]; |
---|
1728 | [[window contentView] addSubview: messagebox]; |
---|
1729 | [messagebox release]; |
---|
1730 | [[window contentView] display]; |
---|
1731 | |
---|
1732 | [pool release]; |
---|
1733 | |
---|
1734 | self->messagebox = messagebox; |
---|
1735 | return 0; |
---|
1736 | } |
---|
1737 | |
---|
1738 | static void |
---|
1739 | NavigationToolbar2_dealloc(NavigationToolbar2 *self) |
---|
1740 | { |
---|
1741 | [self->handler release]; |
---|
1742 | Py_TYPE(self)->tp_free((PyObject*)self); |
---|
1743 | } |
---|
1744 | |
---|
1745 | static PyObject* |
---|
1746 | NavigationToolbar2_repr(NavigationToolbar2* self) |
---|
1747 | { |
---|
1748 | #if PY3K |
---|
1749 | return PyUnicode_FromFormat("NavigationToolbar2 object %p", (void*)self); |
---|
1750 | #else |
---|
1751 | return PyString_FromFormat("NavigationToolbar2 object %p", (void*)self); |
---|
1752 | #endif |
---|
1753 | } |
---|
1754 | |
---|
1755 | static char NavigationToolbar2_doc[] = |
---|
1756 | "NavigationToolbar2\n"; |
---|
1757 | |
---|
1758 | static PyObject* |
---|
1759 | NavigationToolbar2_set_message(NavigationToolbar2 *self, PyObject* args) |
---|
1760 | { |
---|
1761 | const char* message; |
---|
1762 | |
---|
1763 | #if PY3K |
---|
1764 | if(!PyArg_ParseTuple(args, "y", &message)) return NULL; |
---|
1765 | #else |
---|
1766 | if(!PyArg_ParseTuple(args, "s", &message)) return NULL; |
---|
1767 | #endif |
---|
1768 | |
---|
1769 | NSText* messagebox = self->messagebox; |
---|
1770 | |
---|
1771 | if (messagebox) |
---|
1772 | { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
1773 | NSString* text = [NSString stringWithUTF8String: message]; |
---|
1774 | [messagebox setString: text]; |
---|
1775 | [pool release]; |
---|
1776 | } |
---|
1777 | |
---|
1778 | Py_RETURN_NONE; |
---|
1779 | } |
---|
1780 | |
---|
1781 | static PyMethodDef NavigationToolbar2_methods[] = { |
---|
1782 | {"set_message", |
---|
1783 | (PyCFunction)NavigationToolbar2_set_message, |
---|
1784 | METH_VARARGS, |
---|
1785 | "Set the message to be displayed on the toolbar." |
---|
1786 | }, |
---|
1787 | {NULL} /* Sentinel */ |
---|
1788 | }; |
---|
1789 | |
---|
1790 | static PyTypeObject NavigationToolbar2Type = { |
---|
1791 | PyVarObject_HEAD_INIT(NULL, 0) |
---|
1792 | "_macosx.NavigationToolbar2", /*tp_name*/ |
---|
1793 | sizeof(NavigationToolbar2), /*tp_basicsize*/ |
---|
1794 | 0, /*tp_itemsize*/ |
---|
1795 | (destructor)NavigationToolbar2_dealloc, /*tp_dealloc*/ |
---|
1796 | 0, /*tp_print*/ |
---|
1797 | 0, /*tp_getattr*/ |
---|
1798 | 0, /*tp_setattr*/ |
---|
1799 | 0, /*tp_compare*/ |
---|
1800 | (reprfunc)NavigationToolbar2_repr, /*tp_repr*/ |
---|
1801 | 0, /*tp_as_number*/ |
---|
1802 | 0, /*tp_as_sequence*/ |
---|
1803 | 0, /*tp_as_mapping*/ |
---|
1804 | 0, /*tp_hash */ |
---|
1805 | 0, /*tp_call*/ |
---|
1806 | 0, /*tp_str*/ |
---|
1807 | 0, /*tp_getattro*/ |
---|
1808 | 0, /*tp_setattro*/ |
---|
1809 | 0, /*tp_as_buffer*/ |
---|
1810 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
1811 | NavigationToolbar2_doc, /* tp_doc */ |
---|
1812 | 0, /* tp_traverse */ |
---|
1813 | 0, /* tp_clear */ |
---|
1814 | 0, /* tp_richcompare */ |
---|
1815 | 0, /* tp_weaklistoffset */ |
---|
1816 | 0, /* tp_iter */ |
---|
1817 | 0, /* tp_iternext */ |
---|
1818 | NavigationToolbar2_methods, /* tp_methods */ |
---|
1819 | 0, /* tp_members */ |
---|
1820 | 0, /* tp_getset */ |
---|
1821 | 0, /* tp_base */ |
---|
1822 | 0, /* tp_dict */ |
---|
1823 | 0, /* tp_descr_get */ |
---|
1824 | 0, /* tp_descr_set */ |
---|
1825 | 0, /* tp_dictoffset */ |
---|
1826 | (initproc)NavigationToolbar2_init, /* tp_init */ |
---|
1827 | 0, /* tp_alloc */ |
---|
1828 | NavigationToolbar2_new, /* tp_new */ |
---|
1829 | }; |
---|
1830 | |
---|
1831 | static PyObject* |
---|
1832 | choose_save_file(PyObject* unused, PyObject* args) |
---|
1833 | { |
---|
1834 | int result; |
---|
1835 | const char* title; |
---|
1836 | char* default_filename; |
---|
1837 | if(!PyArg_ParseTuple(args, "ses", &title, "UTF-8", &default_filename)) |
---|
1838 | return NULL; |
---|
1839 | |
---|
1840 | NSSavePanel* panel = [NSSavePanel savePanel]; |
---|
1841 | [panel setTitle: [NSString stringWithCString: title |
---|
1842 | encoding: NSASCIIStringEncoding]]; |
---|
1843 | NSString* ns_default_filename = |
---|
1844 | [[NSString alloc] |
---|
1845 | initWithCString: default_filename |
---|
1846 | encoding: NSUTF8StringEncoding]; |
---|
1847 | PyMem_Free(default_filename); |
---|
1848 | #ifdef COMPILING_FOR_10_6 |
---|
1849 | [panel setNameFieldStringValue: ns_default_filename]; |
---|
1850 | result = [panel runModal]; |
---|
1851 | #else |
---|
1852 | result = [panel runModalForDirectory: nil file: ns_default_filename]; |
---|
1853 | #endif |
---|
1854 | [ns_default_filename release]; |
---|
1855 | #ifdef COMPILING_FOR_10_10 |
---|
1856 | if (result == NSModalResponseOK) |
---|
1857 | #else |
---|
1858 | if (result == NSOKButton) |
---|
1859 | #endif |
---|
1860 | { |
---|
1861 | #ifdef COMPILING_FOR_10_6 |
---|
1862 | NSURL* url = [panel URL]; |
---|
1863 | NSString* filename = [url path]; |
---|
1864 | if (!filename) { |
---|
1865 | PyErr_SetString(PyExc_RuntimeError, "Failed to obtain filename"); |
---|
1866 | return 0; |
---|
1867 | } |
---|
1868 | #else |
---|
1869 | NSString* filename = [panel filename]; |
---|
1870 | #endif |
---|
1871 | unsigned int n = [filename length]; |
---|
1872 | unichar* buffer = malloc(n*sizeof(unichar)); |
---|
1873 | [filename getCharacters: buffer]; |
---|
1874 | #if PY3K |
---|
1875 | PyObject* string = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, buffer, n); |
---|
1876 | #else |
---|
1877 | PyObject* string = PyUnicode_FromUnicode(buffer, n); |
---|
1878 | #endif |
---|
1879 | free(buffer); |
---|
1880 | return string; |
---|
1881 | } |
---|
1882 | Py_RETURN_NONE; |
---|
1883 | } |
---|
1884 | |
---|
1885 | static PyObject* |
---|
1886 | set_cursor(PyObject* unused, PyObject* args) |
---|
1887 | { |
---|
1888 | int i; |
---|
1889 | if(!PyArg_ParseTuple(args, "i", &i)) return NULL; |
---|
1890 | switch (i) |
---|
1891 | { case 0: [[NSCursor pointingHandCursor] set]; break; |
---|
1892 | case 1: [[NSCursor arrowCursor] set]; break; |
---|
1893 | case 2: [[NSCursor crosshairCursor] set]; break; |
---|
1894 | case 3: [[NSCursor openHandCursor] set]; break; |
---|
1895 | /* OSX handles busy state itself so no need to set a cursor here */ |
---|
1896 | case 4: break; |
---|
1897 | default: return NULL; |
---|
1898 | } |
---|
1899 | Py_RETURN_NONE; |
---|
1900 | } |
---|
1901 | |
---|
1902 | @implementation WindowServerConnectionManager |
---|
1903 | static WindowServerConnectionManager *sharedWindowServerConnectionManager = nil; |
---|
1904 | |
---|
1905 | + (WindowServerConnectionManager *)sharedManager |
---|
1906 | { |
---|
1907 | if (sharedWindowServerConnectionManager == nil) |
---|
1908 | { |
---|
1909 | sharedWindowServerConnectionManager = [[super allocWithZone:NULL] init]; |
---|
1910 | } |
---|
1911 | return sharedWindowServerConnectionManager; |
---|
1912 | } |
---|
1913 | |
---|
1914 | + (id)allocWithZone:(NSZone *)zone |
---|
1915 | { |
---|
1916 | return [[self sharedManager] retain]; |
---|
1917 | } |
---|
1918 | |
---|
1919 | + (id)copyWithZone:(NSZone *)zone |
---|
1920 | { |
---|
1921 | return self; |
---|
1922 | } |
---|
1923 | |
---|
1924 | + (id)retain |
---|
1925 | { |
---|
1926 | return self; |
---|
1927 | } |
---|
1928 | |
---|
1929 | - (NSUInteger)retainCount |
---|
1930 | { |
---|
1931 | return NSUIntegerMax; //denotes an object that cannot be released |
---|
1932 | } |
---|
1933 | |
---|
1934 | - (oneway void)release |
---|
1935 | { |
---|
1936 | // Don't release a singleton object |
---|
1937 | } |
---|
1938 | |
---|
1939 | - (id)autorelease |
---|
1940 | { |
---|
1941 | return self; |
---|
1942 | } |
---|
1943 | |
---|
1944 | - (void)launch:(NSNotification*)notification |
---|
1945 | { |
---|
1946 | CFRunLoopRef runloop; |
---|
1947 | CFMachPortRef port; |
---|
1948 | CFRunLoopSourceRef source; |
---|
1949 | NSDictionary* dictionary = [notification userInfo]; |
---|
1950 | if (! [[dictionary valueForKey:@"NSApplicationName"] |
---|
1951 | isEqualToString:@"Python"]) |
---|
1952 | return; |
---|
1953 | NSNumber* psnLow = [dictionary valueForKey: @"NSApplicationProcessSerialNumberLow"]; |
---|
1954 | NSNumber* psnHigh = [dictionary valueForKey: @"NSApplicationProcessSerialNumberHigh"]; |
---|
1955 | ProcessSerialNumber psn; |
---|
1956 | psn.highLongOfPSN = [psnHigh intValue]; |
---|
1957 | psn.lowLongOfPSN = [psnLow intValue]; |
---|
1958 | runloop = CFRunLoopGetCurrent(); |
---|
1959 | port = CGEventTapCreateForPSN(&psn, |
---|
1960 | kCGHeadInsertEventTap, |
---|
1961 | kCGEventTapOptionListenOnly, |
---|
1962 | kCGEventMaskForAllEvents, |
---|
1963 | &_eventtap_callback, |
---|
1964 | runloop); |
---|
1965 | source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, |
---|
1966 | port, |
---|
1967 | 0); |
---|
1968 | CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode); |
---|
1969 | CFRelease(port); |
---|
1970 | } |
---|
1971 | @end |
---|
1972 | |
---|
1973 | @implementation Window |
---|
1974 | - (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager |
---|
1975 | { |
---|
1976 | self = [super initWithContentRect: rect |
---|
1977 | styleMask: mask |
---|
1978 | backing: bufferingType |
---|
1979 | defer: deferCreation]; |
---|
1980 | manager = theManager; |
---|
1981 | Py_INCREF(manager); |
---|
1982 | return self; |
---|
1983 | } |
---|
1984 | |
---|
1985 | - (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen |
---|
1986 | { |
---|
1987 | /* Allow window sizes larger than the screen */ |
---|
1988 | NSRect suggested = [super constrainFrameRect: rect toScreen: screen]; |
---|
1989 | const CGFloat difference = rect.size.height - suggested.size.height; |
---|
1990 | suggested.origin.y -= difference; |
---|
1991 | suggested.size.height += difference; |
---|
1992 | return suggested; |
---|
1993 | } |
---|
1994 | |
---|
1995 | - (BOOL)closeButtonPressed |
---|
1996 | { |
---|
1997 | PyObject* result; |
---|
1998 | PyGILState_STATE gstate; |
---|
1999 | gstate = PyGILState_Ensure(); |
---|
2000 | result = PyObject_CallMethod(manager, "close", ""); |
---|
2001 | if(result) |
---|
2002 | Py_DECREF(result); |
---|
2003 | else |
---|
2004 | PyErr_Print(); |
---|
2005 | PyGILState_Release(gstate); |
---|
2006 | return YES; |
---|
2007 | } |
---|
2008 | |
---|
2009 | - (void)close |
---|
2010 | { |
---|
2011 | [super close]; |
---|
2012 | --FigureWindowCount; |
---|
2013 | if (!FigureWindowCount) [NSApp stop: self]; |
---|
2014 | /* This is needed for show(), which should exit from [NSApp run] |
---|
2015 | * after all windows are closed. |
---|
2016 | */ |
---|
2017 | } |
---|
2018 | |
---|
2019 | - (void)dealloc |
---|
2020 | { |
---|
2021 | PyGILState_STATE gstate; |
---|
2022 | gstate = PyGILState_Ensure(); |
---|
2023 | Py_DECREF(manager); |
---|
2024 | PyGILState_Release(gstate); |
---|
2025 | /* The reference count of the view that was added as a subview to the |
---|
2026 | * content view of this window was increased during the call to addSubview, |
---|
2027 | * and is decreased during the call to [super dealloc]. |
---|
2028 | */ |
---|
2029 | [super dealloc]; |
---|
2030 | } |
---|
2031 | @end |
---|
2032 | |
---|
2033 | @implementation ToolWindow |
---|
2034 | - (ToolWindow*)initWithContentRect:(NSRect)rect master:(NSWindow*)window |
---|
2035 | { |
---|
2036 | [self initWithContentRect: rect |
---|
2037 | styleMask: NSTitledWindowMask |
---|
2038 | | NSClosableWindowMask |
---|
2039 | | NSResizableWindowMask |
---|
2040 | | NSMiniaturizableWindowMask |
---|
2041 | backing: NSBackingStoreBuffered |
---|
2042 | defer: YES]; |
---|
2043 | [self setTitle: @"Subplot Configuration Tool"]; |
---|
2044 | [[NSNotificationCenter defaultCenter] addObserver: self |
---|
2045 | selector: @selector(masterCloses:) |
---|
2046 | name: NSWindowWillCloseNotification |
---|
2047 | object: window]; |
---|
2048 | return self; |
---|
2049 | } |
---|
2050 | |
---|
2051 | - (void)masterCloses:(NSNotification*)notification |
---|
2052 | { |
---|
2053 | [self close]; |
---|
2054 | } |
---|
2055 | |
---|
2056 | - (void)close |
---|
2057 | { |
---|
2058 | [[NSNotificationCenter defaultCenter] removeObserver: self]; |
---|
2059 | [super close]; |
---|
2060 | } |
---|
2061 | @end |
---|
2062 | |
---|
2063 | @implementation View |
---|
2064 | - (BOOL)isFlipped |
---|
2065 | { |
---|
2066 | return NO; |
---|
2067 | } |
---|
2068 | |
---|
2069 | - (View*)initWithFrame:(NSRect)rect |
---|
2070 | { |
---|
2071 | self = [super initWithFrame: rect]; |
---|
2072 | rubberband = NSZeroRect; |
---|
2073 | inside = false; |
---|
2074 | tracking = 0; |
---|
2075 | device_scale = 1; |
---|
2076 | return self; |
---|
2077 | } |
---|
2078 | |
---|
2079 | - (void)dealloc |
---|
2080 | { |
---|
2081 | FigureCanvas* fc = (FigureCanvas*)canvas; |
---|
2082 | if (fc) fc->view = NULL; |
---|
2083 | [self removeTrackingRect: tracking]; |
---|
2084 | [super dealloc]; |
---|
2085 | } |
---|
2086 | |
---|
2087 | - (void)setCanvas: (PyObject*)newCanvas |
---|
2088 | { |
---|
2089 | canvas = newCanvas; |
---|
2090 | } |
---|
2091 | |
---|
2092 | static void _buffer_release(void* info, const void* data, size_t size) { |
---|
2093 | PyBuffer_Release((Py_buffer *)info); |
---|
2094 | } |
---|
2095 | |
---|
2096 | static int _copy_agg_buffer(CGContextRef cr, PyObject *renderer) |
---|
2097 | { |
---|
2098 | Py_buffer buffer; |
---|
2099 | |
---|
2100 | if (PyObject_GetBuffer(renderer, &buffer, PyBUF_CONTIG_RO) == -1) { |
---|
2101 | PyErr_Print(); |
---|
2102 | return 1; |
---|
2103 | } |
---|
2104 | |
---|
2105 | if (buffer.ndim != 3 || buffer.shape[2] != 4) { |
---|
2106 | PyBuffer_Release(&buffer); |
---|
2107 | return 1; |
---|
2108 | } |
---|
2109 | |
---|
2110 | const Py_ssize_t nrows = buffer.shape[0]; |
---|
2111 | const Py_ssize_t ncols = buffer.shape[1]; |
---|
2112 | const size_t bytesPerComponent = 1; |
---|
2113 | const size_t bitsPerComponent = 8 * bytesPerComponent; |
---|
2114 | const size_t nComponents = 4; /* red, green, blue, alpha */ |
---|
2115 | const size_t bitsPerPixel = bitsPerComponent * nComponents; |
---|
2116 | const size_t bytesPerRow = nComponents * bytesPerComponent * ncols; |
---|
2117 | |
---|
2118 | CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); |
---|
2119 | if (!colorspace) { |
---|
2120 | PyBuffer_Release(&buffer); |
---|
2121 | return 1; |
---|
2122 | } |
---|
2123 | |
---|
2124 | CGDataProviderRef provider = CGDataProviderCreateWithData(&buffer, |
---|
2125 | buffer.buf, |
---|
2126 | buffer.len, |
---|
2127 | _buffer_release); |
---|
2128 | if (!provider) { |
---|
2129 | PyBuffer_Release(&buffer); |
---|
2130 | CGColorSpaceRelease(colorspace); |
---|
2131 | return 1; |
---|
2132 | } |
---|
2133 | |
---|
2134 | CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaLast; |
---|
2135 | CGImageRef bitmap = CGImageCreate(ncols, |
---|
2136 | nrows, |
---|
2137 | bitsPerComponent, |
---|
2138 | bitsPerPixel, |
---|
2139 | bytesPerRow, |
---|
2140 | colorspace, |
---|
2141 | bitmapInfo, |
---|
2142 | provider, |
---|
2143 | NULL, |
---|
2144 | false, |
---|
2145 | kCGRenderingIntentDefault); |
---|
2146 | CGColorSpaceRelease(colorspace); |
---|
2147 | CGDataProviderRelease(provider); |
---|
2148 | |
---|
2149 | if (!bitmap) { |
---|
2150 | PyBuffer_Release(&buffer); |
---|
2151 | return 1; |
---|
2152 | } |
---|
2153 | |
---|
2154 | CGFloat deviceScale = _get_device_scale(cr); |
---|
2155 | CGContextSaveGState(cr); |
---|
2156 | CGContextDrawImage(cr, CGRectMake(0, 0, ncols/deviceScale, nrows/deviceScale), bitmap); |
---|
2157 | CGImageRelease(bitmap); |
---|
2158 | CGContextRestoreGState(cr); |
---|
2159 | |
---|
2160 | return 0; |
---|
2161 | } |
---|
2162 | |
---|
2163 | -(void)drawRect:(NSRect)rect |
---|
2164 | { |
---|
2165 | PyObject* renderer = NULL; |
---|
2166 | PyObject* renderer_buffer = NULL; |
---|
2167 | |
---|
2168 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2169 | |
---|
2170 | CGContextRef cr = [[NSGraphicsContext currentContext] graphicsPort]; |
---|
2171 | |
---|
2172 | double new_device_scale = _get_device_scale(cr); |
---|
2173 | |
---|
2174 | if (device_scale != new_device_scale) { |
---|
2175 | device_scale = new_device_scale; |
---|
2176 | if (!PyObject_CallMethod(canvas, "_set_device_scale", "d", device_scale, NULL)) { |
---|
2177 | PyErr_Print(); |
---|
2178 | goto exit; |
---|
2179 | } |
---|
2180 | } |
---|
2181 | |
---|
2182 | renderer = PyObject_CallMethod(canvas, "_draw", "", NULL); |
---|
2183 | if (!renderer) |
---|
2184 | { |
---|
2185 | PyErr_Print(); |
---|
2186 | goto exit; |
---|
2187 | } |
---|
2188 | |
---|
2189 | renderer_buffer = PyObject_GetAttrString(renderer, "_renderer"); |
---|
2190 | if (!renderer_buffer) { |
---|
2191 | PyErr_Print(); |
---|
2192 | goto exit; |
---|
2193 | } |
---|
2194 | |
---|
2195 | if (_copy_agg_buffer(cr, renderer_buffer)) { |
---|
2196 | printf("copy_agg_buffer failed\n"); |
---|
2197 | goto exit; |
---|
2198 | } |
---|
2199 | |
---|
2200 | |
---|
2201 | if (!NSIsEmptyRect(rubberband)) { |
---|
2202 | NSFrameRect(rubberband); |
---|
2203 | } |
---|
2204 | |
---|
2205 | exit: |
---|
2206 | Py_XDECREF(renderer_buffer); |
---|
2207 | Py_XDECREF(renderer); |
---|
2208 | |
---|
2209 | PyGILState_Release(gstate); |
---|
2210 | } |
---|
2211 | |
---|
2212 | - (void)windowDidResize: (NSNotification*)notification |
---|
2213 | { |
---|
2214 | int width, height; |
---|
2215 | Window* window = [notification object]; |
---|
2216 | NSSize size = [[window contentView] frame].size; |
---|
2217 | NSRect rect = [self frame]; |
---|
2218 | |
---|
2219 | size.height -= rect.origin.y; |
---|
2220 | width = size.width; |
---|
2221 | height = size.height; |
---|
2222 | |
---|
2223 | [self setFrameSize: size]; |
---|
2224 | |
---|
2225 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2226 | PyObject* result = PyObject_CallMethod( |
---|
2227 | canvas, "resize", "ii", width, height); |
---|
2228 | if(result) |
---|
2229 | Py_DECREF(result); |
---|
2230 | else |
---|
2231 | PyErr_Print(); |
---|
2232 | PyGILState_Release(gstate); |
---|
2233 | if (tracking) [self removeTrackingRect: tracking]; |
---|
2234 | tracking = [self addTrackingRect: [self bounds] |
---|
2235 | owner: self |
---|
2236 | userData: nil |
---|
2237 | assumeInside: NO]; |
---|
2238 | [self setNeedsDisplay: YES]; |
---|
2239 | } |
---|
2240 | |
---|
2241 | - (void)windowWillClose:(NSNotification*)notification |
---|
2242 | { |
---|
2243 | PyGILState_STATE gstate; |
---|
2244 | PyObject* result; |
---|
2245 | |
---|
2246 | gstate = PyGILState_Ensure(); |
---|
2247 | result = PyObject_CallMethod(canvas, "close_event", ""); |
---|
2248 | if(result) |
---|
2249 | Py_DECREF(result); |
---|
2250 | else |
---|
2251 | PyErr_Print(); |
---|
2252 | PyGILState_Release(gstate); |
---|
2253 | } |
---|
2254 | |
---|
2255 | - (BOOL)windowShouldClose:(NSNotification*)notification |
---|
2256 | { |
---|
2257 | NSWindow* window = [self window]; |
---|
2258 | NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined |
---|
2259 | location: NSZeroPoint |
---|
2260 | modifierFlags: 0 |
---|
2261 | timestamp: 0.0 |
---|
2262 | windowNumber: 0 |
---|
2263 | context: nil |
---|
2264 | subtype: WINDOW_CLOSING |
---|
2265 | data1: 0 |
---|
2266 | data2: 0]; |
---|
2267 | [NSApp postEvent: event atStart: true]; |
---|
2268 | if ([window respondsToSelector: @selector(closeButtonPressed)]) |
---|
2269 | { BOOL closed = [((Window*) window) closeButtonPressed]; |
---|
2270 | /* If closed, the window has already been closed via the manager. */ |
---|
2271 | if (closed) return NO; |
---|
2272 | } |
---|
2273 | return YES; |
---|
2274 | } |
---|
2275 | |
---|
2276 | - (void)mouseEntered:(NSEvent *)event |
---|
2277 | { |
---|
2278 | PyGILState_STATE gstate; |
---|
2279 | PyObject* result; |
---|
2280 | NSWindow* window = [self window]; |
---|
2281 | if ([window isKeyWindow]==false) return; |
---|
2282 | |
---|
2283 | gstate = PyGILState_Ensure(); |
---|
2284 | result = PyObject_CallMethod(canvas, "enter_notify_event", ""); |
---|
2285 | if(result) |
---|
2286 | Py_DECREF(result); |
---|
2287 | else |
---|
2288 | PyErr_Print(); |
---|
2289 | PyGILState_Release(gstate); |
---|
2290 | |
---|
2291 | [window setAcceptsMouseMovedEvents: YES]; |
---|
2292 | inside = true; |
---|
2293 | } |
---|
2294 | |
---|
2295 | - (void)mouseExited:(NSEvent *)event |
---|
2296 | { |
---|
2297 | PyGILState_STATE gstate; |
---|
2298 | PyObject* result; |
---|
2299 | NSWindow* window = [self window]; |
---|
2300 | if ([window isKeyWindow]==false) return; |
---|
2301 | |
---|
2302 | if (inside==false) return; |
---|
2303 | gstate = PyGILState_Ensure(); |
---|
2304 | result = PyObject_CallMethod(canvas, "leave_notify_event", ""); |
---|
2305 | if(result) |
---|
2306 | Py_DECREF(result); |
---|
2307 | else |
---|
2308 | PyErr_Print(); |
---|
2309 | PyGILState_Release(gstate); |
---|
2310 | |
---|
2311 | [[self window] setAcceptsMouseMovedEvents: NO]; |
---|
2312 | inside = false; |
---|
2313 | } |
---|
2314 | |
---|
2315 | - (void)mouseDown:(NSEvent *)event |
---|
2316 | { |
---|
2317 | int x, y; |
---|
2318 | int num; |
---|
2319 | int dblclick = 0; |
---|
2320 | PyObject* result; |
---|
2321 | PyGILState_STATE gstate; |
---|
2322 | NSPoint location = [event locationInWindow]; |
---|
2323 | location = [self convertPoint: location fromView: nil]; |
---|
2324 | x = location.x * device_scale; |
---|
2325 | y = location.y * device_scale; |
---|
2326 | switch ([event type]) |
---|
2327 | { case NSLeftMouseDown: |
---|
2328 | { unsigned int modifier = [event modifierFlags]; |
---|
2329 | if (modifier & NSControlKeyMask) |
---|
2330 | /* emulate a right-button click */ |
---|
2331 | num = 3; |
---|
2332 | else if (modifier & NSAlternateKeyMask) |
---|
2333 | /* emulate a middle-button click */ |
---|
2334 | num = 2; |
---|
2335 | else |
---|
2336 | { |
---|
2337 | num = 1; |
---|
2338 | if ([NSCursor currentCursor]==[NSCursor openHandCursor]) |
---|
2339 | [[NSCursor closedHandCursor] set]; |
---|
2340 | } |
---|
2341 | break; |
---|
2342 | } |
---|
2343 | case NSOtherMouseDown: num = 2; break; |
---|
2344 | case NSRightMouseDown: num = 3; break; |
---|
2345 | default: return; /* Unknown mouse event */ |
---|
2346 | } |
---|
2347 | if ([event clickCount] == 2) { |
---|
2348 | dblclick = 1; |
---|
2349 | } |
---|
2350 | gstate = PyGILState_Ensure(); |
---|
2351 | result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick); |
---|
2352 | if(result) |
---|
2353 | Py_DECREF(result); |
---|
2354 | else |
---|
2355 | PyErr_Print(); |
---|
2356 | |
---|
2357 | PyGILState_Release(gstate); |
---|
2358 | } |
---|
2359 | |
---|
2360 | - (void)mouseUp:(NSEvent *)event |
---|
2361 | { |
---|
2362 | int num; |
---|
2363 | int x, y; |
---|
2364 | PyObject* result; |
---|
2365 | PyGILState_STATE gstate; |
---|
2366 | NSPoint location = [event locationInWindow]; |
---|
2367 | location = [self convertPoint: location fromView: nil]; |
---|
2368 | x = location.x * device_scale; |
---|
2369 | y = location.y * device_scale; |
---|
2370 | switch ([event type]) |
---|
2371 | { case NSLeftMouseUp: |
---|
2372 | num = 1; |
---|
2373 | if ([NSCursor currentCursor]==[NSCursor closedHandCursor]) |
---|
2374 | [[NSCursor openHandCursor] set]; |
---|
2375 | break; |
---|
2376 | case NSOtherMouseUp: num = 2; break; |
---|
2377 | case NSRightMouseUp: num = 3; break; |
---|
2378 | default: return; /* Unknown mouse event */ |
---|
2379 | } |
---|
2380 | gstate = PyGILState_Ensure(); |
---|
2381 | result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num); |
---|
2382 | if(result) |
---|
2383 | Py_DECREF(result); |
---|
2384 | else |
---|
2385 | PyErr_Print(); |
---|
2386 | |
---|
2387 | PyGILState_Release(gstate); |
---|
2388 | } |
---|
2389 | |
---|
2390 | - (void)mouseMoved:(NSEvent *)event |
---|
2391 | { |
---|
2392 | int x, y; |
---|
2393 | NSPoint location = [event locationInWindow]; |
---|
2394 | location = [self convertPoint: location fromView: nil]; |
---|
2395 | x = location.x * device_scale; |
---|
2396 | y = location.y * device_scale; |
---|
2397 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2398 | PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); |
---|
2399 | if(result) |
---|
2400 | Py_DECREF(result); |
---|
2401 | else |
---|
2402 | PyErr_Print(); |
---|
2403 | |
---|
2404 | PyGILState_Release(gstate); |
---|
2405 | } |
---|
2406 | |
---|
2407 | - (void)mouseDragged:(NSEvent *)event |
---|
2408 | { |
---|
2409 | int x, y; |
---|
2410 | NSPoint location = [event locationInWindow]; |
---|
2411 | location = [self convertPoint: location fromView: nil]; |
---|
2412 | x = location.x * device_scale; |
---|
2413 | y = location.y * device_scale; |
---|
2414 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2415 | PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); |
---|
2416 | if(result) |
---|
2417 | Py_DECREF(result); |
---|
2418 | else |
---|
2419 | PyErr_Print(); |
---|
2420 | |
---|
2421 | PyGILState_Release(gstate); |
---|
2422 | } |
---|
2423 | |
---|
2424 | - (void)rightMouseDown:(NSEvent *)event |
---|
2425 | { |
---|
2426 | int x, y; |
---|
2427 | int num = 3; |
---|
2428 | int dblclick = 0; |
---|
2429 | PyObject* result; |
---|
2430 | PyGILState_STATE gstate; |
---|
2431 | NSPoint location = [event locationInWindow]; |
---|
2432 | location = [self convertPoint: location fromView: nil]; |
---|
2433 | x = location.x * device_scale; |
---|
2434 | y = location.y * device_scale; |
---|
2435 | gstate = PyGILState_Ensure(); |
---|
2436 | if ([event clickCount] == 2) { |
---|
2437 | dblclick = 1; |
---|
2438 | } |
---|
2439 | result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick); |
---|
2440 | if(result) |
---|
2441 | Py_DECREF(result); |
---|
2442 | else |
---|
2443 | PyErr_Print(); |
---|
2444 | |
---|
2445 | PyGILState_Release(gstate); |
---|
2446 | } |
---|
2447 | |
---|
2448 | - (void)rightMouseUp:(NSEvent *)event |
---|
2449 | { |
---|
2450 | int x, y; |
---|
2451 | int num = 3; |
---|
2452 | PyObject* result; |
---|
2453 | PyGILState_STATE gstate; |
---|
2454 | NSPoint location = [event locationInWindow]; |
---|
2455 | location = [self convertPoint: location fromView: nil]; |
---|
2456 | x = location.x * device_scale; |
---|
2457 | y = location.y * device_scale; |
---|
2458 | gstate = PyGILState_Ensure(); |
---|
2459 | result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num); |
---|
2460 | if(result) |
---|
2461 | Py_DECREF(result); |
---|
2462 | else |
---|
2463 | PyErr_Print(); |
---|
2464 | |
---|
2465 | PyGILState_Release(gstate); |
---|
2466 | } |
---|
2467 | |
---|
2468 | - (void)rightMouseDragged:(NSEvent *)event |
---|
2469 | { |
---|
2470 | int x, y; |
---|
2471 | NSPoint location = [event locationInWindow]; |
---|
2472 | location = [self convertPoint: location fromView: nil]; |
---|
2473 | x = location.x * device_scale; |
---|
2474 | y = location.y * device_scale; |
---|
2475 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2476 | PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); |
---|
2477 | if(result) |
---|
2478 | Py_DECREF(result); |
---|
2479 | else |
---|
2480 | PyErr_Print(); |
---|
2481 | |
---|
2482 | PyGILState_Release(gstate); |
---|
2483 | } |
---|
2484 | |
---|
2485 | - (void)otherMouseDown:(NSEvent *)event |
---|
2486 | { |
---|
2487 | int x, y; |
---|
2488 | int num = 2; |
---|
2489 | int dblclick = 0; |
---|
2490 | PyObject* result; |
---|
2491 | PyGILState_STATE gstate; |
---|
2492 | NSPoint location = [event locationInWindow]; |
---|
2493 | location = [self convertPoint: location fromView: nil]; |
---|
2494 | x = location.x * device_scale; |
---|
2495 | y = location.y * device_scale; |
---|
2496 | gstate = PyGILState_Ensure(); |
---|
2497 | if ([event clickCount] == 2) { |
---|
2498 | dblclick = 1; |
---|
2499 | } |
---|
2500 | result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick); |
---|
2501 | if(result) |
---|
2502 | Py_DECREF(result); |
---|
2503 | else |
---|
2504 | PyErr_Print(); |
---|
2505 | |
---|
2506 | PyGILState_Release(gstate); |
---|
2507 | } |
---|
2508 | |
---|
2509 | - (void)otherMouseUp:(NSEvent *)event |
---|
2510 | { |
---|
2511 | int x, y; |
---|
2512 | int num = 2; |
---|
2513 | PyObject* result; |
---|
2514 | PyGILState_STATE gstate; |
---|
2515 | NSPoint location = [event locationInWindow]; |
---|
2516 | location = [self convertPoint: location fromView: nil]; |
---|
2517 | x = location.x * device_scale; |
---|
2518 | y = location.y * device_scale; |
---|
2519 | gstate = PyGILState_Ensure(); |
---|
2520 | result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num); |
---|
2521 | if(result) |
---|
2522 | Py_DECREF(result); |
---|
2523 | else |
---|
2524 | PyErr_Print(); |
---|
2525 | |
---|
2526 | PyGILState_Release(gstate); |
---|
2527 | } |
---|
2528 | |
---|
2529 | - (void)otherMouseDragged:(NSEvent *)event |
---|
2530 | { |
---|
2531 | int x, y; |
---|
2532 | NSPoint location = [event locationInWindow]; |
---|
2533 | location = [self convertPoint: location fromView: nil]; |
---|
2534 | x = location.x * device_scale; |
---|
2535 | y = location.y * device_scale; |
---|
2536 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2537 | PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); |
---|
2538 | if(result) |
---|
2539 | Py_DECREF(result); |
---|
2540 | else |
---|
2541 | PyErr_Print(); |
---|
2542 | |
---|
2543 | PyGILState_Release(gstate); |
---|
2544 | } |
---|
2545 | |
---|
2546 | - (void)setRubberband:(NSRect)rect |
---|
2547 | { |
---|
2548 | if (!NSIsEmptyRect(rubberband)) [self setNeedsDisplayInRect: rubberband]; |
---|
2549 | rubberband = rect; |
---|
2550 | [self setNeedsDisplayInRect: rubberband]; |
---|
2551 | } |
---|
2552 | |
---|
2553 | - (void)removeRubberband |
---|
2554 | { |
---|
2555 | if (NSIsEmptyRect(rubberband)) return; |
---|
2556 | [self setNeedsDisplayInRect: rubberband]; |
---|
2557 | rubberband = NSZeroRect; |
---|
2558 | } |
---|
2559 | |
---|
2560 | |
---|
2561 | |
---|
2562 | - (const char*)convertKeyEvent:(NSEvent*)event |
---|
2563 | { |
---|
2564 | NSDictionary* specialkeymappings = [NSDictionary dictionaryWithObjectsAndKeys: |
---|
2565 | @"left", [NSNumber numberWithUnsignedLong:NSLeftArrowFunctionKey], |
---|
2566 | @"right", [NSNumber numberWithUnsignedLong:NSRightArrowFunctionKey], |
---|
2567 | @"up", [NSNumber numberWithUnsignedLong:NSUpArrowFunctionKey], |
---|
2568 | @"down", [NSNumber numberWithUnsignedLong:NSDownArrowFunctionKey], |
---|
2569 | @"f1", [NSNumber numberWithUnsignedLong:NSF1FunctionKey], |
---|
2570 | @"f2", [NSNumber numberWithUnsignedLong:NSF2FunctionKey], |
---|
2571 | @"f3", [NSNumber numberWithUnsignedLong:NSF3FunctionKey], |
---|
2572 | @"f4", [NSNumber numberWithUnsignedLong:NSF4FunctionKey], |
---|
2573 | @"f5", [NSNumber numberWithUnsignedLong:NSF5FunctionKey], |
---|
2574 | @"f6", [NSNumber numberWithUnsignedLong:NSF6FunctionKey], |
---|
2575 | @"f7", [NSNumber numberWithUnsignedLong:NSF7FunctionKey], |
---|
2576 | @"f8", [NSNumber numberWithUnsignedLong:NSF8FunctionKey], |
---|
2577 | @"f9", [NSNumber numberWithUnsignedLong:NSF9FunctionKey], |
---|
2578 | @"f10", [NSNumber numberWithUnsignedLong:NSF10FunctionKey], |
---|
2579 | @"f11", [NSNumber numberWithUnsignedLong:NSF11FunctionKey], |
---|
2580 | @"f12", [NSNumber numberWithUnsignedLong:NSF12FunctionKey], |
---|
2581 | @"f13", [NSNumber numberWithUnsignedLong:NSF13FunctionKey], |
---|
2582 | @"f14", [NSNumber numberWithUnsignedLong:NSF14FunctionKey], |
---|
2583 | @"f15", [NSNumber numberWithUnsignedLong:NSF15FunctionKey], |
---|
2584 | @"f16", [NSNumber numberWithUnsignedLong:NSF16FunctionKey], |
---|
2585 | @"f17", [NSNumber numberWithUnsignedLong:NSF17FunctionKey], |
---|
2586 | @"f18", [NSNumber numberWithUnsignedLong:NSF18FunctionKey], |
---|
2587 | @"f19", [NSNumber numberWithUnsignedLong:NSF19FunctionKey], |
---|
2588 | @"scroll_lock", [NSNumber numberWithUnsignedLong:NSScrollLockFunctionKey], |
---|
2589 | @"break", [NSNumber numberWithUnsignedLong:NSBreakFunctionKey], |
---|
2590 | @"insert", [NSNumber numberWithUnsignedLong:NSInsertFunctionKey], |
---|
2591 | @"delete", [NSNumber numberWithUnsignedLong:NSDeleteFunctionKey], |
---|
2592 | @"home", [NSNumber numberWithUnsignedLong:NSHomeFunctionKey], |
---|
2593 | @"end", [NSNumber numberWithUnsignedLong:NSEndFunctionKey], |
---|
2594 | @"pagedown", [NSNumber numberWithUnsignedLong:NSPageDownFunctionKey], |
---|
2595 | @"pageup", [NSNumber numberWithUnsignedLong:NSPageUpFunctionKey], |
---|
2596 | @"backspace", [NSNumber numberWithUnsignedLong:NSDeleteCharacter], |
---|
2597 | @"enter", [NSNumber numberWithUnsignedLong:NSEnterCharacter], |
---|
2598 | @"tab", [NSNumber numberWithUnsignedLong:NSTabCharacter], |
---|
2599 | @"enter", [NSNumber numberWithUnsignedLong:NSCarriageReturnCharacter], |
---|
2600 | @"backtab", [NSNumber numberWithUnsignedLong:NSBackTabCharacter], |
---|
2601 | @"escape", [NSNumber numberWithUnsignedLong:27], |
---|
2602 | nil |
---|
2603 | ]; |
---|
2604 | |
---|
2605 | NSMutableString* returnkey = [NSMutableString string]; |
---|
2606 | if ([event modifierFlags] & NSControlKeyMask) |
---|
2607 | [returnkey appendString:@"ctrl+" ]; |
---|
2608 | if ([event modifierFlags] & NSAlternateKeyMask) |
---|
2609 | [returnkey appendString:@"alt+" ]; |
---|
2610 | if ([event modifierFlags] & NSCommandKeyMask) |
---|
2611 | [returnkey appendString:@"cmd+" ]; |
---|
2612 | |
---|
2613 | unichar uc = [[event charactersIgnoringModifiers] characterAtIndex:0]; |
---|
2614 | NSString* specialchar = [specialkeymappings objectForKey:[NSNumber numberWithUnsignedLong:uc]]; |
---|
2615 | if (specialchar) |
---|
2616 | [returnkey appendString:specialchar]; |
---|
2617 | else |
---|
2618 | [returnkey appendString:[event charactersIgnoringModifiers]]; |
---|
2619 | |
---|
2620 | return [returnkey UTF8String]; |
---|
2621 | } |
---|
2622 | |
---|
2623 | - (void)keyDown:(NSEvent*)event |
---|
2624 | { |
---|
2625 | PyObject* result; |
---|
2626 | const char* s = [self convertKeyEvent: event]; |
---|
2627 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2628 | if (s==NULL) |
---|
2629 | { |
---|
2630 | result = PyObject_CallMethod(canvas, "key_press_event", "O", Py_None); |
---|
2631 | } |
---|
2632 | else |
---|
2633 | { |
---|
2634 | result = PyObject_CallMethod(canvas, "key_press_event", "s", s); |
---|
2635 | } |
---|
2636 | if(result) |
---|
2637 | Py_DECREF(result); |
---|
2638 | else |
---|
2639 | PyErr_Print(); |
---|
2640 | |
---|
2641 | PyGILState_Release(gstate); |
---|
2642 | } |
---|
2643 | |
---|
2644 | - (void)keyUp:(NSEvent*)event |
---|
2645 | { |
---|
2646 | PyObject* result; |
---|
2647 | const char* s = [self convertKeyEvent: event]; |
---|
2648 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2649 | if (s==NULL) |
---|
2650 | { |
---|
2651 | result = PyObject_CallMethod(canvas, "key_release_event", "O", Py_None); |
---|
2652 | } |
---|
2653 | else |
---|
2654 | { |
---|
2655 | result = PyObject_CallMethod(canvas, "key_release_event", "s", s); |
---|
2656 | } |
---|
2657 | if(result) |
---|
2658 | Py_DECREF(result); |
---|
2659 | else |
---|
2660 | PyErr_Print(); |
---|
2661 | |
---|
2662 | PyGILState_Release(gstate); |
---|
2663 | } |
---|
2664 | |
---|
2665 | - (void)scrollWheel:(NSEvent*)event |
---|
2666 | { |
---|
2667 | int step; |
---|
2668 | float d = [event deltaY]; |
---|
2669 | if (d > 0) step = 1; |
---|
2670 | else if (d < 0) step = -1; |
---|
2671 | else return; |
---|
2672 | NSPoint location = [event locationInWindow]; |
---|
2673 | NSPoint point = [self convertPoint: location fromView: nil]; |
---|
2674 | int x = (int)round(point.x * device_scale); |
---|
2675 | int y = (int)round(point.y * device_scale - 1); |
---|
2676 | |
---|
2677 | PyObject* result; |
---|
2678 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2679 | result = PyObject_CallMethod(canvas, "scroll_event", "iii", x, y, step); |
---|
2680 | if(result) |
---|
2681 | Py_DECREF(result); |
---|
2682 | else |
---|
2683 | PyErr_Print(); |
---|
2684 | |
---|
2685 | PyGILState_Release(gstate); |
---|
2686 | } |
---|
2687 | |
---|
2688 | - (BOOL)acceptsFirstResponder |
---|
2689 | { |
---|
2690 | return YES; |
---|
2691 | } |
---|
2692 | |
---|
2693 | /* This is all wrong. Address of pointer is being passed instead of pointer, keynames don't |
---|
2694 | match up with what the front-end and does the front-end even handle modifier keys by themselves? |
---|
2695 | |
---|
2696 | - (void)flagsChanged:(NSEvent*)event |
---|
2697 | { |
---|
2698 | const char *s = NULL; |
---|
2699 | if (([event modifierFlags] & NSControlKeyMask) == NSControlKeyMask) |
---|
2700 | s = "control"; |
---|
2701 | else if (([event modifierFlags] & NSShiftKeyMask) == NSShiftKeyMask) |
---|
2702 | s = "shift"; |
---|
2703 | else if (([event modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask) |
---|
2704 | s = "alt"; |
---|
2705 | else return; |
---|
2706 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2707 | PyObject* result = PyObject_CallMethod(canvas, "key_press_event", "s", &s); |
---|
2708 | if(result) |
---|
2709 | Py_DECREF(result); |
---|
2710 | else |
---|
2711 | PyErr_Print(); |
---|
2712 | |
---|
2713 | PyGILState_Release(gstate); |
---|
2714 | } |
---|
2715 | */ |
---|
2716 | @end |
---|
2717 | |
---|
2718 | @implementation ScrollableButton |
---|
2719 | - (void)setScrollWheelUpAction:(SEL)action |
---|
2720 | { |
---|
2721 | scrollWheelUpAction = action; |
---|
2722 | } |
---|
2723 | |
---|
2724 | - (void)setScrollWheelDownAction:(SEL)action |
---|
2725 | { |
---|
2726 | scrollWheelDownAction = action; |
---|
2727 | } |
---|
2728 | |
---|
2729 | - (void)scrollWheel:(NSEvent*)event |
---|
2730 | { |
---|
2731 | float d = [event deltaY]; |
---|
2732 | Window* target = [self target]; |
---|
2733 | if (d > 0) |
---|
2734 | [NSApp sendAction: scrollWheelUpAction to: target from: self]; |
---|
2735 | else if (d < 0) |
---|
2736 | [NSApp sendAction: scrollWheelDownAction to: target from: self]; |
---|
2737 | } |
---|
2738 | @end |
---|
2739 | |
---|
2740 | @implementation MenuItem |
---|
2741 | + (MenuItem*)menuItemWithTitle: (NSString*)title |
---|
2742 | { |
---|
2743 | MenuItem* item = [[MenuItem alloc] initWithTitle: title |
---|
2744 | action: nil |
---|
2745 | keyEquivalent: @""]; |
---|
2746 | item->index = -1; |
---|
2747 | return [item autorelease]; |
---|
2748 | } |
---|
2749 | |
---|
2750 | + (MenuItem*)menuItemForAxis: (int)i |
---|
2751 | { |
---|
2752 | NSString* title = [NSString stringWithFormat: @"Axis %d", i+1]; |
---|
2753 | MenuItem* item = [[MenuItem alloc] initWithTitle: title |
---|
2754 | action: @selector(toggle:) |
---|
2755 | keyEquivalent: @""]; |
---|
2756 | [item setTarget: item]; |
---|
2757 | [item setState: NSOnState]; |
---|
2758 | item->index = i; |
---|
2759 | return [item autorelease]; |
---|
2760 | } |
---|
2761 | |
---|
2762 | + (MenuItem*)menuItemSelectAll |
---|
2763 | { |
---|
2764 | MenuItem* item = [[MenuItem alloc] initWithTitle: @"Select All" |
---|
2765 | action: @selector(selectAll:) |
---|
2766 | keyEquivalent: @""]; |
---|
2767 | [item setTarget: item]; |
---|
2768 | item->index = -1; |
---|
2769 | return [item autorelease]; |
---|
2770 | } |
---|
2771 | |
---|
2772 | + (MenuItem*)menuItemInvertAll |
---|
2773 | { |
---|
2774 | MenuItem* item = [[MenuItem alloc] initWithTitle: @"Invert All" |
---|
2775 | action: @selector(invertAll:) |
---|
2776 | keyEquivalent: @""]; |
---|
2777 | [item setTarget: item]; |
---|
2778 | item->index = -1; |
---|
2779 | return [item autorelease]; |
---|
2780 | } |
---|
2781 | |
---|
2782 | - (void)toggle:(id)sender |
---|
2783 | { |
---|
2784 | if ([self state]) [self setState: NSOffState]; |
---|
2785 | else [self setState: NSOnState]; |
---|
2786 | } |
---|
2787 | |
---|
2788 | - (void)selectAll:(id)sender |
---|
2789 | { |
---|
2790 | NSMenu* menu = [sender menu]; |
---|
2791 | if(!menu) return; /* Weird */ |
---|
2792 | NSArray* items = [menu itemArray]; |
---|
2793 | NSEnumerator* enumerator = [items objectEnumerator]; |
---|
2794 | MenuItem* item; |
---|
2795 | while ((item = [enumerator nextObject])) |
---|
2796 | { |
---|
2797 | if (item->index >= 0) [item setState: NSOnState]; |
---|
2798 | } |
---|
2799 | } |
---|
2800 | |
---|
2801 | - (void)invertAll:(id)sender |
---|
2802 | { |
---|
2803 | NSMenu* menu = [sender menu]; |
---|
2804 | if(!menu) return; /* Weird */ |
---|
2805 | NSArray* items = [menu itemArray]; |
---|
2806 | NSEnumerator* enumerator = [items objectEnumerator]; |
---|
2807 | MenuItem* item; |
---|
2808 | while ((item = [enumerator nextObject])) |
---|
2809 | { |
---|
2810 | if (item->index < 0) continue; |
---|
2811 | if ([item state]==NSOffState) [item setState: NSOnState]; |
---|
2812 | else [item setState: NSOffState]; |
---|
2813 | } |
---|
2814 | } |
---|
2815 | |
---|
2816 | - (int)index |
---|
2817 | { |
---|
2818 | return self->index; |
---|
2819 | } |
---|
2820 | @end |
---|
2821 | |
---|
2822 | static PyObject* |
---|
2823 | show(PyObject* self) |
---|
2824 | { |
---|
2825 | [NSApp activateIgnoringOtherApps: YES]; |
---|
2826 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
2827 | NSArray *windowsArray = [NSApp windows]; |
---|
2828 | NSEnumerator *enumerator = [windowsArray objectEnumerator]; |
---|
2829 | NSWindow *window; |
---|
2830 | while ((window = [enumerator nextObject])) { |
---|
2831 | [window orderFront:nil]; |
---|
2832 | } |
---|
2833 | [pool release]; |
---|
2834 | Py_BEGIN_ALLOW_THREADS |
---|
2835 | [NSApp run]; |
---|
2836 | Py_END_ALLOW_THREADS |
---|
2837 | Py_RETURN_NONE; |
---|
2838 | } |
---|
2839 | |
---|
2840 | typedef struct { |
---|
2841 | PyObject_HEAD |
---|
2842 | CFRunLoopTimerRef timer; |
---|
2843 | } Timer; |
---|
2844 | |
---|
2845 | static PyObject* |
---|
2846 | Timer_new(PyTypeObject* type, PyObject *args, PyObject *kwds) |
---|
2847 | { |
---|
2848 | Timer* self = (Timer*)type->tp_alloc(type, 0); |
---|
2849 | if (!self) return NULL; |
---|
2850 | self->timer = NULL; |
---|
2851 | return (PyObject*) self; |
---|
2852 | } |
---|
2853 | |
---|
2854 | static PyObject* |
---|
2855 | Timer_repr(Timer* self) |
---|
2856 | { |
---|
2857 | #if PY3K |
---|
2858 | return PyUnicode_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p", |
---|
2859 | (void*) self, (void*)(self->timer)); |
---|
2860 | #else |
---|
2861 | return PyString_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p", |
---|
2862 | (void*) self, (void*)(self->timer)); |
---|
2863 | #endif |
---|
2864 | } |
---|
2865 | |
---|
2866 | static char Timer_doc[] = |
---|
2867 | "A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop.\n"; |
---|
2868 | |
---|
2869 | static void timer_callback(CFRunLoopTimerRef timer, void* info) |
---|
2870 | { |
---|
2871 | PyObject* method = info; |
---|
2872 | PyGILState_STATE gstate = PyGILState_Ensure(); |
---|
2873 | PyObject* result = PyObject_CallFunction(method, NULL); |
---|
2874 | if (result) { |
---|
2875 | Py_DECREF(result); |
---|
2876 | } else { |
---|
2877 | PyErr_Print(); |
---|
2878 | } |
---|
2879 | PyGILState_Release(gstate); |
---|
2880 | } |
---|
2881 | |
---|
2882 | static void context_cleanup(const void* info) |
---|
2883 | { |
---|
2884 | Py_DECREF((PyObject*)info); |
---|
2885 | } |
---|
2886 | |
---|
2887 | static PyObject* |
---|
2888 | Timer__timer_start(Timer* self, PyObject* args) |
---|
2889 | { |
---|
2890 | CFRunLoopRef runloop; |
---|
2891 | CFRunLoopTimerRef timer; |
---|
2892 | CFRunLoopTimerContext context; |
---|
2893 | double milliseconds; |
---|
2894 | CFTimeInterval interval; |
---|
2895 | PyObject* attribute; |
---|
2896 | PyObject* failure; |
---|
2897 | runloop = CFRunLoopGetCurrent(); |
---|
2898 | if (!runloop) { |
---|
2899 | PyErr_SetString(PyExc_RuntimeError, "Failed to obtain run loop"); |
---|
2900 | return NULL; |
---|
2901 | } |
---|
2902 | attribute = PyObject_GetAttrString((PyObject*)self, "_interval"); |
---|
2903 | if (attribute==NULL) |
---|
2904 | { |
---|
2905 | PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_interval'"); |
---|
2906 | return NULL; |
---|
2907 | } |
---|
2908 | milliseconds = PyFloat_AsDouble(attribute); |
---|
2909 | failure = PyErr_Occurred(); |
---|
2910 | Py_DECREF(attribute); |
---|
2911 | if (failure) return NULL; |
---|
2912 | attribute = PyObject_GetAttrString((PyObject*)self, "_single"); |
---|
2913 | if (attribute==NULL) |
---|
2914 | { |
---|
2915 | PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_single'"); |
---|
2916 | return NULL; |
---|
2917 | } |
---|
2918 | switch (PyObject_IsTrue(attribute)) { |
---|
2919 | case 1: |
---|
2920 | interval = 0; |
---|
2921 | break; |
---|
2922 | case 0: |
---|
2923 | interval = milliseconds / 1000.0; |
---|
2924 | break; |
---|
2925 | case -1: |
---|
2926 | default: |
---|
2927 | PyErr_SetString(PyExc_ValueError, "Cannot interpret _single attribute as True of False"); |
---|
2928 | return NULL; |
---|
2929 | } |
---|
2930 | Py_DECREF(attribute); |
---|
2931 | attribute = PyObject_GetAttrString((PyObject*)self, "_on_timer"); |
---|
2932 | if (attribute==NULL) |
---|
2933 | { |
---|
2934 | PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_on_timer'"); |
---|
2935 | return NULL; |
---|
2936 | } |
---|
2937 | if (!PyMethod_Check(attribute)) { |
---|
2938 | PyErr_SetString(PyExc_RuntimeError, "_on_timer should be a Python method"); |
---|
2939 | return NULL; |
---|
2940 | } |
---|
2941 | context.version = 0; |
---|
2942 | context.retain = NULL; |
---|
2943 | context.release = context_cleanup; |
---|
2944 | context.copyDescription = NULL; |
---|
2945 | context.info = attribute; |
---|
2946 | timer = CFRunLoopTimerCreate(kCFAllocatorDefault, |
---|
2947 | 0, |
---|
2948 | interval, |
---|
2949 | 0, |
---|
2950 | 0, |
---|
2951 | timer_callback, |
---|
2952 | &context); |
---|
2953 | if (!timer) { |
---|
2954 | Py_DECREF(attribute); |
---|
2955 | PyErr_SetString(PyExc_RuntimeError, "Failed to create timer"); |
---|
2956 | return NULL; |
---|
2957 | } |
---|
2958 | if (self->timer) { |
---|
2959 | CFRunLoopTimerInvalidate(self->timer); |
---|
2960 | CFRelease(self->timer); |
---|
2961 | } |
---|
2962 | CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes); |
---|
2963 | /* Don't release the timer here, since the run loop may be destroyed and |
---|
2964 | * the timer lost before we have a chance to decrease the reference count |
---|
2965 | * of the attribute */ |
---|
2966 | self->timer = timer; |
---|
2967 | Py_RETURN_NONE; |
---|
2968 | } |
---|
2969 | |
---|
2970 | static PyObject* |
---|
2971 | Timer__timer_stop(Timer* self) |
---|
2972 | { |
---|
2973 | if (self->timer) { |
---|
2974 | CFRunLoopTimerInvalidate(self->timer); |
---|
2975 | CFRelease(self->timer); |
---|
2976 | self->timer = NULL; |
---|
2977 | } |
---|
2978 | Py_RETURN_NONE; |
---|
2979 | } |
---|
2980 | |
---|
2981 | static void |
---|
2982 | Timer_dealloc(Timer* self) |
---|
2983 | { |
---|
2984 | Timer__timer_stop(self); |
---|
2985 | Py_TYPE(self)->tp_free((PyObject*)self); |
---|
2986 | } |
---|
2987 | |
---|
2988 | static PyMethodDef Timer_methods[] = { |
---|
2989 | {"_timer_start", |
---|
2990 | (PyCFunction)Timer__timer_start, |
---|
2991 | METH_VARARGS, |
---|
2992 | "Initialize and start the timer." |
---|
2993 | }, |
---|
2994 | {"_timer_stop", |
---|
2995 | (PyCFunction)Timer__timer_stop, |
---|
2996 | METH_NOARGS, |
---|
2997 | "Stop the timer." |
---|
2998 | }, |
---|
2999 | {NULL} /* Sentinel */ |
---|
3000 | }; |
---|
3001 | |
---|
3002 | static PyTypeObject TimerType = { |
---|
3003 | PyVarObject_HEAD_INIT(NULL, 0) |
---|
3004 | "_macosx.Timer", /*tp_name*/ |
---|
3005 | sizeof(Timer), /*tp_basicsize*/ |
---|
3006 | 0, /*tp_itemsize*/ |
---|
3007 | (destructor)Timer_dealloc, /*tp_dealloc*/ |
---|
3008 | 0, /*tp_print*/ |
---|
3009 | 0, /*tp_getattr*/ |
---|
3010 | 0, /*tp_setattr*/ |
---|
3011 | 0, /*tp_compare*/ |
---|
3012 | (reprfunc)Timer_repr, /*tp_repr*/ |
---|
3013 | 0, /*tp_as_number*/ |
---|
3014 | 0, /*tp_as_sequence*/ |
---|
3015 | 0, /*tp_as_mapping*/ |
---|
3016 | 0, /*tp_hash */ |
---|
3017 | 0, /*tp_call*/ |
---|
3018 | 0, /*tp_str*/ |
---|
3019 | 0, /*tp_getattro*/ |
---|
3020 | 0, /*tp_setattro*/ |
---|
3021 | 0, /*tp_as_buffer*/ |
---|
3022 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
3023 | Timer_doc, /* tp_doc */ |
---|
3024 | 0, /* tp_traverse */ |
---|
3025 | 0, /* tp_clear */ |
---|
3026 | 0, /* tp_richcompare */ |
---|
3027 | 0, /* tp_weaklistoffset */ |
---|
3028 | 0, /* tp_iter */ |
---|
3029 | 0, /* tp_iternext */ |
---|
3030 | Timer_methods, /* tp_methods */ |
---|
3031 | 0, /* tp_members */ |
---|
3032 | 0, /* tp_getset */ |
---|
3033 | 0, /* tp_base */ |
---|
3034 | 0, /* tp_dict */ |
---|
3035 | 0, /* tp_descr_get */ |
---|
3036 | 0, /* tp_descr_set */ |
---|
3037 | 0, /* tp_dictoffset */ |
---|
3038 | 0, /* tp_init */ |
---|
3039 | 0, /* tp_alloc */ |
---|
3040 | Timer_new, /* tp_new */ |
---|
3041 | }; |
---|
3042 | |
---|
3043 | static bool verify_framework(void) |
---|
3044 | { |
---|
3045 | #ifdef COMPILING_FOR_10_6 |
---|
3046 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
3047 | NSRunningApplication* app = [NSRunningApplication currentApplication]; |
---|
3048 | NSApplicationActivationPolicy activationPolicy = [app activationPolicy]; |
---|
3049 | [pool release]; |
---|
3050 | switch (activationPolicy) { |
---|
3051 | case NSApplicationActivationPolicyRegular: |
---|
3052 | case NSApplicationActivationPolicyAccessory: |
---|
3053 | return true; |
---|
3054 | case NSApplicationActivationPolicyProhibited: |
---|
3055 | break; |
---|
3056 | } |
---|
3057 | #else |
---|
3058 | ProcessSerialNumber psn; |
---|
3059 | if (CGMainDisplayID()!=0 |
---|
3060 | && GetCurrentProcess(&psn)==noErr |
---|
3061 | && SetFrontProcess(&psn)==noErr) return true; |
---|
3062 | #endif |
---|
3063 | PyErr_SetString(PyExc_RuntimeError, |
---|
3064 | "Python is not installed as a framework. The Mac OS X backend will " |
---|
3065 | "not be able to function correctly if Python is not installed as a " |
---|
3066 | "framework. See the Python documentation for more information on " |
---|
3067 | "installing Python as a framework on Mac OS X. Please either reinstall " |
---|
3068 | "Python as a framework, or try one of the other backends. If you are " |
---|
3069 | "using (Ana)Conda please install python.app and replace the use of 'python' " |
---|
3070 | "with 'pythonw'. See 'Working with Matplotlib on OSX' " |
---|
3071 | "in the Matplotlib FAQ for more information."); |
---|
3072 | return false; |
---|
3073 | } |
---|
3074 | |
---|
3075 | static struct PyMethodDef methods[] = { |
---|
3076 | {"show", |
---|
3077 | (PyCFunction)show, |
---|
3078 | METH_NOARGS, |
---|
3079 | "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." |
---|
3080 | }, |
---|
3081 | {"choose_save_file", |
---|
3082 | (PyCFunction)choose_save_file, |
---|
3083 | METH_VARARGS, |
---|
3084 | "Closes the window." |
---|
3085 | }, |
---|
3086 | {"set_cursor", |
---|
3087 | (PyCFunction)set_cursor, |
---|
3088 | METH_VARARGS, |
---|
3089 | "Sets the active cursor." |
---|
3090 | }, |
---|
3091 | {NULL, NULL, 0, NULL}/* sentinel */ |
---|
3092 | }; |
---|
3093 | |
---|
3094 | #if PY3K |
---|
3095 | |
---|
3096 | static struct PyModuleDef moduledef = { |
---|
3097 | PyModuleDef_HEAD_INIT, |
---|
3098 | "_macosx", |
---|
3099 | "Mac OS X native backend", |
---|
3100 | -1, |
---|
3101 | methods, |
---|
3102 | NULL, |
---|
3103 | NULL, |
---|
3104 | NULL, |
---|
3105 | NULL |
---|
3106 | }; |
---|
3107 | |
---|
3108 | PyObject* PyInit__macosx(void) |
---|
3109 | |
---|
3110 | #else |
---|
3111 | |
---|
3112 | void init_macosx(void) |
---|
3113 | #endif |
---|
3114 | { |
---|
3115 | PyObject *module; |
---|
3116 | |
---|
3117 | if (PyType_Ready(&FigureCanvasType) < 0 |
---|
3118 | || PyType_Ready(&FigureManagerType) < 0 |
---|
3119 | || PyType_Ready(&NavigationToolbarType) < 0 |
---|
3120 | || PyType_Ready(&NavigationToolbar2Type) < 0 |
---|
3121 | || PyType_Ready(&TimerType) < 0) |
---|
3122 | #if PY3K |
---|
3123 | return NULL; |
---|
3124 | #else |
---|
3125 | return; |
---|
3126 | #endif |
---|
3127 | |
---|
3128 | NSApp = [NSApplication sharedApplication]; |
---|
3129 | |
---|
3130 | if (!verify_framework()) |
---|
3131 | #if PY3K |
---|
3132 | return NULL; |
---|
3133 | #else |
---|
3134 | return; |
---|
3135 | #endif |
---|
3136 | |
---|
3137 | #if PY3K |
---|
3138 | module = PyModule_Create(&moduledef); |
---|
3139 | if (module==NULL) return NULL; |
---|
3140 | #else |
---|
3141 | module = Py_InitModule4("_macosx", |
---|
3142 | methods, |
---|
3143 | "Mac OS X native backend", |
---|
3144 | NULL, |
---|
3145 | PYTHON_API_VERSION); |
---|
3146 | #endif |
---|
3147 | |
---|
3148 | Py_INCREF(&FigureCanvasType); |
---|
3149 | Py_INCREF(&FigureManagerType); |
---|
3150 | Py_INCREF(&NavigationToolbarType); |
---|
3151 | Py_INCREF(&NavigationToolbar2Type); |
---|
3152 | Py_INCREF(&TimerType); |
---|
3153 | PyModule_AddObject(module, "FigureCanvas", (PyObject*) &FigureCanvasType); |
---|
3154 | PyModule_AddObject(module, "FigureManager", (PyObject*) &FigureManagerType); |
---|
3155 | PyModule_AddObject(module, "NavigationToolbar", (PyObject*) &NavigationToolbarType); |
---|
3156 | PyModule_AddObject(module, "NavigationToolbar2", (PyObject*) &NavigationToolbar2Type); |
---|
3157 | PyModule_AddObject(module, "Timer", (PyObject*) &TimerType); |
---|
3158 | |
---|
3159 | PyOS_InputHook = wait_for_stdin; |
---|
3160 | |
---|
3161 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
---|
3162 | WindowServerConnectionManager* connectionManager = [WindowServerConnectionManager sharedManager]; |
---|
3163 | NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; |
---|
3164 | NSNotificationCenter* notificationCenter = [workspace notificationCenter]; |
---|
3165 | [notificationCenter addObserver: connectionManager |
---|
3166 | selector: @selector(launch:) |
---|
3167 | name: NSWorkspaceDidLaunchApplicationNotification |
---|
3168 | object: nil]; |
---|
3169 | [pool release]; |
---|
3170 | #if PY3K |
---|
3171 | return module; |
---|
3172 | #endif |
---|
3173 | } |
---|