summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorZac Pullar-Strecker <zacps@users.noreply.github.com>2018-10-17 06:02:52 +1300
committerJoe Wilm <jwilm@users.noreply.github.com>2018-10-16 10:02:52 -0700
commit15e0deae2b49078b47a782679300cdf99d9ce687 (patch)
tree8175fbed0def1af08cd2db41583975adbb27dff1 /src
parentb41c6b736d67d61e92b174dfea58ae46813934cd (diff)
Add support for Windows (#1374)
Initial support for Windows is implemented using the winpty translation layer. Clipboard support for Windows is provided through the `clipboard` crate, and font rasterization is provided by RustType. The tty.rs file has been split into OS-specific files to separate standard pty handling from the winpty implementation. Several binary components are fetched via build script on windows including libclang and winpty. These could be integrated more directly in the future either by building those dependencies as part of the Alacritty build process or by leveraging git lfs to store the artifacts. Fixes #28.
Diffstat (limited to 'src')
-rw-r--r--src/config.rs48
-rw-r--r--src/display.rs46
-rw-r--r--src/event_loop.rs186
-rw-r--r--src/input.rs14
-rw-r--r--src/lib.rs18
-rw-r--r--src/main.rs65
-rw-r--r--src/renderer/mod.rs318
-rw-r--r--src/tty/mod.rs45
-rw-r--r--src/tty/unix.rs (renamed from src/tty.rs)148
-rw-r--r--src/tty/windows.rs284
-rw-r--r--src/window.rs51
11 files changed, 902 insertions, 321 deletions
diff --git a/src/config.rs b/src/config.rs
index 0f250522..c7d7ea58 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -555,10 +555,12 @@ fn failure_default<'a, D, T>(deserializer: D)
}
}
-#[cfg(not(target_os="macos"))]
+#[cfg(not(any(windows, target_os="macos")))]
static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty.yml");
#[cfg(target_os="macos")]
static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_macos.yml");
+#[cfg(windows)]
+static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_windows.yml");
impl Default for Config {
fn default() -> Self {
@@ -1444,6 +1446,7 @@ impl Config {
/// 2. $XDG_CONFIG_HOME/alacritty.yml
/// 3. $HOME/.config/alacritty/alacritty.yml
/// 4. $HOME/.alacritty.yml
+ #[cfg(not(windows))]
pub fn installed_config<'a>() -> Option<Cow<'a, Path>> {
// Try using XDG location by default
::xdg::BaseDirectories::with_prefix("alacritty")
@@ -1472,6 +1475,19 @@ impl Config {
.map(|path| path.into())
}
+ #[cfg(windows)]
+ pub fn installed_config() -> Option<Cow<'static, Path>> {
+ if let Some(mut path) = ::std::env::home_dir() {
+ path.push("alacritty");
+ path.set_extension("yml");
+ if path.exists() {
+ return Some(path.into());
+ }
+ }
+ None
+ }
+
+ #[cfg(not(windows))]
pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
let path = ::xdg::BaseDirectories::with_prefix("alacritty")
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, ::std::error::Error::description(&err)))
@@ -1480,6 +1496,15 @@ impl Config {
Ok(path.into())
}
+ #[cfg(windows)]
+ pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
+ let path = ::std::env::home_dir()
+ .ok_or(io::Error::new(io::ErrorKind::NotFound, "could not find profile directory"))
+ .and_then(|mut p| {p.push("alacritty"); p.set_extension("yml"); Ok(p)})?;
+ File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
+ Ok(path.into())
+ }
+
/// Get list of colors
///
/// The ordering returned here is expected by the terminal. Colors are simply indexed in this
@@ -1894,6 +1919,22 @@ impl Default for Font {
}
}
+#[cfg(windows)]
+impl Default for Font {
+ fn default() -> Font {
+ Font {
+ normal: FontDescription::new_with_family("Consolas"),
+ bold: FontDescription::new_with_family("Consolas"),
+ italic: FontDescription::new_with_family("Consolas"),
+ size: Size::new(11.0),
+ use_thin_strokes: false,
+ offset: Default::default(),
+ glyph_offset: Default::default(),
+ scale_with_dpi: false,
+ }
+ }
+}
+
pub struct Monitor {
_thread: ::std::thread::JoinHandle<()>,
rx: mpsc::Receiver<Config>,
@@ -1977,7 +2018,10 @@ mod tests {
#[cfg(target_os="macos")]
static ALACRITTY_YML: &'static str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty_macos.yml"));
- #[cfg(not(target_os="macos"))]
+ #[cfg(windows)]
+ static ALACRITTY_YML: &'static str =
+ include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty_windows.yml"));
+ #[cfg(not(any(target_os="macos", windows)))]
static ALACRITTY_YML: &'static str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
diff --git a/src/display.rs b/src/display.rs
index d806b33a..d5a2ea0a 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -16,7 +16,7 @@
//! GPU drawing.
use std::sync::mpsc;
-use parking_lot::{MutexGuard};
+use parking_lot::MutexGuard;
use Rgb;
use cli;
@@ -27,7 +27,7 @@ use renderer::{self, GlyphCache, QuadRenderer};
use term::{Term, SizeInfo, RenderableCell};
use sync::FairMutex;
-use window::{self, Size, Pixels, Window, SetInnerSize};
+use window::{self, Pixels, SetInnerSize, Size, Window};
#[derive(Debug)]
pub enum Error {
@@ -128,10 +128,7 @@ impl Display {
&self.size_info
}
- pub fn new(
- config: &Config,
- options: &cli::Options,
- ) -> Result<Display, Error> {
+ pub fn new(config: &Config, options: &cli::Options) -> Result<Display, Error> {
// Extract some properties from config
let render_timer = config.render_timer();
@@ -196,9 +193,14 @@ impl Display {
// Clear screen
let background_color = config.colors().primary.background;
- renderer.with_api(config, &size_info, 0. /* visual bell intensity */, |api| {
- api.clear(background_color);
- });
+ renderer.with_api(
+ config,
+ &size_info,
+ 0., /* visual bell intensity */
+ |api| {
+ api.clear(background_color);
+ },
+ );
Ok(Display {
window,
@@ -224,9 +226,8 @@ impl Display {
info!("Initializing glyph cache");
let init_start = ::std::time::Instant::now();
- let cache = renderer.with_loader(|mut api| {
- GlyphCache::new(rasterizer, &font, &mut api)
- })?;
+ let cache =
+ renderer.with_loader(|mut api| GlyphCache::new(rasterizer, &font, &mut api))?;
let stop = init_start.elapsed();
let stop_f = stop.as_secs() as f64 + f64::from(stop.subsec_nanos()) / 1_000_000_000f64;
@@ -276,7 +277,7 @@ impl Display {
&mut self,
terminal: &mut MutexGuard<Term>,
config: &Config,
- items: &mut [&mut OnResize]
+ items: &mut [&mut OnResize],
) {
// Resize events new_size and are handled outside the poll_events
// iterator. This has the effect of coalescing multiple resize
@@ -295,8 +296,7 @@ impl Display {
if new_size == None {
// Force a resize to refresh things
- new_size = Some((self.size_info.width as u32,
- self.size_info.height as u32));
+ new_size = Some((self.size_info.width as u32, self.size_info.height as u32));
}
}
@@ -316,7 +316,6 @@ impl Display {
self.window.resize(w, h);
self.renderer.resize(w as i32, h as i32);
}
-
}
/// Draw the screen
@@ -385,10 +384,15 @@ impl Display {
// Draw render timer
if self.render_timer {
let timing = format!("{:.3} usec", self.meter.average());
- let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
- self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
- api.render_string(&timing[..], glyph_cache, color);
- });
+ let color = Rgb {
+ r: 0xd5,
+ g: 0x4e,
+ b: 0x53,
+ };
+ self.renderer
+ .with_api(config, &size_info, visual_bell_intensity, |mut api| {
+ api.render_string(&timing[..], glyph_cache, color);
+ });
}
}
@@ -403,7 +407,7 @@ impl Display {
/// Adjust the IME editor position according to the new location of the cursor
pub fn update_ime_position(&mut self, terminal: &Term) {
- use index::{Point, Line, Column};
+ use index::{Column, Line, Point};
use term::SizeInfo;
let Point{line: Line(row), col: Column(col)} = terminal.cursor().point;
let SizeInfo{cell_width: cw,
diff --git a/src/event_loop.rs b/src/event_loop.rs
index d7d27243..8cc094f6 100644
--- a/src/event_loop.rs
+++ b/src/event_loop.rs
@@ -1,20 +1,21 @@
//! The main event loop which performs I/O on the pseudoterminal
use std::borrow::Cow;
use std::collections::VecDeque;
-use std::io::{self, ErrorKind, Write};
+use std::io::{self, ErrorKind, Read, Write};
use std::fs::File;
-use std::os::unix::io::AsRawFd;
use std::sync::Arc;
+use std::marker::Send;
use mio::{self, Events, PollOpt, Ready};
-#[cfg(unix)]
+use mio_more::channel::{self, Receiver, Sender};
+
+#[cfg(not(windows))]
use mio::unix::UnixReady;
-use mio::unix::EventedFd;
-use mio_more::channel::{self, Sender, Receiver};
use ansi;
use display;
use event;
+use tty;
use term::Term;
use util::thread;
use sync::FairMutex;
@@ -26,16 +27,16 @@ pub enum Msg {
Input(Cow<'static, [u8]>),
/// Indicates that the `EventLoop` should shut down, as Alacritty is shutting down
- Shutdown
+ Shutdown,
}
/// The main event!.. loop.
///
/// Handles all the pty I/O and runs the pty parser which updates terminal
/// state.
-pub struct EventLoop<Io> {
+pub struct EventLoop<T: tty::EventedReadWrite> {
poll: mio::Poll,
- pty: Io,
+ pty: T,
rx: Receiver<Msg>,
tx: Sender<Msg>,
terminal: Arc<FairMutex<Term>>,
@@ -83,7 +84,7 @@ pub struct Notifier(pub Sender<Msg>);
impl event::Notify for Notifier {
fn notify<B>(&mut self, bytes: B)
- where B: Into<Cow<'static, [u8]>>
+ where B: Into<Cow<'static, [u8]>>,
{
let bytes = bytes.into();
// terminal hangs if we send 0 bytes through.
@@ -96,7 +97,6 @@ impl event::Notify for Notifier {
}
}
-
impl Default for State {
fn default() -> State {
State {
@@ -163,19 +163,17 @@ impl Writing {
/// `mio::Token` for the event loop channel
const CHANNEL: mio::Token = mio::Token(0);
-/// `mio::Token` for the pty file descriptor
-const PTY: mio::Token = mio::Token(1);
-
-impl<Io> EventLoop<Io>
- where Io: io::Read + io::Write + Send + AsRawFd + 'static
+impl<T> EventLoop<T>
+ where
+ T: tty::EventedReadWrite + Send + 'static,
{
/// Create a new event loop
pub fn new(
terminal: Arc<FairMutex<Term>>,
display: display::Notifier,
- pty: Io,
+ pty: T,
ref_test: bool,
- ) -> EventLoop<Io> {
+ ) -> EventLoop<T> {
let (tx, rx) = channel::channel();
EventLoop {
poll: mio::Poll::new().expect("create mio Poll"),
@@ -203,7 +201,7 @@ impl<Io> EventLoop<Io>
match msg {
Msg::Input(input) => {
state.write_list.push_back(input);
- },
+ }
Msg::Shutdown => {
return DrainResult::Shutdown;
}
@@ -224,32 +222,22 @@ impl<Io> EventLoop<Io>
return false;
}
- self.poll.reregister(
- &self.rx, CHANNEL,
- Ready::readable(),
- PollOpt::edge() | PollOpt::oneshot()
- ).expect("reregister channel");
-
- if state.needs_write() {
- self.poll.reregister(
- &EventedFd(&self.pty.as_raw_fd()),
- PTY,
- Ready::readable() | Ready::writable(),
- PollOpt::edge() | PollOpt::oneshot()
- ).expect("reregister fd after channel recv");
- }
+ self.poll
+ .reregister(&self.rx, CHANNEL, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
+ .unwrap();
true
}
#[inline]
- fn pty_read<W>(
+ fn pty_read<X>(
&mut self,
state: &mut State,
buf: &mut [u8],
- mut writer: Option<&mut W>
+ mut writer: Option<&mut X>,
) -> io::Result<()>
- where W: Write
+ where
+ X: Write,
{
const MAX_READ: usize = 0x1_0000;
let mut processed = 0;
@@ -259,7 +247,7 @@ impl<Io> EventLoop<Io>
let mut send_wakeup = false;
loop {
- match self.pty.read(&mut buf[..]) {
+ match self.pty.reader().read(&mut buf[..]) {
Ok(0) => break,
Ok(got) => {
// Record bytes read; used to limit time spent in pty_read.
@@ -286,23 +274,22 @@ impl<Io> EventLoop<Io>
// Run the parser
for byte in &buf[..got] {
- state.parser.advance(&mut **terminal, *byte, &mut self.pty);
+ state
+ .parser
+ .advance(&mut **terminal, *byte, &mut self.pty.writer());
}
// Exit if we've processed enough bytes
if processed > MAX_READ {
break;
}
- },
- Err(err) => {
- match err.kind() {
- ErrorKind::Interrupted |
- ErrorKind::WouldBlock => {
- break;
- },
- _ => return Err(err),
- }
}
+ Err(err) => match err.kind() {
+ ErrorKind::Interrupted | ErrorKind::WouldBlock => {
+ break;
+ }
+ _ => return Err(err),
+ },
}
}
@@ -323,56 +310,53 @@ impl<Io> EventLoop<Io>
'write_many: while let Some(mut current) = state.take_current() {
'write_one: loop {
- match self.pty.write(current.remaining_bytes()) {
+ match self.pty.writer().write(current.remaining_bytes()) {
Ok(0) => {
state.set_current(Some(current));
break 'write_many;
- },
+ }
Ok(n) => {
current.advance(n);
if current.finished() {
state.goto_next();
break 'write_one;
}
- },
+ }
Err(err) => {
state.set_current(Some(current));
match err.kind() {
- ErrorKind::Interrupted |
- ErrorKind::WouldBlock => break 'write_many,
+ ErrorKind::Interrupted | ErrorKind::WouldBlock => break 'write_many,
_ => return Err(err),
}
}
}
-
}
}
Ok(())
}
- pub fn spawn(
- mut self,
- state: Option<State>
- ) -> thread::JoinHandle<(EventLoop<Io>, State)> {
+ pub fn spawn(mut self, state: Option<State>) -> thread::JoinHandle<(Self, State)> {
thread::spawn_named("pty reader", move || {
let mut state = state.unwrap_or_else(Default::default);
let mut buf = [0u8; 0x1000];
- let fd = self.pty.as_raw_fd();
- let fd = EventedFd(&fd);
-
let poll_opts = PollOpt::edge() | PollOpt::oneshot();
- self.poll.register(&self.rx, CHANNEL, Ready::readable(), poll_opts).unwrap();
- self.poll.register(&fd, PTY, Ready::readable(), poll_opts).unwrap();
+ let tokens = [1, 2];
+
+ self.poll
+ .register(&self.rx, CHANNEL, Ready::readable(), poll_opts)
+ .unwrap();
+
+ // Register TTY through EventedRW interface
+ self.pty
+ .register(&self.poll, &mut tokens.iter(), Ready::readable(), poll_opts).unwrap();
let mut events = Events::with_capacity(1024);
let mut pipe = if self.ref_test {
- let file = File::create("./alacritty.recording")
- .expect("create alacritty recording");
- Some(file)
+ Some(File::create("./alacritty.recording").expect("create alacritty recording"))
} else {
None
};
@@ -381,64 +365,68 @@ impl<Io> EventLoop<Io>
if let Err(err) = self.poll.poll(&mut events, None) {
match err.kind() {
ErrorKind::Interrupted => continue,
- _ => panic!("EventLoop polling error: {:?}", err)
+ _ => panic!("EventLoop polling error: {:?}", err),
}
}
for event in events.iter() {
match event.token() {
- CHANNEL => {
- if !self.channel_event(&mut state) {
- break 'event_loop;
- }
+ CHANNEL => if !self.channel_event(&mut state) {
+ break 'event_loop;
},
- PTY => {
- let ready = event.readiness();
-
- #[cfg(unix)] {
- if UnixReady::from(ready).is_hup() {
- break 'event_loop;
- }
- }
-
- if ready.is_readable() {
- if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut()) {
- error!("Event loop exiting due to error: {} [{}:{}]",
- err, file!(), line!());
- break 'event_loop;
+ token if token == self.pty.read_token() || token == self.pty.write_token() => {
+ #[cfg(unix)]
+ {
+ if UnixReady::from(event.readiness()).is_hup() {
+ break 'event_loop;
+ }
}
+ if event.readiness().is_readable() {
+ if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut())
+ {
+ error!(
+ "Event loop exitting due to error: {} [{}:{}]",
+ err,
+ file!(),
+ line!()
+ );
+ break 'event_loop;
+ }
if ::tty::process_should_exit() {
break 'event_loop;
}
}
- if ready.is_writable() {
+ if event.readiness().is_writable() {
if let Err(err) = self.pty_write(&mut state) {
- error!("Event loop exiting due to error: {} [{}:{}]",
- err, file!(), line!());
+ error!(
+ "Event loop exitting due to error: {} [{}:{}]",
+ err,
+ file!(),
+ line!()
+ );
break 'event_loop;
}
}
-
- // Figure out pty interest
- let mut interest = Ready::readable();
- if state.needs_write() {
- interest.insert(Ready::writable());
- }
-
- // Reregister pty
- self.poll
- .reregister(&fd, PTY, interest, poll_opts)
- .expect("register fd after read/write");
- },
+ }
_ => (),
}
}
+
+ // Register write interest if necessary
+ let mut interest = Ready::readable();
+ if state.needs_write() {
+ interest.insert(Ready::writable());
+ }
+ // Reregister with new interest
+ self.pty.reregister(&self.poll, interest, poll_opts).unwrap();
}
+ // The evented instances are not dropped here so deregister them explicitly
+ // TODO: Is this still necessary?
let _ = self.poll.deregister(&self.rx);
- let _ = self.poll.deregister(&fd);
+ self.pty.deregister(&self.poll).unwrap();
(self, state)
})
diff --git a/src/input.rs b/src/input.rs
index cc3f13df..6d3b407a 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -22,6 +22,7 @@ use std::borrow::Cow;
use std::mem;
use std::process::Command;
use std::time::Instant;
+#[cfg(not(windows))]
use std::os::unix::process::CommandExt;
use copypasta::{Clipboard, Load, Buffer as ClipboardBuffer};
@@ -232,7 +233,9 @@ impl Action {
},
Action::Command(ref program, ref args) => {
trace!("running command: {} {:?}", program, args);
- match Command::new(program)
+
+ #[cfg(not(windows))]
+ let spawned = Command::new(program)
.args(args)
.before_exec(|| {
// Detach forked process from Alacritty. This will cause
@@ -240,7 +243,14 @@ impl Action {
unsafe { ::libc::daemon(1, 0); }
Ok(())
})
- .spawn()
+ .spawn();
+
+ #[cfg(windows)]
+ let spawned = Command::new(program)
+ .args(args)
+ .spawn();
+
+ match spawned
{
Ok(child) => {
debug!("spawned new proc with pid: {}", child.id());
diff --git a/src/lib.rs b/src/lib.rs
index fcc55799..d0e48c3d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,9 +23,23 @@
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate static_assertions;
-#[cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))]
+#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly",
+ target_os = "openbsd"))]
extern crate x11_dl;
+#[cfg(windows)]
+extern crate mio_named_pipes;
+#[cfg(windows)]
+extern crate winapi;
+#[cfg(windows)]
+extern crate winpty;
+#[cfg(windows)]
+extern crate dunce;
+#[cfg(windows)]
+extern crate winit;
+#[cfg(windows)]
+extern crate image;
+
#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;
@@ -33,8 +47,8 @@ extern crate objc;
extern crate arraydeque;
extern crate cgmath;
extern crate copypasta;
-extern crate errno;
extern crate env_logger;
+extern crate errno;
extern crate fnv;
extern crate font;
extern crate glutin;
diff --git a/src/main.rs b/src/main.rs
index 03a372df..651c5abd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,6 +17,12 @@
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
#![cfg_attr(all(test, feature = "bench"), feature(test))]
+// With the default subsystem, 'console', windows creates an additional console
+// window for the program.
+// This is silently ignored on non-windows systems.
+// See https://msdn.microsoft.com/en-us/library/4cc7ya5b.aspx for more details.
+#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+
#[macro_use]
extern crate alacritty;
@@ -29,6 +35,8 @@ use std::error::Error;
use std::sync::Arc;
#[cfg(target_os = "macos")]
use std::env;
+#[cfg(not(windows))]
+use std::os::unix::io::AsRawFd;
use alacritty::cli;
use alacritty::config::{self, Config};
@@ -39,7 +47,7 @@ use alacritty::event_loop::{self, EventLoop, Msg};
use alacritty::locale;
use alacritty::logging;
use alacritty::sync::FairMutex;
-use alacritty::term::{Term};
+use alacritty::term::Term;
use alacritty::tty::{self, process_should_exit};
use alacritty::util::fmt::Red;
@@ -67,7 +75,8 @@ fn main() {
///
/// If a configuration file is given as a command line argument we don't
/// generate a default file. If an empty configuration file is given, i.e.
-/// /dev/null, we load the compiled-in defaults.
+/// /dev/null, we load the compiled-in defaults.)
+#[cfg(not(windows))]
fn load_config(options: &cli::Options) -> Config {
let config_path = options.config_path()
.or_else(Config::installed_config)
@@ -81,6 +90,27 @@ fn load_config(options: &cli::Options) -> Config {
Config::default()
})
}
+#[cfg(windows)]
+fn load_config(options: &cli::Options) -> Config {
+ let config_path = options
+ .config_path()
+ .or_else(|| Config::installed_config())
+ .unwrap_or_else(|| {
+ Config::write_defaults()
+ .unwrap_or_else(|err| die!("Write defaults config failure: {}", err))
+ });
+
+ Config::load_from(&*config_path).unwrap_or_else(|err| match err {
+ config::Error::NotFound => {
+ die!("Config file not found after writing: {}", config_path.display());
+ }
+ config::Error::Empty => {
+ eprintln!("Empty config; Loading defaults");
+ Config::default()
+ }
+ _ => die!("{}", err),
+ })
+}
/// Run Alacritty
///
@@ -122,7 +152,17 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> {
// 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 mut pty = tty::new(&config, options, &display.size(), window_id);
+ let pty = tty::new(&config, options, &display.size(), window_id);
+
+ // Get a reference to something that we can resize
+ //
+ // This exists because rust doesn't know the interface is thread-safe
+ // and we need to be able to resize the PTY from the main thread while the IO
+ // thread owns the EventedRW object.
+ #[cfg(windows)]
+ let resize_handle = unsafe { &mut *pty.winpty.get() };
+ #[cfg(not(windows))]
+ let mut resize_handle = pty.fd.as_raw_fd();
// Create the pseudoterminal I/O loop
//
@@ -133,7 +173,7 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> {
let event_loop = EventLoop::new(
Arc::clone(&terminal),
display.notifier(),
- pty.reader(),
+ pty,
options.ref_test,
);
@@ -168,7 +208,9 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> {
};
// Kick off the I/O thread
- let io_thread = event_loop.spawn(None);
+ let _io_thread = event_loop.spawn(None);
+
+ info!("Initialisation complete");
// Main display loop
loop {
@@ -195,7 +237,11 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> {
//
// The second argument is a list of types that want to be notified
// of display size changes.
- display.handle_resize(&mut terminal_lock, &config, &mut [&mut pty, &mut processor]);
+ #[cfg(windows)]
+ display.handle_resize(&mut terminal_lock, &config, &mut [resize_handle, &mut processor]);
+ #[cfg(not(windows))]
+ display.handle_resize(&mut terminal_lock, &config, &mut [&mut resize_handle, &mut processor]);
+
drop(terminal_lock);
// Draw the current state of the terminal
@@ -208,13 +254,12 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> {
}
}
- loop_tx.send(Msg::Shutdown).expect("Error sending shutdown to event loop");
+ loop_tx
+ .send(Msg::Shutdown)
+ .expect("Error sending shutdown to event loop");
// FIXME patch notify library to have a shutdown method
// config_reloader.join().ok();
- // Wait for the I/O thread thread to finish
- let _ = io_thread.join();
-
Ok(())
}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index bcc896ef..28b44633 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -16,22 +16,22 @@ use std::fs::File;
use std::hash::BuildHasherDefault;
use std::io::{self, Read};
use std::mem::size_of;
-use std::path::{PathBuf};
+use std::path::PathBuf;
use std::ptr;
use std::sync::mpsc;
use std::time::Duration;
use cgmath;
use fnv::FnvHasher;
-use font::{self, Rasterizer, Rasterize, RasterizedGlyph, FontDesc, GlyphKey, FontKey};
+use font::{self, FontDesc, FontKey, GlyphKey, Rasterize, RasterizedGlyph, Rasterizer};
use gl::types::*;
use gl;
-use index::{Line, Column, RangeInclusive};
-use notify::{Watcher, watcher, RecursiveMode, DebouncedEvent};
+use index::{Column, Line, RangeInclusive};
+use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use config::{self, Config, Delta};
use term::{self, cell, RenderableCell};
-use window::{Size, Pixels};
+use window::{Pixels, Size};
use Rgb;
@@ -40,12 +40,10 @@ static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/
static TEXT_SHADER_V_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl");
// Shader source which is used when live-shader-reload feature is disable
-static TEXT_SHADER_F: &'static str = include_str!(
- concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl")
-);
-static TEXT_SHADER_V: &'static str = include_str!(
- concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl")
-);
+static TEXT_SHADER_F: &'static str =
+ include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl"));
+static TEXT_SHADER_V: &'static str =
+ include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl"));
/// `LoadGlyph` allows for copying a rasterized glyph into graphics memory
pub trait LoadGlyph {
@@ -97,7 +95,6 @@ impl From<ShaderCreationError> for Error {
}
}
-
/// Text drawing program