blob: 24aa9a5c6aec193a4f92e28eb2060a20760fc40f [file] [log] [blame]
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_upper_case_globals)]
pub use core_foundation_sys::runloop::*;
use core_foundation_sys::base::CFIndex;
use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags};
use core_foundation_sys::string::CFStringRef;
use base::{TCFType};
use date::{CFAbsoluteTime, CFTimeInterval};
use filedescriptor::CFFileDescriptor;
use string::{CFString};
pub type CFRunLoopMode = CFStringRef;
declare_TCFType!(CFRunLoop, CFRunLoopRef);
impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID);
impl_CFTypeDescription!(CFRunLoop);
impl CFRunLoop {
pub fn get_current() -> CFRunLoop {
unsafe {
let run_loop_ref = CFRunLoopGetCurrent();
TCFType::wrap_under_get_rule(run_loop_ref)
}
}
pub fn get_main() -> CFRunLoop {
unsafe {
let run_loop_ref = CFRunLoopGetMain();
TCFType::wrap_under_get_rule(run_loop_ref)
}
}
pub fn run_current() {
unsafe {
CFRunLoopRun();
}
}
pub fn stop(&self) {
unsafe {
CFRunLoopStop(self.0);
}
}
pub fn current_mode(&self) -> Option<String> {
unsafe {
let string_ref = CFRunLoopCopyCurrentMode(self.0);
if string_ref.is_null() {
return None;
}
let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref);
Some(cf_string.to_string())
}
}
pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool {
unsafe {
CFRunLoopContainsTimer(self.0, timer.0, mode) != 0
}
}
pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) {
unsafe {
CFRunLoopAddTimer(self.0, timer.0, mode);
}
}
pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) {
unsafe {
CFRunLoopRemoveTimer(self.0, timer.0, mode);
}
}
pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool {
unsafe {
CFRunLoopContainsSource(self.0, source.0, mode) != 0
}
}
pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) {
unsafe {
CFRunLoopAddSource(self.0, source.0, mode);
}
}
pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) {
unsafe {
CFRunLoopRemoveSource(self.0, source.0, mode);
}
}
pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool {
unsafe {
CFRunLoopContainsObserver(self.0, observer.0, mode) != 0
}
}
pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) {
unsafe {
CFRunLoopAddObserver(self.0, observer.0, mode);
}
}
pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) {
unsafe {
CFRunLoopRemoveObserver(self.0, observer.0, mode);
}
}
}
declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef);
impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID);
impl CFRunLoopTimer {
pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer {
unsafe {
let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context);
TCFType::wrap_under_create_rule(timer_ref)
}
}
}
declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef);
impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID);
impl CFRunLoopSource {
pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option<CFRunLoopSource> {
fd.to_run_loop_source(order)
}
}
declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef);
impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID);
#[cfg(test)]
mod test {
use super::*;
use date::{CFDate, CFAbsoluteTime};
use std::mem;
use std::os::raw::c_void;
use std::sync::mpsc;
#[test]
fn wait_200_milliseconds() {
let run_loop = CFRunLoop::get_current();
let now = CFDate::now().abs_time();
let (elapsed_tx, elapsed_rx) = mpsc::channel();
let mut info = Info {
start_time: now,
elapsed_tx,
};
let mut context = unsafe { CFRunLoopTimerContext {
version: 0,
info: &mut info as *mut _ as *mut c_void,
retain: mem::zeroed(),
release: mem::zeroed(),
copyDescription: mem::zeroed(),
} };
let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context);
unsafe {
run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode);
}
CFRunLoop::run_current();
let elapsed = elapsed_rx.try_recv().unwrap();
println!("wait_200_milliseconds, elapsed: {}", elapsed);
assert!(elapsed > 0.19 && elapsed < 0.30);
}
struct Info {
start_time: CFAbsoluteTime,
elapsed_tx: mpsc::Sender<f64>,
}
extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void) {
let info: *mut Info = unsafe { mem::transmute(raw_info) };
let now = CFDate::now().abs_time();
let elapsed = now - unsafe { (*info).start_time };
let _ = unsafe { (*info).elapsed_tx.send(elapsed) };
CFRunLoop::get_current().stop();
}
}