diff options
-rw-r--r-- | src/main.rs | 179 | ||||
-rw-r--r-- | src/term.rs | 27 |
2 files changed, 115 insertions, 91 deletions
diff --git a/src/main.rs b/src/main.rs index 94cc1bc1..76216685 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,7 @@ mod ansi; mod term; mod util; -use std::sync::mpsc::TryRecvError; +use std::sync::mpsc; use std::collections::HashMap; use std::io::{BufReader, Read, BufRead, Write, BufWriter}; use std::sync::Arc; @@ -46,6 +46,64 @@ use meter::Meter; use util::thread; use tty::process_should_exit; +/// Things that the render/update thread needs to respond to +#[derive(Debug)] +enum Event { + PtyChar(char), + Glutin(glutin::Event), +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum ShouldExit { + Yes, + No +} + +fn handle_event<W>(event: Event, + writer: &mut W, + terminal: &mut Term, + pty_parser: &mut ansi::Parser) -> ShouldExit + where W: Write +{ + match event { + // Handle char from pty + Event::PtyChar(c) => pty_parser.advance(terminal, c), + // Handle keyboard/mouse input and other window events + Event::Glutin(gevent) => match gevent { + glutin::Event::Closed => return ShouldExit::Yes, + glutin::Event::ReceivedCharacter(c) => { + let encoded = c.encode_utf8(); + writer.write(encoded.as_slice()).unwrap(); + }, + glutin::Event::KeyboardInput(state, _code, key) => { + match state { + glutin::ElementState::Pressed => { + match key { + Some(glutin::VirtualKeyCode::Up) => { + writer.write("\x1b[A".as_bytes()).unwrap(); + }, + Some(glutin::VirtualKeyCode::Down) => { + writer.write("\x1b[B".as_bytes()).unwrap(); + }, + Some(glutin::VirtualKeyCode::Left) => { + writer.write("\x1b[D".as_bytes()).unwrap(); + }, + Some(glutin::VirtualKeyCode::Right) => { + writer.write("\x1b[C".as_bytes()).unwrap(); + }, + _ => (), + } + }, + _ => (), + } + }, + _ => () + } + } + + ShouldExit::No +} + #[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] pub struct Rgb { r: u8, @@ -130,11 +188,12 @@ fn main() { gl::Enable(gl::MULTISAMPLE); } - let (chars_tx, chars_rx) = ::std::sync::mpsc::channel(); + let (tx, rx) = mpsc::channel(); + let reader_tx = tx.clone(); let reader_thread = thread::spawn_named("TTY Reader", move || { for c in reader.chars() { let c = c.unwrap(); - chars_tx.send(c).unwrap(); + reader_tx.send(Event::PtyChar(c)).unwrap(); } }); @@ -143,50 +202,45 @@ fn main() { let mut pty_parser = ansi::Parser::new(); + let window = Arc::new(window); + let window_ref = window.clone(); + let input_thread = thread::spawn_named("Input Thread", move || { + for event in window_ref.wait_events() { + tx.send(Event::Glutin(event)); + if process_should_exit() { + break; + } + } + + }); + 'main_loop: loop { - // Handle keyboard/mouse input and other window events - { - let mut writer = BufWriter::new(&writer); - for event in window.poll_events() { - match event { - glutin::Event::Closed => break 'main_loop, - glutin::Event::ReceivedCharacter(c) => { - let encoded = c.encode_utf8(); - writer.write(encoded.as_slice()).unwrap(); - }, - glutin::Event::KeyboardInput(state, _code, key) => { - match state { - glutin::ElementState::Pressed => { - match key { - Some(glutin::VirtualKeyCode::Up) => { - writer.write("\x1b[A".as_bytes()).unwrap(); - }, - Some(glutin::VirtualKeyCode::Down) => { - writer.write("\x1b[B".as_bytes()).unwrap(); - }, - Some(glutin::VirtualKeyCode::Left) => { - writer.write("\x1b[D".as_bytes()).unwrap(); - }, - Some(glutin::VirtualKeyCode::Right) => { - writer.write("\x1b[C".as_bytes()).unwrap(); - }, - _ => (), - } - }, - _ => (), - } - }, - _ => () + // Block waiting for next event + match rx.recv() { + Ok(e) => { + let res = handle_event(e, &mut writer, &mut terminal, &mut pty_parser); + if res == ShouldExit::Yes { + break; } - } + }, + Err(mpsc::RecvError) => break, } + // Handle Any events that have been queued loop { - match chars_rx.try_recv() { - Ok(c) => pty_parser.advance(&mut terminal, c), - Err(TryRecvError::Disconnected) => break 'main_loop, - Err(TryRecvError::Empty) => break, + match rx.try_recv() { + Ok(e) => { + let res = handle_event(e, &mut writer, &mut terminal, &mut pty_parser); + + if res == ShouldExit::Yes { + break; + } + }, + Err(mpsc::TryRecvError::Disconnected) => break 'main_loop, + Err(mpsc::TryRecvError::Empty) => break, } + + // TODO make sure this doesn't block renders } unsafe { @@ -194,39 +248,36 @@ fn main() { gl::Clear(gl::COLOR_BUFFER_BIT); } - if terminal.dirty() { - { - let _sampler = meter.sampler(); - - renderer.with_api(&props, |mut api| { - // Draw the grid - api.render_grid(terminal.grid(), &mut glyph_cache); - - // Also draw the cursor - if !terminal.mode().contains(term::mode::TEXT_CURSOR) { - api.render_cursor(terminal.cursor(), &mut glyph_cache); - } - }) - } + { + let _sampler = meter.sampler(); - // Draw render timer - let timing = format!("{:.3} usec", meter.average()); - let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 }; renderer.with_api(&props, |mut api| { - api.render_string(&timing[..], &mut glyph_cache, &color); - }); - - terminal.clear_dirty(); + // Draw the grid + api.render_grid(terminal.grid(), &mut glyph_cache); - window.swap_buffers().unwrap(); + // Also draw the cursor + if !terminal.mode().contains(term::mode::TEXT_CURSOR) { + api.render_cursor(terminal.cursor(), &mut glyph_cache); + } + }) } + // Draw render timer + let timing = format!("{:.3} usec", meter.average()); + let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 }; + renderer.with_api(&props, |mut api| { + api.render_string(&timing[..], &mut glyph_cache, &color); + }); + + window.swap_buffers().unwrap(); + if process_should_exit() { break; } } - reader_thread.join(); + reader_thread.join().ok(); + input_thread.join().ok(); println!("Goodbye"); } diff --git a/src/term.rs b/src/term.rs index 0bcf6b24..9d92e282 100644 --- a/src/term.rs +++ b/src/term.rs @@ -105,9 +105,6 @@ pub struct Term { /// Cell attributes attr: grid::CellFlags, - /// Whether state has changed and needs to be updated. - dirty: bool, - /// Mode flags mode: TermMode, @@ -136,20 +133,11 @@ impl Term { tty: tty, tabs: tabs, attr: CellFlags::empty(), - dirty: false, mode: TermMode::empty(), scroll_region: scroll_region, } } - pub fn dirty(&self) -> bool { - self.dirty - } - - pub fn clear_dirty(&mut self) { - self.dirty = false; - } - pub fn grid(&self) -> &Grid { &self.grid } @@ -190,7 +178,6 @@ impl Term { /// Set character in current cursor position fn set_char(&mut self, c: char) { - self.dirty = true; if self.cursor.x == self.grid.num_cols() as u16 { println!("wrapping"); self.cursor.y += 1; @@ -253,17 +240,14 @@ impl ansi::Handler for Term { fn goto(&mut self, x: i64, y: i64) { println!("goto: x={}, y={}", x, y); - self.dirty = true; self.cursor.goto(x as u16, y as u16); } fn goto_row(&mut self, y: i64) { - self.dirty = true; println!("goto_row: {}", y); let x = self.cursor_x(); self.cursor.goto(x, y as u16); } fn goto_col(&mut self, x: i64) { - self.dirty = true; println!("goto_col: {}", x); let y = self.cursor_y(); self.cursor.goto(x as u16, y); @@ -272,25 +256,21 @@ impl ansi::Handler for Term { fn insert_blank(&mut self, num: i64) { println!("insert_blank: {}", num); } fn move_up(&mut self, rows: i64) { - self.dirty = true; println!("move_up: {}", rows); self.cursor.advance(-rows, 0); } fn move_down(&mut self, rows: i64) { - self.dirty = true; println!("move_down: {}", rows); self.cursor.advance(rows, 0); } fn move_forward(&mut self, cols: i64) { - self.dirty = true; println!("move_forward: {}", cols); self.cursor.advance(0, cols); } fn move_backward(&mut self, spaces: i64) { - self.dirty = true; println!("move_backward: {}", spaces); self.cursor.advance(0, -spaces); } @@ -299,7 +279,6 @@ impl ansi::Handler for Term { fn move_down_and_cr(&mut self, rows: i64) { println!("move_down_and_cr: {}", rows); } fn move_up_and_cr(&mut self, rows: i64) { println!("move_up_and_cr: {}", rows); } fn put_tab(&mut self, mut count: i64) { - self.dirty = true; println!("put_tab: {}", count); let mut x = self.cursor_x(); @@ -320,7 +299,6 @@ impl ansi::Handler for Term { #[inline] fn backspace(&mut self, count: i64) { println!("backspace"); - self.dirty = true; self.cursor.x -= 1; self.set_char(' '); } @@ -329,14 +307,12 @@ impl ansi::Handler for Term { #[inline] fn carriage_return(&mut self) { println!("carriage_return"); - self.dirty = true; self.cursor.x = 0; } /// Linefeed #[inline] fn linefeed(&mut self) { - self.dirty = true; println!("linefeed"); // TODO handle scroll? not clear what parts of this the pty handle if self.cursor_y() + 1 >= self.scroll_region.end as u16 { @@ -378,7 +354,6 @@ impl ansi::Handler for Term { fn save_cursor_position(&mut self) { println!("save_cursor_position"); } fn restore_cursor_position(&mut self) { println!("restore_cursor_position"); } fn clear_line(&mut self, mode: ansi::LineClearMode) { - self.dirty = true; println!("clear_line: {:?}", mode); match mode { ansi::LineClearMode::Right => { @@ -393,7 +368,6 @@ impl ansi::Handler for Term { } } fn clear_screen(&mut self, mode: ansi::ClearMode) { - self.dirty = true; println!("clear_screen: {:?}", mode); match mode { ansi::ClearMode::Below => { @@ -417,7 +391,6 @@ impl ansi::Handler for Term { fn clear_tabs(&mut self, mode: ansi::TabulationClearMode) { println!("clear_tabs: {:?}", mode); } fn reset_state(&mut self) { println!("reset_state"); } fn reverse_index(&mut self) { - self.dirty = true; println!("reverse_index"); // if cursor is at the top if self.cursor.y == 0 { |