1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-26 14:54:16 +03:00

refactor event loop into its own struct

This commit is contained in:
Wez Furlong 2018-03-02 08:53:38 -08:00
parent 377135a71c
commit a8d2472d29
2 changed files with 155 additions and 100 deletions

View File

@ -11,6 +11,7 @@ use opengl::textureatlas::OutOfTextureSpace;
use pty::MasterPty;
use std::io;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, RawFd};
use std::process::{Child, Command, ExitStatus};
use std::rc::Rc;
use term::{self, Terminal};
@ -143,6 +144,10 @@ impl TerminalWindow {
self.host.display.gl_window().id()
}
pub fn pty_fd(&self) -> RawFd {
self.host.pty.as_raw_fd()
}
pub fn paint(&mut self) -> Result<(), Error> {
let mut target = self.host.display.draw();
let res = self.renderer.paint(&mut target, &mut self.terminal);

View File

@ -38,16 +38,16 @@ extern crate xcb_util;
use glium::glutin::WindowId;
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio::unix::EventedFd;
use mio_extras::channel::{channel as mio_channel, Receiver as MioReceiver};
use mio_extras::channel::{channel as mio_channel, Receiver as MioReceiver, Sender as MioSender};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::env;
use std::ffi::CStr;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::process::Command;
use std::str;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::thread::{self, JoinHandle};
use std::time::{Duration, Instant};
mod config;
@ -161,64 +161,63 @@ fn run_pty_thread(mut wakeup: Wakeup, receiver: MioReceiver<PtyMsg>) -> Result<(
}
}
fn start_pty_thread(wakeup: Wakeup, receiver: MioReceiver<PtyMsg>) -> std::thread::JoinHandle<()> {
fn start_pty_thread(wakeup: Wakeup, receiver: MioReceiver<PtyMsg>) -> JoinHandle<()> {
thread::spawn(move || match run_pty_thread(wakeup, receiver) {
Ok(_) => {}
Err(err) => eprintln!("pty thread returned error {:?}", err),
})
}
fn run_glium(
master: pty::MasterPty,
child: std::process::Child,
config: config::Config,
fontconfig: FontConfiguration,
terminal: term::Terminal,
initial_pixel_width: u16,
initial_pixel_height: u16,
) -> Result<(), Error> {
let mut events_loop = glium::glutin::EventsLoop::new();
struct GuiEventLoop {
event_loop: RefCell<glium::glutin::EventsLoop>,
windows_by_id: RefCell<HashMap<WindowId, gliumwindows::TerminalWindow>>,
wakeup_receiver: std::sync::mpsc::Receiver<WakeupMsg>,
wakeup: Wakeup,
pty_sender: MioSender<PtyMsg>,
pty_thread: Option<JoinHandle<()>>,
}
let mut windows_by_id = HashMap::new();
let (wakeup_receiver, wakeup) = Wakeup::new(events_loop.create_proxy());
impl GuiEventLoop {
fn new() -> Result<Self, Error> {
let event_loop = glium::glutin::EventsLoop::new();
let (wakeup_receiver, wakeup) = Wakeup::new(event_loop.create_proxy());
sigchld::activate(wakeup.clone())?;
let (pty_sender, pty_receiver) = mio_channel();
let pty_thread = start_pty_thread(wakeup.clone(), pty_receiver);
let master_fd = master.as_raw_fd();
let window = gliumwindows::TerminalWindow::new(
&events_loop,
wakeup.clone(),
initial_pixel_width,
initial_pixel_height,
terminal,
master,
child,
fontconfig,
config
.colors
.map(|p| p.into())
.unwrap_or_else(term::color::ColorPalette::default),
)?;
Ok(Self {
event_loop: RefCell::new(event_loop),
wakeup_receiver,
wakeup,
windows_by_id: RefCell::new(HashMap::new()),
pty_sender,
pty_thread: Some(pty_thread),
})
}
fn add_window(&self, window: gliumwindows::TerminalWindow) -> Result<(), Error> {
let window_id = window.window_id();
let fd = window.pty_fd();
self.windows_by_id.borrow_mut().insert(window_id, window);
self.pty_sender.send(PtyMsg::AddPty(window_id, fd))?;
Ok(())
}
windows_by_id.insert(window_id, window);
pty_sender.send(PtyMsg::AddPty(window_id, master_fd))?;
events_loop.run_forever(|event| {
fn run(&self) -> Result<(), Error> {
let mut event_loop = self.event_loop.borrow_mut();
event_loop.run_forever(|event| {
use glium::glutin::ControlFlow::{Break, Continue};
use glium::glutin::Event;
let mut dead_windows = HashSet::new();
let result = match event {
Event::WindowEvent { window_id, .. } => match windows_by_id.get_mut(&window_id) {
Event::WindowEvent { window_id, .. } => {
match self.windows_by_id.borrow_mut().get_mut(&window_id) {
Some(window) => match window.dispatch_event(event) {
Ok(_) => Continue,
Err(err) => match err.downcast_ref::<gliumwindows::SessionTerminated>() {
Err(err) => match err.downcast_ref::<gliumwindows::SessionTerminated>()
{
Some(_) => {
dead_windows.insert(window_id.clone());
Continue
@ -234,13 +233,18 @@ fn run_glium(
// eprintln!("window event for unknown {:?}", window_id);
Continue
}
},
Event::Awakened => loop {
match wakeup_receiver.try_recv() {
Ok(WakeupMsg::PtyReadable(window_id)) => {
windows_by_id.get_mut(&window_id).map(|w| w.try_read_pty());
}
Ok(WakeupMsg::SigChld) => for (window_id, window) in windows_by_id.iter_mut() {
}
Event::Awakened => loop {
match self.wakeup_receiver.try_recv() {
Ok(WakeupMsg::PtyReadable(window_id)) => {
self.windows_by_id
.borrow_mut()
.get_mut(&window_id)
.map(|w| w.try_read_pty());
}
Ok(WakeupMsg::SigChld) => {
for (window_id, window) in self.windows_by_id.borrow_mut().iter_mut() {
match window.test_for_child_exit() {
Ok(_) => {}
Err(err) => {
@ -248,12 +252,16 @@ fn run_glium(
dead_windows.insert(window_id.clone());
}
}
},
Ok(WakeupMsg::Paint) => for (_, window) in windows_by_id.iter_mut() {
}
}
Ok(WakeupMsg::Paint) => {
for (_, window) in self.windows_by_id.borrow_mut().iter_mut() {
window.paint_if_needed().unwrap();
},
}
}
Ok(WakeupMsg::Paste(window_id)) => {
windows_by_id
self.windows_by_id
.borrow_mut()
.get_mut(&window_id)
.map(|w| w.process_clipboard());
}
@ -272,10 +280,10 @@ fn run_glium(
.send(PtyMsg::DelPty(window_id, master_fd))
.unwrap();
*/
windows_by_id.remove(&window_id);
self.windows_by_id.borrow_mut().remove(&window_id);
}
if windows_by_id.len() == 0 {
if self.windows_by_id.borrow().len() == 0 {
// If we have no more windows left to manage, we're done
Break
} else {
@ -285,9 +293,51 @@ fn run_glium(
Break => Break,
}
});
self.pty_sender.send(PtyMsg::Terminate)?;
Ok(())
}
}
pty_sender.send(PtyMsg::Terminate)?;
pty_thread.join().ok();
impl Drop for GuiEventLoop {
fn drop(&mut self) {
match self.pty_thread.take() {
Some(t) => {
t.join().unwrap();
}
None => {}
}
}
}
fn run_glium(
master: pty::MasterPty,
child: std::process::Child,
config: config::Config,
fontconfig: FontConfiguration,
terminal: term::Terminal,
initial_pixel_width: u16,
initial_pixel_height: u16,
) -> Result<(), Error> {
let event_loop = GuiEventLoop::new()?;
let window = gliumwindows::TerminalWindow::new(
&*event_loop.event_loop.borrow_mut(),
event_loop.wakeup.clone(),
initial_pixel_width,
initial_pixel_height,
terminal,
master,
child,
fontconfig,
config
.colors
.map(|p| p.into())
.unwrap_or_else(term::color::ColorPalette::default),
)?;
event_loop.add_window(window)?;
event_loop.run()?;
Ok(())
}