aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs179
-rw-r--r--src/term.rs27
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 {