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.

------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to