aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/display
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/display')
-rw-r--r--alacritty/src/display/mod.rs64
-rw-r--r--alacritty/src/display/window.rs68
2 files changed, 100 insertions, 32 deletions
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index 946c27f9..a942a88d 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -3,15 +3,15 @@
use std::cmp::min;
use std::convert::TryFrom;
-use std::f64;
use std::fmt::{self, Formatter};
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use std::sync::atomic::Ordering;
use std::time::Instant;
+use std::{f64, mem};
use glutin::dpi::{PhysicalPosition, PhysicalSize};
use glutin::event::ModifiersState;
-use glutin::event_loop::EventLoop;
+use glutin::event_loop::EventLoopWindowTarget;
#[cfg(not(any(target_os = "macos", windows)))]
use glutin::platform::unix::EventLoopWindowTargetExtUnix;
use glutin::window::CursorIcon;
@@ -19,7 +19,7 @@ use log::{debug, info};
use parking_lot::MutexGuard;
use unicode_width::UnicodeWidthChar;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use wayland_client::{Display as WaylandDisplay, EventQueue};
+use wayland_client::EventQueue;
use crossfont::{self, Rasterize, Rasterizer};
@@ -178,9 +178,6 @@ pub struct Display {
/// Hint highlighted by the vi mode cursor.
pub vi_highlighted_hint: Option<HintMatch>,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- pub wayland_event_queue: Option<EventQueue>,
-
#[cfg(not(any(target_os = "macos", windows)))]
pub is_x11: bool,
@@ -195,13 +192,21 @@ pub struct Display {
/// State of the keyboard hints.
pub hint_state: HintState,
+ /// Unprocessed display updates.
+ pub pending_update: DisplayUpdate,
+
renderer: QuadRenderer,
glyph_cache: GlyphCache,
meter: Meter,
}
impl Display {
- pub fn new<E>(config: &Config, event_loop: &EventLoop<E>) -> Result<Display, Error> {
+ pub fn new<E>(
+ config: &Config,
+ event_loop: &EventLoopWindowTarget<E>,
+ #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
+ wayland_event_queue: Option<&EventQueue>,
+ ) -> Result<Display, Error> {
#[cfg(any(not(feature = "x11"), target_os = "macos", windows))]
let is_x11 = false;
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
@@ -229,23 +234,13 @@ impl Display {
debug!("Estimated window size: {:?}", estimated_size);
debug!("Estimated cell size: {} x {}", cell_width, cell_height);
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- let mut wayland_event_queue = None;
-
- // Initialize Wayland event queue, to handle Wayland callbacks.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- if let Some(display) = event_loop.wayland_display() {
- let display = unsafe { WaylandDisplay::from_external_display(display as _) };
- wayland_event_queue = Some(display.create_event_queue());
- }
-
// Spawn the Alacritty window.
let mut window = Window::new(
event_loop,
config,
estimated_size,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue.as_ref(),
+ wayland_event_queue,
)?;
info!("Device pixel ratio: {}", window.dpr);
@@ -344,11 +339,10 @@ impl Display {
vi_highlighted_hint: None,
#[cfg(not(any(target_os = "macos", windows)))]
is_x11,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue,
cursor_hidden: false,
visual_bell: VisualBell::from(&config.ui_config.bell),
colors: List::from(&config.ui_config.colors),
+ pending_update: Default::default(),
})
}
@@ -414,26 +408,30 @@ impl Display {
message_buffer: &MessageBuffer,
search_active: bool,
config: &Config,
- update_pending: DisplayUpdate,
) where
T: EventListener,
{
+ let pending_update = mem::take(&mut self.pending_update);
+
let (mut cell_width, mut cell_height) =
(self.size_info.cell_width(), self.size_info.cell_height());
+ // Ensure we're modifying the correct OpenGL context.
+ self.window.make_current();
+
// Update font size and cell dimensions.
- if let Some(font) = update_pending.font() {
+ if let Some(font) = pending_update.font() {
let cell_dimensions = self.update_glyph_cache(config, font);
cell_width = cell_dimensions.0;
cell_height = cell_dimensions.1;
info!("Cell size: {} x {}", cell_width, cell_height);
- } else if update_pending.cursor_dirty() {
+ } else if pending_update.cursor_dirty() {
self.clear_glyph_cache();
}
let (mut width, mut height) = (self.size_info.width(), self.size_info.height());
- if let Some(dimensions) = update_pending.dimensions() {
+ if let Some(dimensions) = pending_update.dimensions() {
width = dimensions.width as f32;
height = dimensions.height as f32;
}
@@ -463,8 +461,7 @@ impl Display {
terminal.resize(self.size_info);
// Resize renderer.
- let physical =
- PhysicalSize::new(self.size_info.width() as u32, self.size_info.height() as u32);
+ let physical = PhysicalSize::new(self.size_info.width() as _, self.size_info.height() as _);
self.window.resize(physical);
self.renderer.resize(&self.size_info);
@@ -505,6 +502,9 @@ impl Display {
// Drop terminal as early as possible to free lock.
drop(terminal);
+ // Make sure this window's OpenGL context is active.
+ self.window.make_current();
+
self.renderer.with_api(&config.ui_config, &size_info, |api| {
api.clear(background_color);
});
@@ -515,6 +515,10 @@ impl Display {
{
let _sampler = self.meter.sampler();
+ // Ensure macOS hasn't reset our viewport.
+ #[cfg(target_os = "macos")]
+ self.renderer.set_viewport(&size_info);
+
let glyph_cache = &mut self.glyph_cache;
let highlighted_hint = &self.highlighted_hint;
let vi_highlighted_hint = &self.vi_highlighted_hint;
@@ -819,6 +823,14 @@ impl Display {
}
}
+impl Drop for Display {
+ fn drop(&mut self) {
+ // Switch OpenGL context before dropping, otherwise objects (like programs) from other
+ // contexts might be deleted.
+ self.window.make_current()
+ }
+}
+
/// Convert a terminal point to a viewport relative point.
pub fn point_to_viewport(display_offset: usize, point: Point) -> Option<Point<usize>> {
let viewport_line = point.line.0 + display_offset as i32;
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 12416700..16932dc4 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -29,11 +29,12 @@ use {
};
use std::fmt::{self, Display, Formatter};
+use std::ops::{Deref, DerefMut};
#[cfg(target_os = "macos")]
use cocoa::base::{id, NO, YES};
use glutin::dpi::{PhysicalPosition, PhysicalSize};
-use glutin::event_loop::EventLoop;
+use glutin::event_loop::EventLoopWindowTarget;
#[cfg(target_os = "macos")]
use glutin::platform::macos::{WindowBuilderExtMacOS, WindowExtMacOS};
#[cfg(windows)]
@@ -124,7 +125,7 @@ impl From<crossfont::Error> for Error {
fn create_gl_window<E>(
mut window: WindowBuilder,
- event_loop: &EventLoop<E>,
+ event_loop: &EventLoopWindowTarget<E>,
srgb: bool,
vsync: bool,
dimensions: Option<PhysicalSize<u32>>,
@@ -160,7 +161,7 @@ pub struct Window {
/// Cached DPR for quickly scaling pixel sizes.
pub dpr: f64,
- windowed_context: WindowedContext<PossiblyCurrent>,
+ windowed_context: Replaceable<WindowedContext<PossiblyCurrent>>,
current_mouse_cursor: CursorIcon,
mouse_visible: bool,
}
@@ -170,7 +171,7 @@ impl Window {
///
/// This creates a window and fully initializes a window.
pub fn new<E>(
- event_loop: &EventLoop<E>,
+ event_loop: &EventLoopWindowTarget<E>,
config: &Config,
size: Option<PhysicalSize<u32>>,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@@ -232,7 +233,7 @@ impl Window {
Ok(Self {
current_mouse_cursor,
mouse_visible: true,
- windowed_context,
+ windowed_context: Replaceable::new(windowed_context),
#[cfg(not(any(target_os = "macos", windows)))]
should_draw: Arc::new(AtomicBool::new(true)),
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@@ -241,10 +242,12 @@ impl Window {
})
}
+ #[inline]
pub fn set_inner_size(&mut self, size: PhysicalSize<u32>) {
self.window().set_inner_size(size);
}
+ #[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.window().inner_size()
}
@@ -261,6 +264,11 @@ impl Window {
}
#[inline]
+ pub fn request_redraw(&self) {
+ self.window().request_redraw();
+ }
+
+ #[inline]
pub fn set_mouse_cursor(&mut self, cursor: CursorIcon) {
if cursor != self.current_mouse_cursor {
self.current_mouse_cursor = cursor;
@@ -374,7 +382,7 @@ impl Window {
None
}
- pub fn window_id(&self) -> WindowId {
+ pub fn id(&self) -> WindowId {
self.window().id()
}
@@ -436,6 +444,13 @@ impl Window {
self.windowed_context.resize(size);
}
+ pub fn make_current(&mut self) {
+ if !self.windowed_context.is_current() {
+ self.windowed_context
+ .replace_with(|context| unsafe { context.make_current().expect("context swap") });
+ }
+ }
+
/// Disable macOS window shadows.
///
/// This prevents rendering artifacts from showing up when the window is transparent.
@@ -496,3 +511,44 @@ unsafe extern "C" fn xembed_error_handler(_: *mut XDisplay, _: *mut XErrorEvent)
log::error!("Could not embed into specified window.");
std::process::exit(1);
}
+
+/// Struct for safe in-place replacement.
+///
+/// This struct allows easily replacing struct fields that provide `self -> Self` methods in-place,
+/// without having to deal with constantly unwrapping the underlying [`Option`].
+struct Replaceable<T>(Option<T>);
+
+impl<T> Replaceable<T> {
+ pub fn new(inner: T) -> Self {
+ Self(Some(inner))
+ }
+
+ /// Replace the contents of the container.
+ pub fn replace_with<F: FnMut(T) -> T>(&mut self, f: F) {
+ self.0 = self.0.take().map(f);
+ }
+
+ /// Get immutable access to the wrapped value.
+ pub fn get(&self) -> &T {
+ self.0.as_ref().unwrap()
+ }
+
+ /// Get mutable access to the wrapped value.
+ pub fn get_mut(&mut self) -> &mut T {
+ self.0.as_mut().unwrap()
+ }
+}
+
+impl<T> Deref for Replaceable<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ self.get()
+ }
+}
+
+impl<T> DerefMut for Replaceable<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.get_mut()
+ }
+}