aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-12-10 22:44:13 -0800
committerJoe Wilm <joe@jwilm.com>2016-12-11 20:23:41 -0800
commited0b1cfff04903fe26f586340e036c38bbf30b33 (patch)
treeeb4eb3545bee57ed401cb7727c9dc3f106fabe3b /src/main.rs
parentbbd8ddbfc055e85f8810285e71fd227cdd418221 (diff)
downloadalacritty-ed0b1cfff04903fe26f586340e036c38bbf30b33.tar.gz
alacritty-ed0b1cfff04903fe26f586340e036c38bbf30b33.zip
Display manages window, renderer, rasterizer
This is part of an ongoing decoupling effort across the codebase and tidying effort in main.rs. Everything to do with showing the window with a grid of characters is now managed by the `Display` type. It owns the window, the font rasterizer, and the renderer. The only info needed from it are dimensions of characters and the window itself for sizing the terminal properly. Additionally, the I/O loop has access to wake it up when new data arrives.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs280
1 files changed, 61 insertions, 219 deletions
diff --git a/src/main.rs b/src/main.rs
index 1c1397d0..0fba05a6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -42,25 +42,20 @@ extern crate vte;
#[macro_use]
extern crate bitflags;
+use std::error::Error;
use std::sync::{mpsc, Arc};
-use std::sync::atomic::Ordering;
+use std::rc::Rc;
-use parking_lot::{MutexGuard};
-
-use alacritty::Flag;
-use alacritty::Rgb;
+use alacritty::cli;
use alacritty::config::{self, Config};
+use alacritty::display::{self, Display};
use alacritty::event;
use alacritty::event_loop::EventLoop;
use alacritty::input;
-use alacritty::meter::Meter;
-use alacritty::renderer::{QuadRenderer, GlyphCache};
use alacritty::sync::FairMutex;
-use alacritty::term::{self, Term};
-use alacritty::tty::{self, Pty, process_should_exit};
-use alacritty::window::{self, Window, SetInnerSize, Pixels, Size};
+use alacritty::term::{Term};
+use alacritty::tty::{self, process_should_exit};
-mod cli;
fn main() {
// Load configuration
@@ -86,7 +81,11 @@ fn main() {
let options = cli::Options::load();
// Run alacritty
- run(config, options);
+ if let Err(err) = run(config, options) {
+ die!("{}", err);
+ }
+
+ println!("Goodbye");
}
/// Run Alacritty
@@ -156,124 +155,59 @@ fn main() {
///
/// instead of the 200 line monster it currently is.
///
-fn run(config: Config, options: cli::Options) {
-
-
- // Extract some properties from config
- let font = config.font();
- let dpi = config.dpi();
- let render_timer = config.render_timer();
-
- // Create the window where Alacritty will be displayed
- let mut window = match Window::new() {
- Ok(window) => window,
- Err(err) => die!("{}", err)
- };
-
- // get window properties for initializing the other subsytems
- let size = window.inner_size_pixels().unwrap();
- let dpr = window.hidpi_factor();
-
- println!("device_pixel_ratio: {}", dpr);
-
- let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);
-
- // Create renderer
- let mut renderer = QuadRenderer::new(&config, size);
-
- // Initialize glyph cache
- let glyph_cache = {
- println!("Initializing glyph cache");
- let init_start = ::std::time::Instant::now();
-
- let cache = renderer.with_loader(|mut api| {
- GlyphCache::new(rasterizer, &config, &mut api)
- });
-
- let stop = init_start.elapsed();
- let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
- println!("Finished initializing glyph cache in {}", stop_f);
-
- cache
- };
-
- // Need font metrics to resize the window properly. This suggests to me the
- // font metrics should be computed before creating the window in the first
- // place so that a resize is not needed.
- let metrics = glyph_cache.font_metrics();
- let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
- let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;
-
- // Resize window to specified dimensions
- let width = cell_width * options.columns_u32() + 4;
- let height = cell_height * options.lines_u32() + 4;
- let size = Size { width: Pixels(width), height: Pixels(height) };
- println!("set_inner_size: {}", size);
-
- window.set_inner_size(size);
- renderer.resize(*size.width as _, *size.height as _);
-
- println!("Cell Size: ({} x {})", cell_width, cell_height);
-
- let size = term::SizeInfo {
- width: *size.width as f32,
- height: *size.height as f32,
- cell_width: cell_width as f32,
- cell_height: cell_height as f32
- };
-
- let terminal = Term::new(size);
- let pty = tty::new(size.lines(), size.cols());
- pty.resize(size.lines(), size.cols(), size.width as usize, size.height as usize);
- let pty_io = pty.reader();
-
- let (tx, rx) = mpsc::channel();
-
- let signal_flag = Flag::new(false);
-
- let terminal = Arc::new(FairMutex::new(terminal));
-
- // Setup the rsize callback for osx
- let terminal_ref = terminal.clone();
- let signal_flag_ref = signal_flag.clone();
- let proxy = window.create_window_proxy();
- let tx2 = tx.clone();
- window.set_resize_callback(move |width, height| {
- let _ = tx2.send((width, height));
- if !signal_flag_ref.0.swap(true, Ordering::AcqRel) {
- // We raised the signal flag
- let mut terminal = terminal_ref.lock();
- terminal.dirty = true;
- proxy.wakeup_event_loop();
- }
+fn run(config: Config, options: cli::Options) -> Result<(), Box<Error>> {
+ // Create a display.
+ //
+ // The display manages a window and can draw the terminal
+ let mut display = Display::new(&config, &options)?;
+
+ // Create the terminal
+ //
+ // This object contains all of the state about what's being displayed. It's
+ // wrapped in a clonable mutex since both the I/O loop and display need to
+ // access it.
+ let terminal = Arc::new(FairMutex::new(Term::new(display.size().to_owned())));
+
+ // Create the pty
+ //
+ // The pty forks a process to run the shell on the slave side of the
+ // pseudoterminal. A file descriptor for the master side is retained for
+ // reading/writing to the shell.
+ let pty = Rc::new(tty::new(display.size()));
+
+ // When the display is resized, inform the kernel of changes to pty
+ // dimensions.
+ //
+ // TODO: The Rc on pty is needed due to a borrowck error here. The borrow
+ // checker says that `pty` is still borrowed when it is dropped at the end
+ // of the `run` function.
+ let pty_ref = pty.clone();
+ display.set_resize_callback(move |size| {
+ pty_ref.resize(size);
});
+ // Create the pseudoterminal I/O loop
+ //
+ // pty I/O is ran on another thread as to not occupy cycles used by the
+ // renderer and input processing. Note that access to the terminal state is
+ // synchronized since the I/O loop updates the state, and the display
+ // consumes it periodically.
let event_loop = EventLoop::new(
terminal.clone(),
- window.create_window_proxy(),
- signal_flag.clone(),
- pty_io,
+ display.notifier(),
+ pty.reader(),
options.ref_test,
);
let loop_tx = event_loop.channel();
let event_loop_handle = event_loop.spawn(None);
- // Wraps a renderer and gives simple draw() api.
- let mut display = Display::new(
- &window,
- renderer,
- glyph_cache,
- render_timer,
- rx,
- pty
- );
-
// Event processor
+ let resize_tx = display.resize_channel();
let mut processor = event::Processor::new(
input::LoopNotifier(loop_tx),
terminal.clone(),
- tx,
+ resize_tx,
&config,
options.ref_test,
);
@@ -284,28 +218,26 @@ fn run(config: Config, options: cli::Options) {
let _config_reloader = config.path().map(|path| {
config::Watcher::new(path, ConfigHandler {
tx: config_tx,
- window: window.create_window_proxy(),
+ loop_kicker: display.notifier(),
})
});
// Main loop
- let mut force_draw;
+ let mut config_updated = false;
loop {
- force_draw = false;
// Wait for something to happen
- processor.process_events(&window);
+ processor.process_events(display.window());
// Handle config reloads
if let Ok(config) = config_rx.try_recv() {
- force_draw = true;
+ config_updated = true;
display.update_config(&config);
processor.update_config(&config);
}
// Maybe draw the terminal
let terminal = terminal.lock();
- signal_flag.set(false);
- if force_draw || terminal.dirty {
+ if terminal.dirty || config_updated {
display.draw(terminal, &config);
}
@@ -317,16 +249,19 @@ fn run(config: Config, options: cli::Options) {
// FIXME need file watcher to work with custom delegates before
// joining config reloader is possible
+ //
+ // HELP I don't know what I meant in the above fixme
// config_reloader.join().ok();
// shutdown
event_loop_handle.join().ok();
- println!("Goodbye");
+
+ Ok(())
}
struct ConfigHandler {
tx: mpsc::Sender<config::Config>,
- window: window::Proxy,
+ loop_kicker: display::Notifier,
}
impl config::OnConfigReload for ConfigHandler {
@@ -336,100 +271,7 @@ impl config::OnConfigReload for ConfigHandler {
return;
}
- self.window.wakeup_event_loop();
+ self.loop_kicker.notify();
}
}
-struct Display<'a> {
- window: &'a Window,
- renderer: QuadRenderer,
- glyph_cache: GlyphCache,
- render_timer: bool,
- rx: mpsc::Receiver<(u32, u32)>,
- meter: Meter,
- pty: Pty,
-}
-
-impl<'a> Display<'a> {
- pub fn update_config(&mut self, config: &Config) {
- self.renderer.update_config(config);
- self.render_timer = config.render_timer();
- }
-
- pub fn new(
- window: &Window,
- renderer: QuadRenderer,
- glyph_cache: GlyphCache,
- render_timer: bool,
- rx: mpsc::Receiver<(u32, u32)>,
- pty: Pty
- ) -> Display {
- Display {
- window: window,
- renderer: renderer,
- glyph_cache: glyph_cache,
- render_timer: render_timer,
- rx: rx,
- meter: Meter::new(),
- pty: pty,
- }
- }
-
- /// Draw the screen
- ///
- /// A reference to Term whose state is being drawn must be provided.
- ///
- /// This call may block if vsync is enabled
- pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config) {
- terminal.dirty = false;
-
- // Resize events new_size and are handled outside the poll_events
- // iterator. This has the effect of coalescing multiple resize
- // events into one.
- let mut new_size = None;
-
-
- // Check for any out-of-band resize events (mac only)
- while let Ok(sz) = self.rx.try_recv() {
- new_size = Some(sz);
- }
-
- // Receive any resize events; only call gl::Viewport on last
- // available
- if let Some((w, h)) = new_size.take() {
- terminal.resize(w as f32, h as f32);
- let size = terminal.size_info();
- self.pty.resize(size.lines(), size.cols(), w as _, h as _);
- self.renderer.resize(w as i32, h as i32);
- }
-
- {
- let glyph_cache = &mut self.glyph_cache;
- // Draw grid
- {
- let _sampler = self.meter.sampler();
-
- let size_info = terminal.size_info().clone();
- self.renderer.with_api(config, &size_info, |mut api| {
- api.clear();
-
- // Draw the grid
- api.render_cells(terminal.renderable_cells(), glyph_cache);
- });
- }
-
- // Draw render timer
- if self.render_timer {
- let timing = format!("{:.3} usec", self.meter.average());
- let color = alacritty::ansi::Color::Spec(Rgb { r: 0xd5, g: 0x4e, b: 0x53 });
- self.renderer.with_api(config, terminal.size_info(), |mut api| {
- api.render_string(&timing[..], glyph_cache, &color);
- });
- }
- }
-
- // Unlock the terminal mutex
- drop(terminal);
- self.window.swap_buffers().unwrap();
- }
-}