|
From: <md...@us...> - 2010-10-11 14:04:49
|
Revision: 8741
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8741&view=rev
Author: mdehoon
Date: 2010-10-11 14:04:43 +0000 (Mon, 11 Oct 2010)
Log Message:
-----------
First attempt to implement a timer in the Mac OS X backend. Blitting has not
(yet?) been implemented, but otherwise it seems to work fine.
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py
trunk/matplotlib/src/_macosx.m
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2010-10-11 04:50:58 UTC (rev 8740)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2010-10-11 14:04:43 UTC (rev 8741)
@@ -5,7 +5,7 @@
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
- FigureManagerBase, FigureCanvasBase, NavigationToolbar2
+ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, TimerBase
from matplotlib.backend_bases import ShowBase
from matplotlib.cbook import maxdict
@@ -240,6 +240,24 @@
manager = FigureManagerMac(canvas, num)
return manager
+class TimerMac(_macosx.Timer, TimerBase):
+ '''
+ Subclass of :class:`backend_bases.TimerBase` that uses CoreFoundation
+ run loops for timer events.
+
+ Attributes:
+ * interval: The time between timer events in milliseconds. Default
+ is 1000 ms.
+ * single_shot: Boolean flag indicating whether this timer should
+ operate as single shot (run once and then stop). Defaults to False.
+ * callbacks: Stores list of (func, args) tuples that will be called
+ upon timer events. This list can be manipulated directly, or the
+ functions add_callback and remove_callback can be used.
+ '''
+ # completely implemented at the C-level (in _macosx.Timer)
+
+
+
class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasBase):
"""
The canvas the figure renders into. Calls the draw and print fig
@@ -310,7 +328,22 @@
def get_default_filetype(self):
return 'png'
+ def new_timer(self, *args, **kwargs):
+ """
+ Creates a new backend-specific subclass of :class:`backend_bases.Timer`.
+ This is useful for getting periodic events through the backend's native
+ event loop. Implemented only for backends with GUIs.
+ optional arguments:
+
+ *interval*
+ Timer interval in milliseconds
+ *callbacks*
+ Sequence of (func, args, kwargs) where func(*args, **kwargs) will
+ be executed by the timer every *interval*.
+ """
+ return TimerMac(*args, **kwargs)
+
class FigureManagerMac(_macosx.FigureManager, FigureManagerBase):
"""
Wrap everything up into a window for the pylab interface
Modified: trunk/matplotlib/src/_macosx.m
===================================================================
--- trunk/matplotlib/src/_macosx.m 2010-10-11 04:50:58 UTC (rev 8740)
+++ trunk/matplotlib/src/_macosx.m 2010-10-11 14:04:43 UTC (rev 8741)
@@ -5494,6 +5494,195 @@
return Py_True;
}
+typedef struct {
+ PyObject_HEAD
+ CFRunLoopTimerRef timer;
+} Timer;
+
+static PyObject*
+Timer_new(PyTypeObject* type, PyObject *args, PyObject *kwds)
+{
+ Timer* self = (Timer*)type->tp_alloc(type, 0);
+ if (!self) return NULL;
+ self->timer = NULL;
+ return (PyObject*) self;
+}
+
+static void
+Timer_dealloc(Timer* self)
+{
+ if (self->timer) {
+ PyObject* attribute;
+ CFRunLoopTimerContext context;
+ CFRunLoopTimerGetContext(self->timer, &context);
+ attribute = context.info;
+ Py_DECREF(attribute);
+ CFRunLoopRef runloop = CFRunLoopGetCurrent();
+ if (runloop) {
+ CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
+ }
+ CFRelease(self->timer);
+ self->timer = NULL;
+ }
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject*
+Timer_repr(Timer* self)
+{
+ return PyString_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p",
+ (void*) self, (void*)(self->timer));
+}
+
+static char Timer_doc[] =
+"A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop.\n";
+
+static void timer_callback(CFRunLoopTimerRef timer, void* info)
+{
+ PyObject* method = info;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* result = PyObject_CallFunction(method, NULL);
+ if (result==NULL) PyErr_Print();
+ PyGILState_Release(gstate);
+}
+
+static PyObject*
+Timer__timer_start(Timer* self, PyObject* args)
+{
+ CFRunLoopRef runloop;
+ CFRunLoopTimerRef timer;
+ CFRunLoopTimerContext context;
+ double milliseconds;
+ CFTimeInterval interval;
+ PyObject* attribute;
+ PyObject* failure;
+ runloop = CFRunLoopGetCurrent();
+ if (!runloop) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to obtain run loop");
+ return NULL;
+ }
+ context.version = 0;
+ context.retain = 0;
+ context.release = 0;
+ context.copyDescription = 0;
+ attribute = PyObject_GetAttrString((PyObject*)self, "_interval");
+ if (attribute==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_interval'");
+ return NULL;
+ }
+ milliseconds = PyFloat_AsDouble(attribute);
+ failure = PyErr_Occurred();
+ Py_DECREF(attribute);
+ if (failure) return NULL;
+ attribute = PyObject_GetAttrString((PyObject*)self, "_single");
+ if (attribute==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_single'");
+ return NULL;
+ }
+ switch (PyObject_IsTrue(attribute)) {
+ case 1:
+ interval = 0;
+ break;
+ case 0:
+ interval = milliseconds / 1000.0;
+ break;
+ case -1:
+ default:
+ PyErr_SetString(PyExc_ValueError, "Cannot interpret _single attribute as True of False");
+ return NULL;
+ }
+ attribute = PyObject_GetAttrString((PyObject*)self, "_on_timer");
+ if (attribute==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_on_timer'");
+ return NULL;
+ }
+ if (!PyMethod_Check(attribute)) {
+ PyErr_SetString(PyExc_RuntimeError, "_on_timer should be a Python method");
+ return NULL;
+ }
+ context.info = attribute;
+ timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
+ 0,
+ interval,
+ 0,
+ 0,
+ timer_callback,
+ &context);
+ if (!timer) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to create timer");
+ return NULL;
+ }
+ Py_INCREF(attribute);
+ if (self->timer) {
+ CFRunLoopTimerGetContext(self->timer, &context);
+ attribute = context.info;
+ Py_DECREF(attribute);
+ CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
+ CFRelease(self->timer);
+ }
+ CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes);
+ /* Don't release the timer here, since the run loop may be destroyed and
+ * the timer lost before we have a chance to decrease the reference count
+ * of the attribute */
+ self->timer = timer;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef Timer_methods[] = {
+ {"_timer_start",
+ (PyCFunction)Timer__timer_start,
+ METH_VARARGS,
+ "Initialize and start the timer."
+ },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject TimerType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_macosx.Timer", /*tp_name*/
+ sizeof(Timer), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Timer_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)Timer_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Timer_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Timer_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Timer_new, /* tp_new */
+};
+
static struct PyMethodDef methods[] = {
{"show",
(PyCFunction)show,
@@ -5528,6 +5717,7 @@
if (PyType_Ready(&FigureManagerType) < 0) return;
if (PyType_Ready(&NavigationToolbarType) < 0) return;
if (PyType_Ready(&NavigationToolbar2Type) < 0) return;
+ if (PyType_Ready(&TimerType) < 0) return;
m = Py_InitModule4("_macosx",
methods,
@@ -5540,11 +5730,13 @@
Py_INCREF(&FigureManagerType);
Py_INCREF(&NavigationToolbarType);
Py_INCREF(&NavigationToolbar2Type);
+ Py_INCREF(&TimerType);
PyModule_AddObject(m, "GraphicsContext", (PyObject*) &GraphicsContextType);
PyModule_AddObject(m, "FigureCanvas", (PyObject*) &FigureCanvasType);
PyModule_AddObject(m, "FigureManager", (PyObject*) &FigureManagerType);
PyModule_AddObject(m, "NavigationToolbar", (PyObject*) &NavigationToolbarType);
PyModule_AddObject(m, "NavigationToolbar2", (PyObject*) &NavigationToolbar2Type);
+ PyModule_AddObject(m, "Timer", (PyObject*) &TimerType);
PyOS_InputHook = wait_for_stdin;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|