1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
// Copyright 2013-2015, The Rust-GNOME Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT> //! Manages available sources of events for the main loop use std::cell::RefCell; use std::ops::DerefMut; use std::mem::transmute; use ffi::{gboolean, gpointer, g_idle_add_full, g_timeout_add_full, g_timeout_add_seconds_full}; use translate::ToGlib; /// Return type of idle and timeout functions. /// /// In the callback, return `Continue(true)` to continue scheduling the callback /// in the main loop or `Continue(false)` to remove it from the main loop. pub struct Continue(pub bool); impl ToGlib for Continue { type GlibType = gboolean; #[inline] fn to_glib(&self) -> gboolean { self.0.to_glib() } } // Box::into_raw stability workaround unsafe fn into_raw<T>(b: Box<T>) -> *mut T { transmute(b) } extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean { func.borrow_mut().deref_mut()().to_glib() } unsafe extern "C" fn destroy_closure(ptr: gpointer) { // Box::from_raw API stability workaround let ptr = ptr as *mut RefCell<Box<FnMut() -> Continue + 'static>>; let _: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = transmute(ptr); } const PRIORITY_DEFAULT: i32 = 0; const PRIORITY_DEFAULT_IDLE: i32 = 200; /// Adds a function to be called whenever there are no higher priority events pending to the default main loop. /// /// The function is given the default idle priority, `PRIORITY_DEFAULT_IDLE`. /// If the function returns `Continue(false)` it is automatically removed from /// the list of event sources and will not be called again. /// /// # Examples /// /// ```ignore /// let mut i = 0; /// idle_add(move || { /// println!("Idle: {}", i); /// i += 1; /// Continue(if i <= 10 { true } else { false }) /// }); /// ``` pub fn idle_add<F>(func: F) -> u32 where F: FnMut() -> Continue + 'static { let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func))); unsafe { g_idle_add_full(PRIORITY_DEFAULT_IDLE, transmute(trampoline), into_raw(f) as gpointer, destroy_closure) } } /// Sets a function to be called at regular intervals, with the default priority, `PRIORITY_DEFAULT`. /// /// The function is called repeatedly until it returns `Continue(false)`, at which point the timeout is /// automatically destroyed and the function will not be called again. The first call to the /// function will be at the end of the first interval . /// /// Note that timeout functions may be delayed, due to the processing of other event sources. Thus /// they should not be relied on for precise timing. After each call to the timeout function, the /// time of the next timeout is recalculated based on the current time and the given interval (it /// does not try to 'catch up' time lost in delays). /// /// If you want to have a timer in the "seconds" range and do not care about the exact time of the /// first call of the timer, use the `timeout_add_seconds()` function; this function allows for more /// optimizations and more efficient system power usage. /// /// The interval given is in terms of monotonic time, not wall clock time. /// See `g_get_monotonic_time()` in glib documentation. /// /// # Examples /// /// ```ignore /// timeout_add(3000, || { /// println!("This prints once every 3 seconds"); /// Continue(true) /// }); /// ``` pub fn timeout_add<F>(interval: u32, func: F) -> u32 where F: FnMut() -> Continue + 'static { let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func))); unsafe { g_timeout_add_full(PRIORITY_DEFAULT, interval, transmute(trampoline), into_raw(f) as gpointer, destroy_closure) } } /// Sets a function to be called at regular intervals with the default priority, `PRIORITY_DEFAULT`. /// /// The function is called repeatedly until it returns `Continue(false)`, at which point the timeout /// is automatically destroyed and the function will not be called again. /// /// Note that the first call of the timer may not be precise for timeouts of one second. If you need /// finer precision and have such a timeout, you may want to use `timeout_add()` instead. /// /// The interval given is in terms of monotonic time, not wall clock time. /// See `g_get_monotonic_time()` in glib documentation. /// /// # Examples /// /// ```ignore /// timeout_add_seconds(10, || { /// println!("This prints once every 10 seconds"); /// Continue(true) /// }); /// ``` pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32 where F: FnMut() -> Continue + 'static { let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func))); unsafe { g_timeout_add_seconds_full(PRIORITY_DEFAULT, interval, transmute(trampoline), into_raw(f) as gpointer, destroy_closure) } }