@@ -5494,6 +5494,195 @@ - (int)index
5494
5494
return Py_True;
5495
5495
}
5496
5496
5497
+ typedef struct {
5498
+ PyObject_HEAD
5499
+ CFRunLoopTimerRef timer;
5500
+ } Timer;
5501
+
5502
+ static PyObject*
5503
+ Timer_new (PyTypeObject* type, PyObject *args, PyObject *kwds)
5504
+ {
5505
+ Timer* self = (Timer*)type->tp_alloc (type, 0 );
5506
+ if (!self) return NULL ;
5507
+ self->timer = NULL ;
5508
+ return (PyObject*) self;
5509
+ }
5510
+
5511
+ static void
5512
+ Timer_dealloc (Timer* self)
5513
+ {
5514
+ if (self->timer ) {
5515
+ PyObject* attribute;
5516
+ CFRunLoopTimerContext context;
5517
+ CFRunLoopTimerGetContext (self->timer , &context);
5518
+ attribute = context.info ;
5519
+ Py_DECREF (attribute);
5520
+ CFRunLoopRef runloop = CFRunLoopGetCurrent ();
5521
+ if (runloop) {
5522
+ CFRunLoopRemoveTimer (runloop, self->timer , kCFRunLoopCommonModes );
5523
+ }
5524
+ CFRelease (self->timer );
5525
+ self->timer = NULL ;
5526
+ }
5527
+ self->ob_type ->tp_free ((PyObject*)self);
5528
+ }
5529
+
5530
+ static PyObject*
5531
+ Timer_repr (Timer* self)
5532
+ {
5533
+ return PyString_FromFormat (" Timer object %p wrapping CFRunLoopTimerRef %p " ,
5534
+ (void *) self, (void *)(self->timer ));
5535
+ }
5536
+
5537
+ static char Timer_doc[] =
5538
+ " A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop.\n " ;
5539
+
5540
+ static void timer_callback (CFRunLoopTimerRef timer, void * info)
5541
+ {
5542
+ PyObject* method = info;
5543
+ PyGILState_STATE gstate = PyGILState_Ensure ();
5544
+ PyObject* result = PyObject_CallFunction (method, NULL );
5545
+ if (result==NULL ) PyErr_Print ();
5546
+ PyGILState_Release (gstate);
5547
+ }
5548
+
5549
+ static PyObject*
5550
+ Timer__timer_start (Timer* self, PyObject* args)
5551
+ {
5552
+ CFRunLoopRef runloop;
5553
+ CFRunLoopTimerRef timer;
5554
+ CFRunLoopTimerContext context;
5555
+ double milliseconds;
5556
+ CFTimeInterval interval;
5557
+ PyObject* attribute;
5558
+ PyObject* failure;
5559
+ runloop = CFRunLoopGetCurrent ();
5560
+ if (!runloop) {
5561
+ PyErr_SetString (PyExc_RuntimeError, " Failed to obtain run loop" );
5562
+ return NULL ;
5563
+ }
5564
+ context.version = 0 ;
5565
+ context.retain = 0 ;
5566
+ context.release = 0 ;
5567
+ context.copyDescription = 0 ;
5568
+ attribute = PyObject_GetAttrString ((PyObject*)self, " _interval" );
5569
+ if (attribute==NULL )
5570
+ {
5571
+ PyErr_SetString (PyExc_AttributeError, " Timer has no attribute '_interval'" );
5572
+ return NULL ;
5573
+ }
5574
+ milliseconds = PyFloat_AsDouble (attribute);
5575
+ failure = PyErr_Occurred ();
5576
+ Py_DECREF (attribute);
5577
+ if (failure) return NULL ;
5578
+ attribute = PyObject_GetAttrString ((PyObject*)self, " _single" );
5579
+ if (attribute==NULL )
5580
+ {
5581
+ PyErr_SetString (PyExc_AttributeError, " Timer has no attribute '_single'" );
5582
+ return NULL ;
5583
+ }
5584
+ switch (PyObject_IsTrue (attribute)) {
5585
+ case 1 :
5586
+ interval = 0 ;
5587
+ break ;
5588
+ case 0 :
5589
+ interval = milliseconds / 1000.0 ;
5590
+ break ;
5591
+ case -1 :
5592
+ default :
5593
+ PyErr_SetString (PyExc_ValueError, " Cannot interpret _single attribute as True of False" );
5594
+ return NULL ;
5595
+ }
5596
+ attribute = PyObject_GetAttrString ((PyObject*)self, " _on_timer" );
5597
+ if (attribute==NULL )
5598
+ {
5599
+ PyErr_SetString (PyExc_AttributeError, " Timer has no attribute '_on_timer'" );
5600
+ return NULL ;
5601
+ }
5602
+ if (!PyMethod_Check (attribute)) {
5603
+ PyErr_SetString (PyExc_RuntimeError, " _on_timer should be a Python method" );
5604
+ return NULL ;
5605
+ }
5606
+ context.info = attribute;
5607
+ timer = CFRunLoopTimerCreate (kCFAllocatorDefault ,
5608
+ 0 ,
5609
+ interval,
5610
+ 0 ,
5611
+ 0 ,
5612
+ timer_callback,
5613
+ &context);
5614
+ if (!timer) {
5615
+ PyErr_SetString (PyExc_RuntimeError, " Failed to create timer" );
5616
+ return NULL ;
5617
+ }
5618
+ Py_INCREF (attribute);
5619
+ if (self->timer ) {
5620
+ CFRunLoopTimerGetContext (self->timer , &context);
5621
+ attribute = context.info ;
5622
+ Py_DECREF (attribute);
5623
+ CFRunLoopRemoveTimer (runloop, self->timer , kCFRunLoopCommonModes );
5624
+ CFRelease (self->timer );
5625
+ }
5626
+ CFRunLoopAddTimer (runloop, timer, kCFRunLoopCommonModes );
5627
+ /* Don't release the timer here, since the run loop may be destroyed and
5628
+ * the timer lost before we have a chance to decrease the reference count
5629
+ * of the attribute */
5630
+ self->timer = timer;
5631
+ Py_INCREF (Py_None);
5632
+ return Py_None;
5633
+ }
5634
+
5635
+ static PyMethodDef Timer_methods[] = {
5636
+ {" _timer_start" ,
5637
+ (PyCFunction)Timer__timer_start,
5638
+ METH_VARARGS,
5639
+ " Initialize and start the timer."
5640
+ },
5641
+ {NULL } /* Sentinel */
5642
+ };
5643
+
5644
+ static PyTypeObject TimerType = {
5645
+ PyObject_HEAD_INIT (NULL )
5646
+ 0 , /* ob_size*/
5647
+ " _macosx.Timer" , /* tp_name*/
5648
+ sizeof (Timer), /* tp_basicsize*/
5649
+ 0 , /* tp_itemsize*/
5650
+ (destructor)Timer_dealloc, /* tp_dealloc*/
5651
+ 0 , /* tp_print*/
5652
+ 0 , /* tp_getattr*/
5653
+ 0 , /* tp_setattr*/
5654
+ 0 , /* tp_compare*/
5655
+ (reprfunc)Timer_repr, /* tp_repr*/
5656
+ 0 , /* tp_as_number*/
5657
+ 0 , /* tp_as_sequence*/
5658
+ 0 , /* tp_as_mapping*/
5659
+ 0 , /* tp_hash */
5660
+ 0 , /* tp_call*/
5661
+ 0 , /* tp_str*/
5662
+ 0 , /* tp_getattro*/
5663
+ 0 , /* tp_setattro*/
5664
+ 0 , /* tp_as_buffer*/
5665
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/
5666
+ Timer_doc, /* tp_doc */
5667
+ 0 , /* tp_traverse */
5668
+ 0 , /* tp_clear */
5669
+ 0 , /* tp_richcompare */
5670
+ 0 , /* tp_weaklistoffset */
5671
+ 0 , /* tp_iter */
5672
+ 0 , /* tp_iternext */
5673
+ Timer_methods, /* tp_methods */
5674
+ 0 , /* tp_members */
5675
+ 0 , /* tp_getset */
5676
+ 0 , /* tp_base */
5677
+ 0 , /* tp_dict */
5678
+ 0 , /* tp_descr_get */
5679
+ 0 , /* tp_descr_set */
5680
+ 0 , /* tp_dictoffset */
5681
+ 0 , /* tp_init */
5682
+ 0 , /* tp_alloc */
5683
+ Timer_new, /* tp_new */
5684
+ };
5685
+
5497
5686
static struct PyMethodDef methods[] = {
5498
5687
{" show" ,
5499
5688
(PyCFunction)show,
@@ -5528,6 +5717,7 @@ void init_macosx(void)
5528
5717
if (PyType_Ready (&FigureManagerType) < 0 ) return ;
5529
5718
if (PyType_Ready (&NavigationToolbarType) < 0 ) return ;
5530
5719
if (PyType_Ready (&NavigationToolbar2Type) < 0 ) return ;
5720
+ if (PyType_Ready (&TimerType) < 0 ) return ;
5531
5721
5532
5722
m = Py_InitModule4 (" _macosx" ,
5533
5723
methods,
@@ -5540,11 +5730,13 @@ void init_macosx(void)
5540
5730
Py_INCREF (&FigureManagerType);
5541
5731
Py_INCREF (&NavigationToolbarType);
5542
5732
Py_INCREF (&NavigationToolbar2Type);
5733
+ Py_INCREF (&TimerType);
5543
5734
PyModule_AddObject (m, " GraphicsContext" , (PyObject*) &GraphicsContextType);
5544
5735
PyModule_AddObject (m, " FigureCanvas" , (PyObject*) &FigureCanvasType);
5545
5736
PyModule_AddObject (m, " FigureManager" , (PyObject*) &FigureManagerType);
5546
5737
PyModule_AddObject (m, " NavigationToolbar" , (PyObject*) &NavigationToolbarType);
5547
5738
PyModule_AddObject (m, " NavigationToolbar2" , (PyObject*) &NavigationToolbar2Type);
5739
+ PyModule_AddObject (m, " Timer" , (PyObject*) &TimerType);
5548
5740
5549
5741
PyOS_InputHook = wait_for_stdin;
5550
5742
}
0 commit comments