diff options
author | Christian Duerr <contact@christianduerr.com> | 2021-10-23 07:16:47 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-23 07:16:47 +0000 |
commit | 1df7dc5171abfe1eab3e95be964f61c5876198f1 (patch) | |
tree | 315ceaa093b86b8e875512825302f38e32f697a4 /alacritty/src/display/mod.rs | |
parent | d8a98f88295e59d6518ae780a9857c033a83161c (diff) | |
download | r-alacritty-1df7dc5171abfe1eab3e95be964f61c5876198f1.tar.gz r-alacritty-1df7dc5171abfe1eab3e95be964f61c5876198f1.tar.bz2 r-alacritty-1df7dc5171abfe1eab3e95be964f61c5876198f1.zip |
Add multi-window support
Previously Alacritty would always initialize only a single terminal
emulator window feeding into the winit event loop, however some
platforms like macOS expect all windows to be spawned by the same
process and this "daemon-mode" can also come with the advantage of
increased memory efficiency.
The event loop has been restructured to handle all window-specific
events only by the event processing context with the associated window
id. This makes it possible to add new terminal windows at any time using
the WindowContext::new function call.
Some preliminary tests have shown that for empty terminals, this reduces
the cost of additional terminal emulators from ~100M to ~6M. However at
this point the robustness of the daemon against issues with individual
terminals has not been refined, making the reliability of this system
questionable.
New windows can be created either by using the new `CreateNewWindow`
action, or with the `alacritty msg create-window` subcommand. The
subcommand sends a message to an IPC socket which Alacritty listens on,
its location can be found in the `ALACRITTY_SOCKET` environment
variable.
Fixes #607.
Diffstat (limited to 'alacritty/src/display/mod.rs')
-rw-r--r-- | alacritty/src/display/mod.rs | 64 |
1 files changed, 38 insertions, 26 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; |