@@ -1811,93 +1811,53 @@ - (void)flagsChanged:(NSEvent *)event
18111811
18121812typedef struct {
18131813 PyObject_HEAD
1814- CFRunLoopTimerRef timer;
1814+ NSTimer * timer;
1815+
18151816} Timer;
18161817
18171818static PyObject*
18181819Timer_new (PyTypeObject* type, PyObject *args, PyObject *kwds)
18191820{
18201821 lazy_init ();
18211822 Timer* self = (Timer*)type->tp_alloc (type, 0 );
1822- if (!self) { return NULL ; }
1823+ if (!self) {
1824+ return NULL ;
1825+ }
18231826 self->timer = NULL ;
18241827 return (PyObject*) self;
18251828}
18261829
18271830static PyObject*
18281831Timer_repr (Timer* self)
18291832{
1830- return PyUnicode_FromFormat (" Timer object %p wrapping CFRunLoopTimerRef %p " ,
1833+ return PyUnicode_FromFormat (" Timer object %p wrapping NSTimer %p " ,
18311834 (void *) self, (void *)(self->timer ));
18321835}
18331836
1834- static void timer_callback (CFRunLoopTimerRef timer, void * info)
1835- {
1836- gil_call_method (info, " _on_timer" );
1837- }
1838-
1839- static void context_cleanup (const void * info)
1840- {
1841- Py_DECREF ((PyObject*)info);
1842- }
1843-
18441837static PyObject*
18451838Timer__timer_start (Timer* self, PyObject* args)
18461839{
1847- CFRunLoopRef runloop;
1848- CFRunLoopTimerRef timer;
1849- CFRunLoopTimerContext context;
1850- CFAbsoluteTime firstFire;
1851- CFTimeInterval interval;
1840+ NSTimeInterval interval;
18521841 PyObject* py_interval = NULL , * py_single = NULL , * py_on_timer = NULL ;
18531842 int single;
1854- runloop = CFRunLoopGetMain ();
1855- if (!runloop) {
1856- PyErr_SetString (PyExc_RuntimeError, " Failed to obtain run loop" );
1857- return NULL ;
1858- }
18591843 if (!(py_interval = PyObject_GetAttrString ((PyObject*)self, " _interval" ))
18601844 || ((interval = PyFloat_AsDouble (py_interval) / 1000 .), PyErr_Occurred ())
18611845 || !(py_single = PyObject_GetAttrString ((PyObject*)self, " _single" ))
18621846 || ((single = PyObject_IsTrue (py_single)) == -1 )
18631847 || !(py_on_timer = PyObject_GetAttrString ((PyObject*)self, " _on_timer" ))) {
18641848 goto exit;
18651849 }
1866- // (current time + interval) is time of first fire.
1867- firstFire = CFAbsoluteTimeGetCurrent () + interval;
1868- if (single) {
1869- interval = 0 ;
1870- }
18711850 if (!PyMethod_Check (py_on_timer)) {
18721851 PyErr_SetString (PyExc_RuntimeError, " _on_timer should be a Python method" );
18731852 goto exit;
18741853 }
1875- Py_INCREF (self);
1876- context.version = 0 ;
1877- context.retain = NULL ;
1878- context.release = context_cleanup;
1879- context.copyDescription = NULL ;
1880- context.info = self;
1881- timer = CFRunLoopTimerCreate (kCFAllocatorDefault ,
1882- firstFire,
1883- interval,
1884- 0 ,
1885- 0 ,
1886- timer_callback,
1887- &context);
1888- if (!timer) {
1889- PyErr_SetString (PyExc_RuntimeError, " Failed to create timer" );
1890- goto exit;
1891- }
1892- if (self->timer ) {
1893- CFRunLoopTimerInvalidate (self->timer );
1894- CFRelease (self->timer );
1895- }
1896- CFRunLoopAddTimer (runloop, timer, kCFRunLoopCommonModes );
1897- /* Don't release the timer here, since the run loop may be destroyed and
1898- * the timer lost before we have a chance to decrease the reference count
1899- * of the attribute */
1900- self->timer = timer;
1854+
1855+ // hold a reference to the timer so we can invalidate/stop it later
1856+ self->timer = [NSTimer scheduledTimerWithTimeInterval: interval
1857+ repeats: !single
1858+ block: ^(NSTimer *timer) {
1859+ gil_call_method ((PyObject*)self, " _on_timer" );
1860+ }];
19011861exit:
19021862 Py_XDECREF (py_interval);
19031863 Py_XDECREF (py_single);
@@ -1913,8 +1873,7 @@ static void context_cleanup(const void* info)
19131873Timer__timer_stop (Timer* self)
19141874{
19151875 if (self->timer ) {
1916- CFRunLoopTimerInvalidate (self->timer );
1917- CFRelease (self->timer );
1876+ [self ->timer invalidate ];
19181877 self->timer = NULL ;
19191878 }
19201879 Py_RETURN_NONE;
@@ -1935,7 +1894,7 @@ static void context_cleanup(const void* info)
19351894 .tp_repr = (reprfunc)Timer_repr,
19361895 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
19371896 .tp_new = (newfunc)Timer_new,
1938- .tp_doc = " A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop." ,
1897+ .tp_doc = " A Timer object that contains an NSTimer that gets added to the event loop when started ." ,
19391898 .tp_methods = (PyMethodDef[]){ // All docstrings are inherited.
19401899 {" _timer_start" ,
19411900 (PyCFunction)Timer__timer_start,
0 commit comments