1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

provide a more targeted channel for wakeups

This allows using the mio poll timer as the signal for drawing
frames, rather than always drawing them after each byte is read
from the pty.   We're using 50ms as the frame interval at the moment.
This commit is contained in:
Wez Furlong 2018-02-22 01:44:07 -08:00
parent f6a95aafcf
commit 79ebf717e8
4 changed files with 76 additions and 19 deletions

View File

@ -13,12 +13,14 @@ use std::io::{Read, Write};
use std::process::Child;
use std::process::Command;
use std::rc::Rc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError;
use term::{self, Terminal};
use term::{MouseButton, MouseEventKind};
use term::KeyCode;
use term::KeyModifiers;
use term::hyperlink::Hyperlink;
use wakeup::WakeupMsg;
struct Host {
display: glium::Display,
@ -62,11 +64,13 @@ pub struct TerminalWindow {
terminal: Terminal,
process: Child,
last_mouse_coords: (f64, f64),
wakeup_receiver: Receiver<WakeupMsg>,
}
impl TerminalWindow {
pub fn new(
event_loop: &glutin::EventsLoop,
wakeup_receiver: Receiver<WakeupMsg>,
width: u16,
height: u16,
terminal: Terminal,
@ -116,6 +120,7 @@ impl TerminalWindow {
terminal,
process,
last_mouse_coords: (0.0, 0.0),
wakeup_receiver,
})
}
@ -439,8 +444,19 @@ impl TerminalWindow {
Err(TryRecvError::Disconnected) => bail!("clipboard thread died"),
}
self.try_read_pty()?;
self.test_for_child_exit()?;
loop {
match self.wakeup_receiver.try_recv() {
Ok(WakeupMsg::PtyReadable) => self.try_read_pty()?,
Ok(WakeupMsg::SigChld) => self.test_for_child_exit()?,
Ok(WakeupMsg::Paint) => if self.terminal.has_dirty_lines() {
self.paint()?;
},
Err(_) => break,
}
}
}
Event::Suspended(suspended) => {
eprintln!("Suspended {:?}", suspended);
}
_ => {}
}

View File

@ -38,12 +38,15 @@ use std::os::unix::io::AsRawFd;
use std::process::Command;
use std::str;
use std::thread;
use std::time::Duration;
mod config;
mod opengl;
mod clipboard;
mod wakeup;
use wakeup::{Wakeup, WakeupMsg};
mod gliumwindows;
mod font;
@ -81,12 +84,15 @@ fn run_glium(
initial_pixel_height: u16,
) -> Result<(), Error> {
let mut events_loop = glium::glutin::EventsLoop::new();
sigchld::activate(events_loop.create_proxy())?;
let (wakeup_receiver, wakeup) = Wakeup::new(events_loop.create_proxy());
sigchld::activate(wakeup.clone())?;
let master_fd = master.as_raw_fd();
let mut window = gliumwindows::TerminalWindow::new(
&events_loop,
wakeup_receiver,
initial_pixel_width,
initial_pixel_height,
terminal,
@ -100,7 +106,7 @@ fn run_glium(
)?;
{
let proxy = events_loop.create_proxy();
let mut wakeup = wakeup.clone();
thread::spawn(move || {
let poll = Poll::new().expect("mio Poll failed to init");
poll.register(
@ -112,12 +118,24 @@ fn run_glium(
let mut events = Events::with_capacity(8);
loop {
match poll.poll(&mut events, None) {
Ok(_) => for event in &events {
match poll.poll(&mut events, Some(Duration::from_millis(50))) {
Ok(n) if n > 0 => for event in &events {
if event.token() == Token(0) && event.readiness().is_readable() {
proxy.wakeup().expect("failed to wake event loop");
wakeup
.send(WakeupMsg::PtyReadable)
.expect("failed to wakeup gui thread");
}
},
Ok(_) => {
// Tick and wakeup the gui thread to ask it to render
// if needed. Without this we'd only repaint when
// the window system decides that we were damaged.
// We don't want to paint after every state change
// as that would be too frequent.
wakeup
.send(WakeupMsg::Paint)
.expect("failed to wakeup gui thread");
}
_ => {}
}
}
@ -125,12 +143,7 @@ fn run_glium(
}
events_loop.run_forever(|event| match window.dispatch_event(event) {
Ok(_) => {
if window.need_paint() {
window.paint().expect("paint failed");
}
glium::glutin::ControlFlow::Continue
}
Ok(_) => glium::glutin::ControlFlow::Continue,
Err(err) => {
eprintln!("{:?}", err);
glium::glutin::ControlFlow::Break

View File

@ -1,28 +1,28 @@
//! Helper for detecting SIGCHLD
use failure::Error;
use glium::glutin::EventsLoopProxy;
use libc;
use std::io;
use std::mem;
use std::ptr;
use wakeup::{Wakeup, WakeupMsg};
static mut EVENT_LOOP: Option<EventsLoopProxy> = None;
static mut EVENT_LOOP: Option<Wakeup> = None;
extern "C" fn chld_handler(_signo: libc::c_int, _si: *const libc::siginfo_t, _: *const u8) {
unsafe {
match EVENT_LOOP.as_mut() {
Some(proxy) => {
proxy.wakeup().ok();
Some(wakeup) => {
wakeup.send(WakeupMsg::SigChld).ok();
}
None => (),
}
}
}
pub fn activate(proxy: EventsLoopProxy) -> Result<(), Error> {
pub fn activate(wakeup: Wakeup) -> Result<(), Error> {
unsafe {
EVENT_LOOP = Some(proxy);
EVENT_LOOP = Some(wakeup);
let mut sa: libc::sigaction = mem::zeroed();
sa.sa_sigaction = chld_handler as usize;

28
src/wakeup.rs Normal file
View File

@ -0,0 +1,28 @@
use failure::Error;
use glium::glutin::EventsLoopProxy;
use std::sync::mpsc::{channel, Receiver, Sender};
#[derive(Debug)]
pub enum WakeupMsg {
PtyReadable,
SigChld,
Paint,
}
#[derive(Clone)]
pub struct Wakeup {
sender: Sender<WakeupMsg>,
proxy: EventsLoopProxy,
}
impl Wakeup {
pub fn new(proxy: EventsLoopProxy) -> (Receiver<WakeupMsg>, Self) {
let (sender, receiver) = channel();
(receiver, Self { sender, proxy })
}
pub fn send(&mut self, what: WakeupMsg) -> Result<(), Error> {
self.sender.send(what)?;
self.proxy.wakeup()?;
Ok(())
}
}