aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src
diff options
context:
space:
mode:
authorAyose <ayosec@gmail.com>2025-02-24 00:00:00 +0000
committerAyose <ayosec@gmail.com>2025-02-24 00:00:00 +0000
commit814e8fefc60b4457ea155d11df9f27795de830ec (patch)
treeecc31d4e95680fd7f2a4dfb61cf30cefae387d3b /alacritty/src
parentff44690b072de6cccffbc8e56b869b8842797692 (diff)
parent03c2907b44b4189aac5fdeaea331f5aab5c7072e (diff)
downloadr-alacritty-814e8fefc60b4457ea155d11df9f27795de830ec.tar.gz
r-alacritty-814e8fefc60b4457ea155d11df9f27795de830ec.tar.bz2
r-alacritty-814e8fefc60b4457ea155d11df9f27795de830ec.zip
Merge remote-tracking branch 'vendor/master' into graphics
Diffstat (limited to 'alacritty/src')
-rw-r--r--alacritty/src/cli.rs9
-rw-r--r--alacritty/src/config/ui_config.rs4
-rw-r--r--alacritty/src/daemon.rs13
-rw-r--r--alacritty/src/display/mod.rs133
-rw-r--r--alacritty/src/display/window.rs20
-rw-r--r--alacritty/src/event.rs25
-rw-r--r--alacritty/src/input/keyboard.rs21
-rw-r--r--alacritty/src/input/mod.rs5
-rw-r--r--alacritty/src/ipc.rs15
-rw-r--r--alacritty/src/main.rs19
-rw-r--r--alacritty/src/renderer/mod.rs69
-rw-r--r--alacritty/src/renderer/platform.rs22
-rw-r--r--alacritty/src/window_context.rs14
13 files changed, 235 insertions, 134 deletions
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index bb0a24f4..feac41bd 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -189,7 +189,7 @@ impl TerminalOptions {
pty_config.shell = Some(command.into());
}
- pty_config.hold |= self.hold;
+ pty_config.drain_on_exit |= self.hold;
}
}
@@ -198,7 +198,7 @@ impl From<TerminalOptions> for PtyOptions {
PtyOptions {
working_directory: options.working_directory.take(),
shell: options.command().map(Into::into),
- hold: options.hold,
+ drain_on_exit: options.hold,
env: HashMap::new(),
}
}
@@ -300,6 +300,11 @@ pub struct WindowOptions {
/// The window tabbing identifier to use when building a window.
pub window_tabbing_id: Option<String>,
+ #[clap(skip)]
+ #[cfg(not(any(target_os = "macos", windows)))]
+ /// `ActivationToken` that we pass to winit.
+ pub activation_token: Option<String>,
+
/// Override configuration file options [example: 'cursor.style="Beam"'].
#[clap(short = 'o', long, num_args = 1..)]
option: Vec<String>,
diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs
index b44bda0d..960bdbbc 100644
--- a/alacritty/src/config/ui_config.rs
+++ b/alacritty/src/config/ui_config.rs
@@ -37,7 +37,7 @@ use crate::config::LOG_TARGET_CONFIG;
/// Regex used for the default URL hint.
#[rustfmt::skip]
const URL_REGEX: &str = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)\
- [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`]+";
+ [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`\\\\]+";
#[derive(ConfigDeserialize, Default, Clone, Debug, PartialEq)]
pub struct UiConfig {
@@ -130,7 +130,7 @@ impl UiConfig {
let shell = self.terminal.shell.clone().or_else(|| self.shell.clone()).map(Into::into);
let working_directory =
self.working_directory.clone().or_else(|| self.general.working_directory.clone());
- PtyOptions { working_directory, shell, hold: false, env: HashMap::new() }
+ PtyOptions { working_directory, shell, drain_on_exit: false, env: HashMap::new() }
}
/// Generate key bindings for all keyboard hints.
diff --git a/alacritty/src/daemon.rs b/alacritty/src/daemon.rs
index c8fb88d1..fa530fa0 100644
--- a/alacritty/src/daemon.rs
+++ b/alacritty/src/daemon.rs
@@ -9,6 +9,7 @@ use std::process::{Command, Stdio};
#[rustfmt::skip]
#[cfg(not(windows))]
use {
+ std::env,
std::error::Error,
std::os::unix::process::CommandExt,
std::os::unix::io::RawFd,
@@ -58,18 +59,22 @@ where
{
let mut command = Command::new(program);
command.args(args).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
- if let Ok(cwd) = foreground_process_path(master_fd, shell_pid) {
- command.current_dir(cwd);
- }
+
+ let working_directory = foreground_process_path(master_fd, shell_pid).ok();
unsafe {
command
- .pre_exec(|| {
+ .pre_exec(move || {
match libc::fork() {
-1 => return Err(io::Error::last_os_error()),
0 => (),
_ => libc::_exit(0),
}
+ // Copy foreground process' working directory, ignoring invalid paths.
+ if let Some(working_directory) = working_directory.as_ref() {
+ let _ = env::set_current_dir(working_directory);
+ }
+
if libc::setsid() == -1 {
return Err(io::Error::last_os_error());
}
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index a679fe21..6ff8b1e3 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -5,10 +5,13 @@ use std::cmp;
use std::fmt::{self, Formatter};
use std::mem::{self, ManuallyDrop};
use std::num::NonZeroU32;
-use std::ops::{Deref, DerefMut};
+use std::ops::Deref;
use std::time::{Duration, Instant};
+use glutin::config::GetGlConfig;
use glutin::context::{NotCurrentContext, PossiblyCurrentContext};
+use glutin::display::GetGlDisplay;
+use glutin::error::ErrorKind;
use glutin::prelude::*;
use glutin::surface::{Surface, SwapInterval, WindowSurface};
@@ -33,6 +36,7 @@ use alacritty_terminal::term::{
};
use alacritty_terminal::vte::ansi::{CursorShape, NamedColor};
+use crate::config::debug::RendererPreference;
use crate::config::font::Font;
use crate::config::window::Dimensions;
#[cfg(not(windows))]
@@ -49,7 +53,7 @@ use crate::display::window::Window;
use crate::event::{Event, EventType, Mouse, SearchState};
use crate::message_bar::{MessageBuffer, MessageType};
use crate::renderer::rects::{RenderLine, RenderLines, RenderRect};
-use crate::renderer::{self, GlyphCache, Renderer};
+use crate::renderer::{self, platform, GlyphCache, Renderer};
use crate::scheduler::{Scheduler, TimerId, Topic};
use crate::string::{ShortenDirection, StrShortener};
@@ -395,10 +399,11 @@ pub struct Display {
hint_mouse_point: Option<Point>,
renderer: ManuallyDrop<Renderer>,
+ renderer_preference: Option<RendererPreference>,
surface: ManuallyDrop<Surface<WindowSurface>>,
- context: ManuallyDrop<Replaceable<PossiblyCurrentContext>>,
+ context: ManuallyDrop<PossiblyCurrentContext>,
glyph_cache: GlyphCache,
meter: Meter,
@@ -431,7 +436,7 @@ impl Display {
}
// Create the GL surface to draw into.
- let surface = renderer::platform::create_gl_surface(
+ let surface = platform::create_gl_surface(
&gl_context,
window.inner_size(),
window.raw_window_handle(),
@@ -520,9 +525,10 @@ impl Display {
}
Ok(Self {
- context: ManuallyDrop::new(Replaceable::new(context)),
+ context: ManuallyDrop::new(context),
visual_bell: VisualBell::from(&config.bell),
renderer: ManuallyDrop::new(renderer),
+ renderer_preference: config.debug.renderer,
surface: ManuallyDrop::new(surface),
colors: List::from(&config.colors),
frame_timer: FrameTimer::new(),
@@ -548,29 +554,69 @@ impl Display {
#[inline]
pub fn gl_context(&self) -> &PossiblyCurrentContext {
- self.context.get()
+ &self.context
}
pub fn make_not_current(&mut self) {
- if self.context.get().is_current() {
- self.context.replace_with(|context| {
- context
- .make_not_current()
- .expect("failed to disable context")
- .treat_as_possibly_current()
- });
+ if self.context.is_current() {
+ self.context.make_not_current_in_place().expect("failed to disable context");
}
}
- pub fn make_current(&self) {
- if !self.context.get().is_current() {
- self.context.make_current(&self.surface).expect("failed to make context current")
+ pub fn make_current(&mut self) {
+ let is_current = self.context.is_current();
+
+ // Attempt to make the context current if it's not.
+ let context_loss = if is_current {
+ self.renderer.was_context_reset()
+ } else {
+ match self.context.make_current(&self.surface) {
+ Err(err) if err.error_kind() == ErrorKind::ContextLost => {
+ info!("Context lost for window {:?}", self.window.id());
+ true
+ },
+ _ => false,
+ }
+ };
+
+ if !context_loss {
+ return;
+ }
+
+ let gl_display = self.context.display();
+ let gl_config = self.context.config();
+ let raw_window_handle = Some(self.window.raw_window_handle());
+ let context = platform::create_gl_context(&gl_display, &gl_config, raw_window_handle)
+ .expect("failed to recreate context.");
+
+ // Drop the old context and renderer.
+ unsafe {
+ ManuallyDrop::drop(&mut self.renderer);
+ ManuallyDrop::drop(&mut self.context);
}
+
+ // Activate new context.
+ let context = context.treat_as_possibly_current();
+ self.context = ManuallyDrop::new(context);
+ self.context.make_current(&self.surface).expect("failed to reativate context after reset.");
+
+ // Recreate renderer.
+ let renderer = Renderer::new(&self.context, self.renderer_preference)
+ .expect("failed to recreate renderer after reset");
+ self.renderer = ManuallyDrop::new(renderer);
+
+ // Resize the renderer.
+ self.renderer.resize(&self.size_info);
+
+ self.reset_glyph_cache();
+ self.damage_tracker.frame().mark_fully_damaged();
+
+ debug!("Recovered window {:?} from gpu reset", self.window.id());
}
fn swap_buffers(&self) {
#[allow(clippy::single_match)]
- let res = match (self.surface.deref(), &self.context.get()) {
+ let res = match (self.surface.deref(), &self.context.deref()) {
#[cfg(not(any(target_os = "macos", windows)))]
(Surface::Egl(surface), PossiblyCurrentContext::Egl(context))
if matches!(self.raw_window_handle, RawWindowHandle::Wayland(_))
@@ -1374,6 +1420,8 @@ impl Display {
(&mut self.highlighted_hint, &mut self.highlighted_hint_age, true),
(&mut self.vi_highlighted_hint, &mut self.vi_highlighted_hint_age, false),
];
+
+ let num_lines = self.size_info.screen_lines();
for (hint, hint_age, reset_mouse) in hints {
let (start, end) = match hint {
Some(hint) => (*hint.bounds().start(), *hint.bounds().end()),
@@ -1387,10 +1435,12 @@ impl Display {
}
// Convert hint bounds to viewport coordinates.
- let start = term::point_to_viewport(display_offset, start).unwrap_or_default();
- let end = term::point_to_viewport(display_offset, end).unwrap_or_else(|| {
- Point::new(self.size_info.screen_lines() - 1, self.size_info.last_column())
- });
+ let start = term::point_to_viewport(display_offset, start)
+ .filter(|point| point.line < num_lines)
+ .unwrap_or_default();
+ let end = term::point_to_viewport(display_offset, end)
+ .filter(|point| point.line < num_lines)
+ .unwrap_or_else(|| Point::new(num_lines - 1, self.size_info.last_column()));
// Clear invalidated hints.
if frame.intersects(start, end) {
@@ -1525,47 +1575,6 @@ pub struct RendererUpdate {
clear_font_cache: bool,
}
-/// 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()
- }
-}
-
/// The frame timer state.
pub struct FrameTimer {
/// Base timestamp used to compute sync points.
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 1c8089bc..f9fb9272 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -2,6 +2,8 @@
use winit::platform::startup_notify::{
self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify,
};
+#[cfg(not(any(target_os = "macos", windows)))]
+use winit::window::ActivationToken;
#[cfg(all(not(feature = "x11"), not(any(target_os = "macos", windows))))]
use winit::platform::wayland::WindowAttributesExtWayland;
@@ -38,6 +40,7 @@ use winit::window::{
use alacritty_terminal::index::Point;
+use crate::cli::WindowOptions;
use crate::config::window::{Decorations, Identity, WindowConfig};
use crate::config::UiConfig;
use crate::display::SizeInfo;
@@ -106,6 +109,9 @@ pub struct Window {
/// Flag indicating whether redraw was requested.
pub requested_redraw: bool,
+ /// Hold the window when terminal exits.
+ pub hold: bool,
+
window: WinitWindow,
/// Current window title.
@@ -124,9 +130,7 @@ impl Window {
event_loop: &ActiveEventLoop,
config: &UiConfig,
identity: &Identity,
- #[rustfmt::skip]
- #[cfg(target_os = "macos")]
- tabbing_id: &Option<String>,
+ options: &mut WindowOptions,
#[rustfmt::skip]
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
x11_visual: Option<X11VisualInfo>,
@@ -138,7 +142,7 @@ impl Window {
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
x11_visual,
#[cfg(target_os = "macos")]
- tabbing_id,
+ &options.window_tabbing_id.take(),
);
if let Some(position) = config.window.position {
@@ -147,7 +151,12 @@ impl Window {
}
#[cfg(not(any(target_os = "macos", windows)))]
- if let Some(token) = event_loop.read_token_from_env() {
+ if let Some(token) = options
+ .activation_token
+ .take()
+ .map(ActivationToken::from_raw)
+ .or_else(|| event_loop.read_token_from_env())
+ {
log::debug!("Activating window with token: {token:?}");
window_attributes = window_attributes.with_activation_token(token);
@@ -193,6 +202,7 @@ impl Window {
let is_x11 = matches!(window.window_handle().unwrap().as_raw(), RawWindowHandle::Xlib(_));
Ok(Self {
+ hold: options.terminal_options.hold,
requested_redraw: false,
title: identity.title,
current_mouse_cursor,
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 2ac6279d..c761f5ae 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -4,6 +4,7 @@ use crate::ConfigMonitor;
use glutin::config::GetGlConfig;
use std::borrow::Cow;
use std::cmp::min;
+use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet, VecDeque};
use std::error::Error;
use std::ffi::OsStr;
@@ -380,9 +381,14 @@ impl ApplicationHandler<Event> for Processor {
},
(EventType::Terminal(TerminalEvent::Exit), Some(window_id)) => {
// Remove the closed terminal.
- let window_context = match self.windows.remove(window_id) {
- Some(window_context) => window_context,
- None => return,
+ let window_context = match self.windows.entry(*window_id) {
+ // Don't exit when terminal exits if user asked to hold the window.
+ Entry::Occupied(window_context)
+ if !window_context.get().display.window.hold =>
+ {
+ window_context.remove()
+ },
+ _ => return,
};
// Unschedule pending events.
@@ -838,9 +844,8 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
#[cfg(not(windows))]
fn create_new_window(&mut self, #[cfg(target_os = "macos")] tabbing_id: Option<String>) {
let mut options = WindowOptions::default();
- if let Ok(working_directory) = foreground_process_path(self.master_fd, self.shell_pid) {
- options.terminal_options.working_directory = Some(working_directory);
- }
+ options.terminal_options.working_directory =
+ foreground_process_path(self.master_fd, self.shell_pid).ok();
#[cfg(target_os = "macos")]
{
@@ -869,7 +874,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
match result {
Ok(_) => debug!("Launched {} with args {:?}", program, args),
- Err(_) => warn!("Unable to launch {} with args {:?}", program, args),
+ Err(err) => warn!("Unable to launch {program} with args {args:?}: {err}"),
}
}
@@ -1793,7 +1798,11 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
},
WinitEvent::WindowEvent { event, .. } => {
match event {
- WindowEvent::CloseRequested => self.ctx.terminal.exit(),
+ WindowEvent::CloseRequested => {
+ // User asked to close the window, so no need to hold it.
+ self.ctx.window().hold = false;
+ self.ctx.terminal.exit();
+ },
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
let old_scale_factor =
mem::replace(&mut self.ctx.window().scale_factor, scale_factor);
diff --git a/alacritty/src/input/keyboard.rs b/alacritty/src/input/keyboard.rs
index af9bfbb2..417f599b 100644
--- a/alacritty/src/input/keyboard.rs
+++ b/alacritty/src/input/keyboard.rs
@@ -342,18 +342,21 @@ impl SequenceBuilder {
};
if character.chars().count() == 1 {
- let character = character.chars().next().unwrap();
- let base_character = character.to_lowercase().next().unwrap();
+ let shift = self.modifiers.contains(SequenceModifiers::SHIFT);
- let alternate_key_code = u32::from(character);
- let mut unicode_key_code = u32::from(base_character);
+ let ch = character.chars().next().unwrap();
+ let unshifted_ch = if shift { ch.to_lowercase().next().unwrap() } else { ch };
+
+ let alternate_key_code = u32::from(ch);
+ let mut unicode_key_code = u32::from(unshifted_ch);
// Try to get the base for keys which change based on modifier, like `1` for `!`.
- match key.key_without_modifiers().as_ref() {
- Key::Character(unmodded) if alternate_key_code == unicode_key_code => {
- unicode_key_code = u32::from(unmodded.chars().next().unwrap_or(base_character));
- },
- _ => (),
+ //
+ // However it should only be performed when `SHIFT` is pressed.
+ if shift && alternate_key_code == unicode_key_code {
+ if let Key::Character(unmodded) = key.key_without_modifiers().as_ref() {
+ unicode_key_code = u32::from(unmodded.chars().next().unwrap_or(unshifted_ch));
+ }
}
// NOTE: Base layouts are ignored, since winit doesn't expose this information
diff --git a/alacritty/src/input/mod.rs b/alacritty/src/input/mod.rs
index 60a50529..3f85512f 100644
--- a/alacritty/src/input/mod.rs
+++ b/alacritty/src/input/mod.rs
@@ -324,7 +324,10 @@ impl<T: EventListener> Execute<T> for Action {
#[cfg(not(target_os = "macos"))]
Action::Hide => ctx.window().set_visible(false),
Action::Minimize => ctx.window().set_minimized(true),
- Action::Quit => ctx.terminal_mut().exit(),
+ Action::Quit => {
+ ctx.window().hold = false;
+ ctx.terminal_mut().exit();
+ },
Action::IncreaseFontSize => ctx.change_font_size(FONT_SIZE_STEP),
Action::DecreaseFontSize => ctx.change_font_size(-FONT_SIZE_STEP),
Action::ResetFontSize => ctx.reset_font_size(),
diff --git a/alacritty/src/ipc.rs b/alacritty/src/ipc.rs
index 3d14c4ce..919035a6 100644
--- a/alacritty/src/ipc.rs
+++ b/alacritty/src/ipc.rs
@@ -19,7 +19,10 @@ use crate::event::{Event, EventType};
const ALACRITTY_SOCKET_ENV: &str = "ALACRITTY_SOCKET";
/// Create an IPC socket.
-pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -> Option<PathBuf> {
+pub fn spawn_ipc_socket(
+ options: &Options,
+ event_proxy: EventLoopProxy<Event>,
+) -> IoResult<PathBuf> {
// Create the IPC socket and export its path as env.
let socket_path = options.socket.clone().unwrap_or_else(|| {
@@ -28,13 +31,7 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -
path
});
- let listener = match UnixListener::bind(&socket_path) {
- Ok(listener) => listener,
- Err(err) => {
- warn!("Unable to create socket: {:?}", err);
- return None;
- },
- };
+ let listener = UnixListener::bind(&socket_path)?;
env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str());
if options.daemon {
@@ -80,7 +77,7 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -
}
});
- Some(socket_path)
+ Ok(socket_path)
}
/// Send a message to the active Alacritty socket.
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 6bbf8dfd..9260bfa4 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -55,6 +55,8 @@ mod gl {
#[cfg(unix)]
use crate::cli::MessageOptions;
+#[cfg(not(any(target_os = "macos", windows)))]
+use crate::cli::SocketMessage;
use crate::cli::{Options, Subcommands};
use crate::config::monitor::ConfigMonitor;
use crate::config::UiConfig;
@@ -89,7 +91,13 @@ fn main() -> Result<(), Box<dyn Error>> {
/// `msg` subcommand entrypoint.
#[cfg(unix)]
-fn msg(options: MessageOptions) -> Result<(), Box<dyn Error>> {
+#[allow(unused_mut)]
+fn msg(mut options: MessageOptions) -> Result<(), Box<dyn Error>> {
+ #[cfg(not(any(target_os = "macos", windows)))]
+ if let SocketMessage::CreateWindow(window_options) = &mut options.message {
+ window_options.activation_token =
+ env::var("XDG_ACTIVATION_TOKEN").or_else(|_| env::var("DESKTOP_STARTUP_ID")).ok();
+ }
ipc::send_message(options.socket, options.message).map_err(|err| err.into())
}
@@ -175,7 +183,14 @@ fn alacritty(mut options: Options) -> Result<(), Box<dyn Error>> {
// Create the IPC socket listener.
#[cfg(unix)]
let socket_path = if config.ipc_socket() {
- ipc::spawn_ipc_socket(&options, window_event_loop.create_proxy())
+ match ipc::spawn_ipc_socket(&options, window_event_loop.create_proxy()) {
+ Ok(path) => Some(path),
+ Err(err) if options.daemon => return Err(err.into()),
+ Err(err) => {
+ log::warn!("Unable to create socket: {:?}", err);
+ None
+ },
+ }
} else {
None
};
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index a1ffb311..ce6b0914 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -9,7 +9,7 @@ use ahash::RandomState;
use crossfont::Metrics;
use glutin::context::{ContextApi, GlContext, PossiblyCurrentContext};
use glutin::display::{GetGlDisplay, GlDisplay};
-use log::{debug, error, info, warn, LevelFilter};
+use log::{debug, info, LevelFilter};
use unicode_width::UnicodeWidthChar;
use alacritty_terminal::graphics::UpdateQueues;
@@ -101,6 +101,7 @@ pub struct Renderer {
text_renderer: TextRendererProvider,
rect_renderer: RectRenderer,
graphics_renderer: GraphicsRenderer,
+ robustness: bool,
}
/// Wrapper around gl::GetString with error checking and reporting.
@@ -148,6 +149,9 @@ impl Renderer {
info!("Running on {renderer}");
info!("OpenGL version {gl_version}, shader_version {shader_version}");
+ // Check if robustness is supported.
+ let robustness = Self::supports_robustness();
+
let is_gles_context = matches!(context.context_api(), ContextApi::Gles(_));
// Use the config option to enforce a particular renderer configuration.
@@ -181,7 +185,7 @@ impl Renderer {
}
}
- Ok(Self { text_renderer, rect_renderer, graphics_renderer })
+ Ok(Self { text_renderer, rect_renderer, graphics_renderer, robustness })
}
pub fn draw_cells<I: Iterator<Item = RenderableCell>>(
@@ -212,10 +216,10 @@ impl Renderer {
glyph_cache: &mut GlyphCache,
) {
let mut wide_char_spacer = false;
- let cells = string_chars.enumerate().map(|(i, character)| {
+ let cells = string_chars.enumerate().filter_map(|(i, character)| {
let flags = if wide_char_spacer {
wide_char_spacer = false;
- Flags::WIDE_CHAR_SPACER
+ return None;
} else if character.width() == Some(2) {
// The spacer is always following the wide char.
wide_char_spacer = true;
@@ -224,7 +228,7 @@ impl Renderer {
Flags::empty()
};
- RenderableCell {
+ Some(RenderableCell {
point: Point::new(point.line, point.column + i),
character,
extra: None,
@@ -233,7 +237,7 @@ impl Renderer {
fg,
bg,
underline: fg,
- }
+ })
});
self.draw_cells(size_info, glyph_cache, cells);
@@ -287,6 +291,49 @@ impl Renderer {
}
}
+ /// Get the context reset status.
+ pub fn was_context_reset(&self) -> bool {
+ // If robustness is not supported, don't use its functions.
+ if !self.robustness {
+ return false;
+ }
+
+ let status = unsafe { gl::GetGraphicsResetStatus() };
+ if status == gl::NO_ERROR {
+ false
+ } else {
+ let reason = match status {
+ gl::GUILTY_CONTEXT_RESET_KHR => "guilty",
+ gl::INNOCENT_CONTEXT_RESET_KHR => "innocent",
+ gl::UNKNOWN_CONTEXT_RESET_KHR => "unknown",
+ _ => "invalid",
+ };
+
+ info!("GPU reset ({})", reason);
+
+ true
+ }
+ }
+
+ fn supports_robustness() -> bool {
+ let mut notification_strategy = 0;
+ if GlExtensions::contains("GL_KHR_robustness") {
+ unsafe {
+ gl::GetIntegerv(gl::RESET_NOTIFICATION_STRATEGY_KHR, &mut notification_strategy);
+ }
+ } else {
+ notification_strategy = gl::NO_RESET_NOTIFICATION_KHR as gl::types::GLint;
+ }
+
+ if notification_strategy == gl::LOSE_CONTEXT_ON_RESET_KHR as gl::types::GLint {
+ info!("GPU reset notifications are enabled");
+ true
+ } else {
+ info!("GPU reset notifications are disabled");
+ false
+ }
+ }
+
pub fn finish(&self) {
unsafe {
gl::Finish();
@@ -387,7 +434,7 @@ impl GlExtensions {
extern "system" fn gl_debug_log(
_: gl::types::GLenum,
- kind: gl::types::GLenum,
+ _: gl::types::GLenum,
_: gl::types::GLuint,
_: gl::types::GLenum,
_: gl::types::GLsizei,
@@ -395,11 +442,5 @@ extern "system" fn gl_debug_log(
_: *mut std::os::raw::c_void,
) {
let msg = unsafe { CStr::from_ptr(msg).to_string_lossy() };
- match kind {
- gl::DEBUG_TYPE_ERROR | gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => {
- error!("[gl_render] {}", msg)
- },
- gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!("[gl_render] {}", msg),
- _ => debug!("[gl_render] {}", msg),
- }
+ debug!("[gl_render] {}", msg);
}
diff --git a/alacritty/src/renderer/platform.rs b/alacritty/src/renderer/platform.rs
index 87ed29c2..3b2e2fce 100644
--- a/alacritty/src/renderer/platform.rs
+++ b/alacritty/src/renderer/platform.rs
@@ -4,9 +4,9 @@ use std::num::NonZeroU32;
use glutin::config::{ColorBufferType, Config, ConfigTemplateBuilder, GetGlConfig};
use glutin::context::{
- ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentContext, Version,
+ ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentContext, Robustness, Version,
};
-use glutin::display::{Display, DisplayApiPreference, GetGlDisplay};
+use glutin::display::{Display, DisplayApiPreference, DisplayFeatures, GetGlDisplay};
use glutin::error::Result as GlutinResult;
use glutin::prelude::*;
use glutin::surface::{Surface, SurfaceAttributesBuilder, WindowSurface};
@@ -110,18 +110,24 @@ pub fn create_gl_context(
raw_window_handle: Option<RawWindowHandle>,
) -> GlutinResult<NotCurrentContext> {
let debug = log::max_level() >= LevelFilter::Debug;
+ let mut builder = ContextAttributesBuilder::new().with_debug(debug);
+
+ // Try to enable robustness.
+ if gl_display.supported_features().contains(DisplayFeatures::CONTEXT_ROBUSTNESS) {
+ builder = builder.with_robustness(Robustness::RobustLoseContextOnReset);
+ }
+
let mut profiles = [
- ContextAttributesBuilder::new()
- .with_debug(debug)
+ builder
+ .clone()
.with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3))))
.build(raw_window_handle),
// Try gles before OpenGL 2.1 as it tends to be more stable.
- ContextAttributesBuilder::new()
- .with_debug(debug)
+ builder
+ .clone()
.with_context_api(ContextApi::Gles(Some(Version::new(2, 0))))
.build(raw_window_handle),
- ContextAttributesBuilder::new()
- .with_debug(debug)
+ builder
.with_profile(GlProfile::Compatibility)
.with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1))))
.build(raw_window_handle),
diff --git a/alacritty/src/window_context.rs b/alacritty/src/window_context.rs
index cfc3cd96..a0e66cc0 100644
--- a/alacritty/src/window_context.rs
+++ b/alacritty/src/window_context.rs
@@ -73,7 +73,7 @@ impl WindowContext {
event_loop: &ActiveEventLoop,
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
- options: WindowOptions,
+ mut options: WindowOptions,
) -> Result<Self, Box<dyn Error>> {
let raw_display_handle = event_loop.display_handle().unwrap().as_raw();
@@ -83,7 +83,7 @@ impl WindowContext {
// Windows has different order of GL platform initialization compared to any other platform;
// it requires the window first.
#[cfg(windows)]
- let window = Window::new(event_loop, &config, &identity)?;
+ let window = Window::new(event_loop, &config, &identity, &mut options)?;
#[cfg(windows)]
let raw_window_handle = Some(window.raw_window_handle());
@@ -102,10 +102,9 @@ impl WindowContext {
event_loop,
&config,
&identity,
+ &mut options,
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
gl_config.x11_visual(),
- #[cfg(target_os = "macos")]
- &options.window_tabbing_id,
)?;
// Create context.
@@ -123,7 +122,7 @@ impl WindowContext {
event_loop: &ActiveEventLoop,
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
- options: WindowOptions,
+ mut options: WindowOptions,
config_overrides: ParsedOptions,
) -> Result<Self, Box<dyn Error>> {
let gl_display = gl_config.display();
@@ -135,10 +134,9 @@ impl WindowContext {
event_loop,
&config,
&identity,
+ &mut options,
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
gl_config.x11_visual(),
- #[cfg(target_os = "macos")]
- &options.window_tabbing_id,
)?;
// Create context.
@@ -214,7 +212,7 @@ impl WindowContext {
Arc::clone(&terminal),
event_proxy.clone(),
pty,
- pty_config.hold,
+ pty_config.drain_on_exit,
config.debug.ref_test,
)?;