aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ansi.rs2
-rw-r--r--src/event.rs3
-rw-r--r--src/event_loop.rs6
-rw-r--r--src/lib.rs7
-rw-r--r--src/macros.rs9
-rw-r--r--src/main.rs83
-rw-r--r--src/renderer/mod.rs27
-rw-r--r--src/window.rs299
8 files changed, 362 insertions, 74 deletions
diff --git a/src/ansi.rs b/src/ansi.rs
index 50dec9ac..f876cb54 100644
--- a/src/ansi.rs
+++ b/src/ansi.rs
@@ -927,7 +927,6 @@ pub mod C1 {
#[cfg(test)]
mod tests {
use std::io;
-
use index::{Line, Column};
use super::{Processor, Handler, Attr, TermInfo, Color};
use ::Rgb;
@@ -945,7 +944,6 @@ mod tests {
}
}
-
#[derive(Default)]
struct AttrHandler {
attr: Option<Attr>,
diff --git a/src/event.rs b/src/event.rs
index 2656db72..900a0fb1 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -5,6 +5,7 @@ use std::sync::{Arc, mpsc};
use serde_json as json;
use glutin;
+use window::Window;
use input;
use sync::FairMutex;
@@ -114,7 +115,7 @@ impl<N: input::Notify> Processor<N> {
}
/// Process at least one event and handle any additional queued events.
- pub fn process_events(&mut self, window: &glutin::Window) {
+ pub fn process_events(&mut self, window: &Window) {
for event in window.wait_events() {
self.handle_event(event);
break;
diff --git a/src/event_loop.rs b/src/event_loop.rs
index 72b98425..c2c5ce69 100644
--- a/src/event_loop.rs
+++ b/src/event_loop.rs
@@ -14,6 +14,8 @@ use term::Term;
use util::thread;
use sync::FairMutex;
+use window;
+
use super::Flag;
/// Messages that may be sent to the `EventLoop`
@@ -33,7 +35,7 @@ pub struct EventLoop<Io> {
rx: mio::channel::Receiver<Msg>,
tx: mio::channel::Sender<Msg>,
terminal: Arc<FairMutex<Term>>,
- proxy: ::glutin::WindowProxy,
+ proxy: window::Proxy,
signal_flag: Flag,
ref_test: bool,
}
@@ -129,7 +131,7 @@ impl<Io> EventLoop<Io>
/// Create a new event loop
pub fn new(
terminal: Arc<FairMutex<Term>>,
- proxy: ::glutin::WindowProxy,
+ proxy: window::Proxy,
signal_flag: Flag,
pty: Io,
ref_test: bool,
diff --git a/src/lib.rs b/src/lib.rs
index 8f08303b..cd4f382e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -48,8 +48,11 @@ extern crate bitflags;
#[macro_use]
pub mod macros;
+pub mod ansi;
+pub mod config;
pub mod event;
pub mod event_loop;
+pub mod grid;
pub mod index;
pub mod input;
pub mod meter;
@@ -58,9 +61,7 @@ pub mod sync;
pub mod term;
pub mod tty;
pub mod util;
-pub mod ansi;
-pub mod config;
-pub mod grid;
+pub mod window;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/macros.rs b/src/macros.rs
index eb37d4db..740e5ed9 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -48,3 +48,12 @@ macro_rules! debug_print {
}
}
+#[macro_export]
+macro_rules! maybe {
+ ($option:expr) => {
+ match $option {
+ Some(value) => value,
+ None => return None,
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 71edea67..9c9c50d7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -51,24 +51,14 @@ use alacritty::Flag;
use alacritty::Rgb;
use alacritty::config::{self, Config};
use alacritty::event;
-use alacritty::gl;
+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::event_loop::EventLoop;
-
-/// Channel used by resize handling on mac
-static mut RESIZE_CALLBACK: Option<Box<Fn(u32, u32)>> = None;
-
-/// Resize handling for Mac
-fn window_resize_handler(width: u32, height: u32) {
- unsafe {
- RESIZE_CALLBACK.as_ref().map(|func| func(width, height));
- }
-}
+use alacritty::window::{self, Window, SetInnerSize, Pixels, Size};
mod cli;
@@ -100,35 +90,22 @@ fn main() {
let dpi = config.dpi();
let render_timer = config.render_timer();
- // Create glutin window
- let mut window = glutin::WindowBuilder::new()
- .with_vsync()
- .with_title("Alacritty")
- .build().unwrap();
-
- // Set the glutin window resize callback for this one window.
- window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));
+ // Create the window where Alacritty will be displayed
+ let mut window = match Window::new() {
+ Ok(window) => window,
+ Err(err) => die!("{}", err)
+ };
- // load gl symbols
- gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
// get window properties for initializing the other subsytems
- let (width, height) = window.get_inner_size_pixels().unwrap();
+ let size = window.inner_size_pixels().unwrap();
let dpr = window.hidpi_factor();
println!("device_pixel_ratio: {}", dpr);
- let _ = unsafe { window.make_current() };
- unsafe {
- // gl::Viewport(0, 0, width as i32, height as i32);
- gl::Enable(gl::BLEND);
- gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
- gl::Enable(gl::MULTISAMPLE);
- }
-
let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);
// Create renderer
- let mut renderer = QuadRenderer::new(&config, width, height);
+ let mut renderer = QuadRenderer::new(&config, size);
// Initialize glyph cache
let glyph_cache = {
@@ -156,19 +133,17 @@ fn main() {
// Resize window to specified dimensions
let width = cell_width * options.columns_u32() + 4;
let height = cell_height * options.lines_u32() + 4;
- println!("set_inner_size: {} x {}", width, height);
- // Is this in points?
- let width_pts = (width as f32 / dpr) as u32;
- let height_pts = (height as f32 / dpr) as u32;
- println!("set_inner_size: {} x {}; pts: {} x {}", width, height, width_pts, height_pts);
- window.set_inner_size(width_pts, height_pts);
- renderer.resize(width as _, height as _);
+ 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: width as f32,
- height: height as f32,
+ width: *size.width as f32,
+ height: *size.height as f32,
cell_width: cell_width as f32,
cell_height: cell_height as f32
};
@@ -189,17 +164,15 @@ fn main() {
let signal_flag_ref = signal_flag.clone();
let proxy = window.create_window_proxy();
let tx2 = tx.clone();
- unsafe {
- RESIZE_CALLBACK = Some(Box::new(move |width: u32, height: u32| {
- 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();
- }
- }));
- }
+ 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();
+ }
+ });
let event_loop = EventLoop::new(
terminal.clone(),
@@ -279,7 +252,7 @@ fn main() {
struct ConfigHandler {
tx: mpsc::Sender<config::Config>,
- window: ::glutin::WindowProxy,
+ window: window::Proxy,
}
impl config::OnConfigReload for ConfigHandler {
@@ -294,7 +267,7 @@ impl config::OnConfigReload for ConfigHandler {
}
struct Display<'a> {
- window: &'a glutin::Window,
+ window: &'a Window,
renderer: QuadRenderer,
glyph_cache: GlyphCache,
render_timer: bool,
@@ -310,7 +283,7 @@ impl<'a> Display<'a> {
}
pub fn new(
- window: &glutin::Window,
+ window: &Window,
renderer: QuadRenderer,
glyph_cache: GlyphCache,
render_timer: bool,
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 2728ad5f..b1fb27ed 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -26,6 +26,8 @@ use gl;
use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op};
use index::{Line, Column};
+use window::{Size, Pixels};
+
use ansi::{Color, NamedColor};
use config::{Config, ColorList};
@@ -385,8 +387,8 @@ const ATLAS_SIZE: i32 = 1024;
impl QuadRenderer {
// TODO should probably hand this a transform instead of width/height
- pub fn new(config: &Config, width: u32, height: u32) -> QuadRenderer {
- let program = ShaderProgram::new(width, height).unwrap();
+ pub fn new(config: &Config, size: Size<Pixels<u32>>) -> QuadRenderer {
+ let program = ShaderProgram::new(size).unwrap();
let mut vao: GLuint = 0;
let mut vbo: GLuint = 0;
@@ -394,8 +396,11 @@ impl QuadRenderer {
let mut vbo_instance: GLuint = 0;
-
unsafe {
+ gl::Enable(gl::BLEND);
+ gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
+ gl::Enable(gl::MULTISAMPLE);
+
gl::GenVertexArrays(1, &mut vao);
gl::GenBuffers(1, &mut vbo);
gl::GenBuffers(1, &mut ebo);
@@ -552,7 +557,10 @@ impl QuadRenderer {
while let Ok(msg) = self.rx.try_recv() {
match msg {
Msg::ShaderReload => {
- self.reload_shaders(props.width as u32, props.height as u32);
+ self.reload_shaders(Size {
+ width: Pixels(props.width as u32),
+ height: Pixels(props.height as u32)
+ });
}
}
}
@@ -599,8 +607,8 @@ impl QuadRenderer {
})
}
- pub fn reload_shaders(&mut self, width: u32, height: u32) {
- let program = match ShaderProgram::new(width, height) {
+ pub fn reload_shaders(&mut self, size: Size<Pixels<u32>>) {
+ let program = match ShaderProgram::new(size) {
Ok(program) => program,
Err(err) => {
match err {
@@ -809,10 +817,7 @@ impl ShaderProgram {
}
}
- pub fn new(
- width: u32,
- height: u32
- ) -> Result<ShaderProgram, ShaderCreationError> {
+ pub fn new(size: Size<Pixels<u32>>) -> Result<ShaderProgram, ShaderCreationError> {
let vertex_source = if cfg!(feature = "live-shader-reload") {
None
} else {
@@ -885,7 +890,7 @@ impl ShaderProgram {
u_background: background,
};
- shader.update_projection(width as f32, height as f32);
+ shader.update_projection(*size.width as f32, *size.height as f32);
shader.deactivate();
diff --git a/src/window.rs b/src/window.rs
new file mode 100644
index 00000000..c1790bb6
--- /dev/null
+++ b/src/window.rs
@@ -0,0 +1,299 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use std::convert::From;
+use std::fmt::{self, Display};
+use std::ops::Deref;
+
+use gl;
+use glutin;
+
+/// Default title for the window
+const DEFAULT_TITLE: &'static str = "Alacritty";
+
+/// Resize handling for Mac and maybe other platforms
+///
+/// This delegates to a statically referenced closure for convenience. The
+/// C-style callback doesn't receive a pointer or anything, so we are forced to
+/// use static storage.
+///
+/// This will fail horribly if more than one window is created. Don't do that :)
+fn window_resize_handler(width: u32, height: u32) {
+ unsafe {
+ RESIZE_CALLBACK.as_ref().map(|func| func(width, height));
+ }
+}
+
+/// The resize callback invoked by `window_resize_handler`
+static mut RESIZE_CALLBACK: Option<Box<Fn(u32, u32)>> = None;
+
+/// Window errors
+#[derive(Debug)]
+pub enum Error {
+ /// Error creating the window
+ Creation(glutin::CreationError),
+
+ /// Error manipulating the rendering context
+ Context(glutin::ContextError),
+}
+
+/// Result of fallible operations concerning a Window.
+type Result<T> = ::std::result::Result<T, Error>;
+
+/// A window which can be used for displaying the terminal
+///
+/// Wraps the underlying windowing library to provide a stable API in Alacritty
+pub struct Window {
+ glutin_window: glutin::Window,
+}
+
+/// Threadsafe APIs for the window
+pub struct Proxy(glutin::WindowProxy);
+
+/// Information about where the window is being displayed
+///
+/// Useful for subsystems like the font rasterized which depend on DPI and scale
+/// factor.
+pub struct DeviceProperties {
+ /// Scale factor for pixels <-> points.
+ ///
+ /// This will be 1. on standard displays and may have a different value on
+ /// hidpi displays.
+ pub scale_factor: f32,
+}
+
+/// Size of the window
+#[derive(Debug, Copy, Clone)]
+pub struct Size<T> {
+ pub width: T,
+ pub height: T,
+}
+
+/// Strongly typed Pixels unit
+#[derive(Debug, Copy, Clone)]
+pub struct Pixels<T>(pub T);
+
+/// Strongly typed Points unit
+///
+/// Points are like pixels but adjusted for DPI.
+#[derive(Debug, Copy, Clone)]
+pub struct Points<T>(pub T);
+
+pub trait ToPoints {
+ fn to_points(&self, scale: f32) -> Size<Points<u32>>;
+}
+
+impl ToPoints for Size<Points<u32>> {
+ #[inline]
+ fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
+ *self
+ }
+}
+
+impl ToPoints for Size<Pixels<u32>> {
+ fn to_points(&self, scale: f32) -> Size<Points<u32>> {
+ let width_pts = (*self.width as f32 / scale) as u32;
+ let height_pts = (*self.height as f32 / scale) as u32;
+
+ Size {
+ width: Points(width_pts),
+ height: Points(height_pts)
+ }
+ }
+}
+
+impl<T: Display> Display for Size<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} × {}", self.width, self.height)
+ }
+}
+
+macro_rules! deref_newtype {
+ ($($src:ty),+) => {
+ $(
+ impl<T> Deref for $src {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ )+
+ }
+}
+
+deref_newtype! { Points<T>, Pixels<T> }
+
+
+impl<T: Display> Display for Pixels<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}px", self.0)
+ }
+}
+
+impl ::std::error::Error for Error {
+ fn cause(&self) -> Option<&::std::error::Error> {
+ match *self {
+ Error::Creation(ref err) => Some(err),
+ Error::Context(ref err) => Some(err),
+ }
+ }
+
+ fn description(&self) -> &str {
+ match *self {
+ Error::Creation(ref _err) => "Error creating glutin Window",
+ Error::Context(ref _err) => "Error operating on render context",
+ }
+ }
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ match *self {
+ Error::Creation(ref err) => {
+ write!(f, "Error creating glutin::Window; {}", err)
+ },
+ Error::Context(ref err) => {
+ write!(f, "Error operating on render context; {}", err)
+ },
+ }
+ }
+}
+
+impl From<glutin::CreationError> for Error {
+ fn from(val: glutin::CreationError) -> Error {
+ Error::Creation(val)
+ }
+}
+
+impl From<glutin::ContextError> for Error {
+ fn from(val: glutin::ContextError) -> Error {
+ Error::Context(val)
+ }
+}
+
+impl Window {
+ /// Create a new window
+ ///
+ /// This creates a window and fully initializes a window.
+ pub fn new() -> Result<Window> {
+ /// Create a glutin::Window
+ let mut window = glutin::WindowBuilder::new()
+ .with_vsync()
+ .with_title(DEFAULT_TITLE)
+ .build()?;
+
+ /// Set the glutin window resize callback for *this* window. The
+ /// function pointer must be a C-style callback. This sets such a
+ /// callback which simply delegates to a statically referenced Rust
+ /// closure.
+ window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));
+
+ /// Set OpenGL symbol loader
+ gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
+
+ /// Make the window's context current so OpenGL operations can run
+ unsafe {
+ window.make_current()?;
+ }
+
+ Ok(Window {
+ glutin_window: window,
+ })
+ }
+
+ /// Get some properties about the device
+ ///
+ /// Some window properties are provided since subsystems like font
+ /// rasterization depend on DPI and scale factor.
+ pub fn device_properties(&self) -> DeviceProperties {
+ DeviceProperties {
+ scale_factor: self.glutin_window.hidpi_factor(),
+ }
+ }
+
+ /// Set the window resize callback
+ ///
+ /// Pass a `move` closure which will be called with the new width and height
+ /// when the window is resized. According to the glutin docs, this can be
+ /// used to draw during resizing.
+ ///
+ /// This method takes self mutably to ensure there's no race condition
+ /// setting the callback.
+ pub fn set_resize_callback<F: Fn(u32, u32) + 'static>(&mut self, func: F) {
+ unsafe {
+ RESIZE_CALLBACK = Some(Box::new(func));
+ }
+ }
+
+ pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
+ self.glutin_window
+ .get_inner_size_pixels()
+ .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
+ }
+
+ #[inline]
+ pub fn hidpi_factor(&self) -> f32 {
+ self.glutin_window.hidpi_factor()
+ }
+
+ #[inline]
+ pub fn create_window_proxy(&self) -> Proxy {
+ Proxy(self.glutin_window.create_window_proxy())
+ }
+
+ #[inline]
+ pub fn swap_buffers(&self) -> Result<()> {
+ self.glutin_window
+ .swap_buffers()
+ .map_err(From::from)
+ }
+
+ /// Block waiting for events
+ ///
+ /// FIXME should return our own type
+ #[inline]
+ pub fn wait_events(&self) -> glutin::WaitEventsIterator {
+ self.glutin_window.wait_events()
+ }
+
+ /// Block waiting for events
+ ///
+ /// FIXME should return our own type
+ #[inline]
+ pub fn poll_events(&self) -> glutin::PollEventsIterator {
+ self.glutin_window.poll_events()
+ }
+}
+
+impl Proxy {
+ /// Wakes up the event loop of the window
+ ///
+ /// This is useful for triggering a draw when the renderer would otherwise
+ /// be waiting on user input.
+ pub fn wakeup_event_loop(&self) {
+ self.0.wakeup_event_loop();
+ }
+}
+
+pub trait SetInnerSize<T> {
+ fn set_inner_size<S: ToPoints>(&mut self, size: S);
+}
+
+impl SetInnerSize<Pixels<u32>> for Window {
+ fn set_inner_size<T: ToPoints>(&mut self, size: T) {
+ let size = size.to_points(self.hidpi_factor());
+ self.glutin_window.set_inner_size(*size.width as _, *size.height as _);
+ }
+}