1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 05:42:03 +03:00

basic timer list for x11 in software front end

This commit is contained in:
Wez Furlong 2019-09-24 09:29:28 -07:00
parent 67d6e7fd1a
commit 3a49b79ec6

View File

@ -8,12 +8,81 @@ use mio::unix::EventedFd;
use mio::{Evented, Events, Poll, PollOpt, Ready, Token};
use promise::BasicExecutor;
use std::cell::RefCell;
use std::collections::HashMap;
use std::cmp::Ordering;
use std::collections::{HashMap, VecDeque};
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use xcb_util::ffi::keysyms::{xcb_key_symbols_alloc, xcb_key_symbols_free, xcb_key_symbols_t};
struct TimerEntry {
callback: Box<dyn FnMut()>,
due: Instant,
interval: Duration,
}
#[derive(Default)]
struct TimerList {
timers: VecDeque<TimerEntry>,
}
impl TimerList {
pub fn new() -> Self {
Default::default()
}
fn find_index_after(&self, due: &Instant) -> usize {
for (idx, entry) in self.timers.iter().enumerate() {
if entry.due.cmp(due) == Ordering::Greater {
return idx;
}
}
self.timers.len()
}
pub fn insert(&mut self, mut entry: TimerEntry) {
entry.due = Instant::now() + entry.interval;
let idx = self.find_index_after(&entry.due);
self.timers.insert(idx, entry);
}
pub fn time_until_due(&self, now: Instant) -> Option<Duration> {
self.timers.front().map(|entry| {
if entry.due <= now {
Duration::from_secs(0)
} else {
entry.due - now
}
})
}
fn first_is_ready(&self, now: Instant) -> bool {
if let Some(first) = self.timers.front() {
if first.due > now {
false
} else {
true
}
} else {
false
}
}
pub fn run_ready(&mut self) {
let now = Instant::now();
let mut requeue = vec![];
while self.first_is_ready(now) {
let mut first = self.timers.pop_front().expect("first_is_ready");
(first.callback)();
requeue.push(first);
}
for entry in requeue.into_iter() {
self.insert(entry);
}
}
}
pub struct Connection {
pub display: *mut x11::xlib::Display,
conn: xcb::Connection,
@ -32,6 +101,7 @@ pub struct Connection {
should_terminate: RefCell<bool>,
pub(crate) shm_available: bool,
tasks: Tasks,
timers: RefCell<TimerList>,
}
impl std::ops::Deref for Connection {
@ -179,6 +249,8 @@ impl ConnectionOps for Connection {
let mut last_interval = Instant::now();
while !*self.should_terminate.borrow() {
self.timers.borrow_mut().run_ready();
let now = Instant::now();
let diff = now - last_interval;
let period = if diff >= paint_interval {
@ -196,6 +268,13 @@ impl ConnectionOps for Connection {
// relied solely on that.
self.process_queued_xcb()?;
let period = self
.timers
.borrow()
.time_until_due(Instant::now())
.map(|duration| duration.min(period))
.unwrap_or(period);
match poll.poll(&mut events, Some(period)) {
Ok(_) => {
for event in &events {
@ -218,6 +297,14 @@ impl ConnectionOps for Connection {
Ok(())
}
fn schedule_timer<F: FnMut() + 'static>(&self, interval: std::time::Duration, callback: F) {
self.timers.borrow_mut().insert(TimerEntry {
callback: Box::new(callback),
due: Instant::now(),
interval,
});
}
}
impl Connection {
@ -335,6 +422,7 @@ impl Connection {
should_terminate: RefCell::new(false),
shm_available,
tasks: Default::default(),
timers: RefCell::new(TimerList::new()),
};
Ok(conn)