diff options
Diffstat (limited to 'alacritty/src/display')
-rw-r--r-- | alacritty/src/display/mod.rs | 64 | ||||
-rw-r--r-- | alacritty/src/display/window.rs | 68 |
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() + } +} |