1 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 // file at the top-level directory of this distribution. 3 // 4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 7 // option. This file may not be copied, modified, or distributed 8 // except according to those terms. 9 10 #![allow(non_upper_case_globals)] 11 12 pub use core_foundation_sys::runloop::*; 13 use core_foundation_sys::base::CFIndex; 14 use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; 15 use core_foundation_sys::string::CFStringRef; 16 17 use base::{TCFType}; 18 use date::{CFAbsoluteTime, CFTimeInterval}; 19 use filedescriptor::CFFileDescriptor; 20 use string::{CFString}; 21 22 pub type CFRunLoopMode = CFStringRef; 23 24 25 declare_TCFType!(CFRunLoop, CFRunLoopRef); 26 impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); 27 impl_CFTypeDescription!(CFRunLoop); 28 29 impl CFRunLoop { get_current() -> CFRunLoop30 pub fn get_current() -> CFRunLoop { 31 unsafe { 32 let run_loop_ref = CFRunLoopGetCurrent(); 33 TCFType::wrap_under_get_rule(run_loop_ref) 34 } 35 } 36 get_main() -> CFRunLoop37 pub fn get_main() -> CFRunLoop { 38 unsafe { 39 let run_loop_ref = CFRunLoopGetMain(); 40 TCFType::wrap_under_get_rule(run_loop_ref) 41 } 42 } 43 run_current()44 pub fn run_current() { 45 unsafe { 46 CFRunLoopRun(); 47 } 48 } 49 stop(&self)50 pub fn stop(&self) { 51 unsafe { 52 CFRunLoopStop(self.0); 53 } 54 } 55 current_mode(&self) -> Option<String>56 pub fn current_mode(&self) -> Option<String> { 57 unsafe { 58 let string_ref = CFRunLoopCopyCurrentMode(self.0); 59 if string_ref.is_null() { 60 return None; 61 } 62 63 let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref); 64 Some(cf_string.to_string()) 65 } 66 } 67 contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool68 pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool { 69 unsafe { 70 CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 71 } 72 } 73 add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode)74 pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { 75 unsafe { 76 CFRunLoopAddTimer(self.0, timer.0, mode); 77 } 78 } 79 remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode)80 pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { 81 unsafe { 82 CFRunLoopRemoveTimer(self.0, timer.0, mode); 83 } 84 } 85 contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool86 pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool { 87 unsafe { 88 CFRunLoopContainsSource(self.0, source.0, mode) != 0 89 } 90 } 91 add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode)92 pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { 93 unsafe { 94 CFRunLoopAddSource(self.0, source.0, mode); 95 } 96 } 97 remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode)98 pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { 99 unsafe { 100 CFRunLoopRemoveSource(self.0, source.0, mode); 101 } 102 } 103 contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool104 pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool { 105 unsafe { 106 CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 107 } 108 } 109 add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode)110 pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { 111 unsafe { 112 CFRunLoopAddObserver(self.0, observer.0, mode); 113 } 114 } 115 remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode)116 pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { 117 unsafe { 118 CFRunLoopRemoveObserver(self.0, observer.0, mode); 119 } 120 } 121 122 } 123 124 125 declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef); 126 impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); 127 128 impl CFRunLoopTimer { new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer129 pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { 130 unsafe { 131 let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context); 132 TCFType::wrap_under_create_rule(timer_ref) 133 } 134 } 135 } 136 137 138 declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef); 139 impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); 140 141 impl CFRunLoopSource { from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option<CFRunLoopSource>142 pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option<CFRunLoopSource> { 143 fd.to_run_loop_source(order) 144 } 145 } 146 147 declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef); 148 impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID); 149 150 #[cfg(test)] 151 mod test { 152 use super::*; 153 use date::{CFDate, CFAbsoluteTime}; 154 use std::mem; 155 use std::os::raw::c_void; 156 use std::sync::mpsc; 157 158 #[test] wait_200_milliseconds()159 fn wait_200_milliseconds() { 160 let run_loop = CFRunLoop::get_current(); 161 162 let now = CFDate::now().abs_time(); 163 let (elapsed_tx, elapsed_rx) = mpsc::channel(); 164 let mut info = Info { 165 start_time: now, 166 elapsed_tx, 167 }; 168 let mut context = CFRunLoopTimerContext { 169 version: 0, 170 info: &mut info as *mut _ as *mut c_void, 171 retain: None, 172 release: None, 173 copyDescription: None, 174 }; 175 176 let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); 177 unsafe { 178 run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); 179 } 180 CFRunLoop::run_current(); 181 let elapsed = elapsed_rx.try_recv().unwrap(); 182 println!("wait_200_milliseconds, elapsed: {}", elapsed); 183 assert!(elapsed > 0.19 && elapsed < 0.30); 184 } 185 186 struct Info { 187 start_time: CFAbsoluteTime, 188 elapsed_tx: mpsc::Sender<f64>, 189 } 190 timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void)191 extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void) { 192 let info: *mut Info = unsafe { mem::transmute(raw_info) }; 193 let now = CFDate::now().abs_time(); 194 let elapsed = now - unsafe { (*info).start_time }; 195 let _ = unsafe { (*info).elapsed_tx.send(elapsed) }; 196 CFRunLoop::get_current().stop(); 197 } 198 } 199