@@ -1822,93 +1822,53 @@ - (void)flagsChanged:(NSEvent *)event
18221822
18231823typedef struct {
18241824 PyObject_HEAD
1825- CFRunLoopTimerRef timer;
1825+ NSTimer * timer;
1826+
18261827} Timer;
18271828
18281829static PyObject*
18291830Timer_new (PyTypeObject* type, PyObject *args, PyObject *kwds)
18301831{
18311832 lazy_init ();
18321833 Timer* self = (Timer*)type->tp_alloc (type, 0 );
1833- if (!self) { return NULL ; }
1834+ if (!self) {
1835+ return NULL ;
1836+ }
18341837 self->timer = NULL ;
18351838 return (PyObject*) self;
18361839}
18371840
18381841static PyObject*
18391842Timer_repr (Timer* self)
18401843{
1841- return PyUnicode_FromFormat (" Timer object %p wrapping CFRunLoopTimerRef %p " ,
1844+ return PyUnicode_FromFormat (" Timer object %p wrapping NSTimer %p " ,
18421845 (void *) self, (void *)(self->timer ));
18431846}
18441847
1845- static void timer_callback (CFRunLoopTimerRef timer, void * info)
1846- {
1847- gil_call_method (info, " _on_timer" );
1848- }
1849-
1850- static void context_cleanup (const void * info)
1851- {
1852- Py_DECREF ((PyObject*)info);
1853- }
1854-
18551848static PyObject*
18561849Timer__timer_start (Timer* self, PyObject* args)
18571850{
1858- CFRunLoopRef runloop;
1859- CFRunLoopTimerRef timer;
1860- CFRunLoopTimerContext context;
1861- CFAbsoluteTime firstFire;
1862- CFTimeInterval interval;
1851+ NSTimeInterval interval;
18631852 PyObject* py_interval = NULL , * py_single = NULL , * py_on_timer = NULL ;
18641853 int single;
1865- runloop = CFRunLoopGetMain ();
1866- if (!runloop) {
1867- PyErr_SetString (PyExc_RuntimeError, " Failed to obtain run loop" );
1868- return NULL ;
1869- }
18701854 if (!(py_interval = PyObject_GetAttrString ((PyObject*)self, " _interval" ))
18711855 || ((interval = PyFloat_AsDouble (py_interval) / 1000 .), PyErr_Occurred ())
18721856 || !(py_single = PyObject_GetAttrString ((PyObject*)self, " _single" ))
18731857 || ((single = PyObject_IsTrue (py_single)) == -1 )
18741858 || !(py_on_timer = PyObject_GetAttrString ((PyObject*)self, " _on_timer" ))) {
18751859 goto exit;
18761860 }
1877- // (current time + interval) is time of first fire.
1878- firstFire = CFAbsoluteTimeGetCurrent () + interval;
1879- if (single) {
1880- interval = 0 ;
1881- }
18821861 if (!PyMethod_Check (py_on_timer)) {
18831862 PyErr_SetString (PyExc_RuntimeError, " _on_timer should be a Python method" );
18841863 goto exit;
18851864 }
1886- Py_INCREF (self);
1887- context.version = 0 ;
1888- context.retain = NULL ;
1889- context.release = context_cleanup;
1890- context.copyDescription = NULL ;
1891- context.info = self;
1892- timer = CFRunLoopTimerCreate (kCFAllocatorDefault ,
1893- firstFire,
1894- interval,
1895- 0 ,
1896- 0 ,
1897- timer_callback,
1898- &context);
1899- if (!timer) {
1900- PyErr_SetString (PyExc_RuntimeError, " Failed to create timer" );
1901- goto exit;
1902- }
1903- if (self->timer ) {
1904- CFRunLoopTimerInvalidate (self->timer );
1905- CFRelease (self->timer );
1906- }
1907- CFRunLoopAddTimer (runloop, timer, kCFRunLoopCommonModes );
1908- /* Don't release the timer here, since the run loop may be destroyed and
1909- * the timer lost before we have a chance to decrease the reference count
1910- * of the attribute */
1911- self->timer = timer;
1865+
1866+ // hold a reference to the timer so we can invalidate/stop it later
1867+ self->timer = [NSTimer scheduledTimerWithTimeInterval: interval
1868+ repeats: !single
1869+ block: ^(NSTimer *timer) {
1870+ gil_call_method ((PyObject*)self, " _on_timer" );
1871+ }];
19121872exit:
19131873 Py_XDECREF (py_interval);
19141874 Py_XDECREF (py_single);
@@ -1924,8 +1884,7 @@ static void context_cleanup(const void* info)
19241884Timer__timer_stop (Timer* self)
19251885{
19261886 if (self->timer ) {
1927- CFRunLoopTimerInvalidate (self->timer );
1928- CFRelease (self->timer );
1887+ [self ->timer invalidate ];
19291888 self->timer = NULL ;
19301889 }
19311890 Py_RETURN_NONE;
@@ -1946,7 +1905,7 @@ static void context_cleanup(const void* info)
19461905 .tp_repr = (reprfunc)Timer_repr,
19471906 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
19481907 .tp_new = (newfunc)Timer_new,
1949- .tp_doc = " A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop." ,
1908+ .tp_doc = " A Timer object that contains an NSTimer that gets added to the event loop when started ." ,
19501909 .tp_methods = (PyMethodDef[]){ // All docstrings are inherited.
19511910 {" _timer_start" ,
19521911 (PyCFunction)Timer__timer_start,
0 commit comments