aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src')
-rw-r--r--alacritty/src/clipboard.rs19
-rw-r--r--alacritty/src/display/mod.rs48
-rw-r--r--alacritty/src/display/window.rs93
-rw-r--r--alacritty/src/event.rs183
-rw-r--r--alacritty/src/input.rs2
-rw-r--r--alacritty/src/main.rs2
-rw-r--r--alacritty/src/renderer/mod.rs1
-rw-r--r--alacritty/src/renderer/platform.rs2
-rw-r--r--alacritty/src/window_context.rs111
9 files changed, 194 insertions, 267 deletions
diff --git a/alacritty/src/clipboard.rs b/alacritty/src/clipboard.rs
index dd0a8348..35982cf5 100644
--- a/alacritty/src/clipboard.rs
+++ b/alacritty/src/clipboard.rs
@@ -1,7 +1,5 @@
-#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use std::ffi::c_void;
-
use log::{debug, warn};
+use winit::window::raw_window_handle::RawDisplayHandle;
use alacritty_terminal::term::ClipboardType;
@@ -21,20 +19,15 @@ pub struct Clipboard {
}
impl Clipboard {
- #[cfg(any(not(feature = "wayland"), target_os = "macos", windows))]
- pub fn new() -> Self {
- Self::default()
- }
-
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- pub unsafe fn new(display: Option<*mut c_void>) -> Self {
+ pub unsafe fn new(display: RawDisplayHandle) -> Self {
match display {
- Some(display) => {
+ #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
+ RawDisplayHandle::Wayland(display) => {
let (selection, clipboard) =
- wayland_clipboard::create_clipboards_from_external(display);
+ wayland_clipboard::create_clipboards_from_external(display.display);
Self { clipboard: Box::new(clipboard), selection: Some(Box::new(selection)) }
},
- None => Self::default(),
+ _ => Self::default(),
}
}
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index c992e9cc..4037cd2e 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -6,7 +6,6 @@ use std::fmt::{self, Formatter};
use std::mem::{self, ManuallyDrop};
use std::num::NonZeroU32;
use std::ops::{Deref, DerefMut};
-use std::sync::atomic::Ordering;
use std::time::{Duration, Instant};
use glutin::context::{NotCurrentContext, PossiblyCurrentContext};
@@ -15,10 +14,10 @@ use glutin::surface::{Rect as DamageRect, Surface, SwapInterval, WindowSurface};
use log::{debug, info};
use parking_lot::MutexGuard;
-use raw_window_handle::RawWindowHandle;
use serde::{Deserialize, Serialize};
use winit::dpi::PhysicalSize;
use winit::keyboard::ModifiersState;
+use winit::window::raw_window_handle::RawWindowHandle;
use winit::window::CursorIcon;
use crossfont::{self, Rasterize, Rasterizer};
@@ -347,7 +346,7 @@ pub struct Display {
/// Hint highlighted by the vi mode cursor.
pub vi_highlighted_hint: Option<HintMatch>,
- pub is_wayland: bool,
+ pub raw_window_handle: RawWindowHandle,
/// UI cursor visibility for blinking.
pub cursor_hidden: bool,
@@ -394,7 +393,7 @@ impl Display {
gl_context: NotCurrentContext,
config: &UiConfig,
) -> Result<Display, Error> {
- let is_wayland = matches!(window.raw_window_handle(), RawWindowHandle::Wayland(_));
+ let raw_window_handle = window.raw_window_handle();
let scale_factor = window.scale_factor as f32;
let rasterizer = Rasterizer::new(scale_factor)?;
@@ -408,7 +407,7 @@ impl Display {
// Resize the window to account for the user configured size.
if let Some(dimensions) = config.window.dimensions() {
let size = window_size(config, dimensions, cell_width, cell_height, scale_factor);
- window.set_inner_size(size);
+ window.request_inner_size(size);
}
// Create the GL surface to draw into.
@@ -459,9 +458,10 @@ impl Display {
#[cfg(target_os = "macos")]
window.set_has_shadow(config.window_opacity() >= 1.0);
+ let is_wayland = matches!(raw_window_handle, RawWindowHandle::Wayland(_));
+
// On Wayland we can safely ignore this call, since the window isn't visible until you
// actually draw something into it and commit those changes.
- #[cfg(not(any(target_os = "macos", windows)))]
if !is_wayland {
surface.swap_buffers(&context).expect("failed to swap buffers.");
renderer.finish();
@@ -479,7 +479,6 @@ impl Display {
match config.window.startup_mode {
#[cfg(target_os = "macos")]
StartupMode::SimpleFullscreen => window.set_simple_fullscreen(true),
- #[cfg(not(any(target_os = "macos", windows)))]
StartupMode::Maximized if !is_wayland => window.set_maximized(true),
_ => (),
}
@@ -511,7 +510,6 @@ impl Display {
ime: Ime::new(),
highlighted_hint: None,
vi_highlighted_hint: None,
- is_wayland,
cursor_hidden: false,
frame_timer: FrameTimer::new(),
visual_bell: VisualBell::from(&config.bell),
@@ -520,6 +518,7 @@ impl Display {
pending_renderer_update: Default::default(),
debug_damage,
damage_rects,
+ raw_window_handle,
next_frame_damage_rects,
hint_mouse_point: None,
})
@@ -552,7 +551,8 @@ impl Display {
let res = match (self.surface.deref(), &self.context.get()) {
#[cfg(not(any(target_os = "macos", windows)))]
(Surface::Egl(surface), PossiblyCurrentContext::Egl(context))
- if self.is_wayland && !self.debug_damage =>
+ if matches!(self.raw_window_handle, RawWindowHandle::Wayland(_))
+ && !self.debug_damage =>
{
surface.swap_buffers_with_damage(context, &self.damage_rects)
},
@@ -972,17 +972,13 @@ impl Display {
self.draw_hyperlink_preview(config, cursor_point, display_offset);
}
- // Frame event should be requested before swapping buffers on Wayland, since it requires
- // surface `commit`, which is done by swap buffers under the hood.
- if self.is_wayland {
- self.request_frame(scheduler);
- }
+ // Notify winit that we're about to present.
+ self.window.pre_present_notify();
// Clearing debug highlights from the previous frame requires full redraw.
self.swap_buffers();
- #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
- if !self.is_wayland {
+ if matches!(self.raw_window_handle, RawWindowHandle::Xcb(_) | RawWindowHandle::Xlib(_)) {
// On X11 `swap_buffers` does not block for vsync. However the next OpenGl command
// will block to synchronize (this is `glClear` in Alacritty), which causes a
// permanent one frame delay.
@@ -991,7 +987,10 @@ impl Display {
// XXX: Request the new frame after swapping buffers, so the
// time to finish OpenGL operations is accounted for in the timeout.
- if !self.is_wayland {
+ if matches!(
+ self.raw_window_handle,
+ RawWindowHandle::AppKit(_) | RawWindowHandle::Xlib(_) | RawWindowHandle::Xcb(_)
+ ) {
self.request_frame(scheduler);
}
@@ -1364,7 +1363,7 @@ impl Display {
/// Returns `true` if damage information should be collected, `false` otherwise.
#[inline]
fn collect_damage(&self) -> bool {
- self.is_wayland || self.debug_damage
+ matches!(self.raw_window_handle, RawWindowHandle::Wayland(_)) || self.debug_damage
}
/// Highlight damaged rects.
@@ -1385,18 +1384,7 @@ impl Display {
/// Requst a new frame for a window on Wayland.
fn request_frame(&mut self, scheduler: &mut Scheduler) {
// Mark that we've used a frame.
- self.window.has_frame.store(false, Ordering::Relaxed);
-
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- if let Some(surface) = self.window.wayland_surface() {
- let has_frame = self.window.has_frame.clone();
- // Request a new frame.
- surface.frame().quick_assign(move |_, _, _| {
- has_frame.store(true, Ordering::Relaxed);
- });
-
- return;
- }
+ self.window.has_frame = false;
// Get the display vblank interval.
let monitor_vblank_interval = 1_000_000.
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 0cf95f7f..942b28ee 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -1,11 +1,3 @@
-#[rustfmt::skip]
-#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use {
- wayland_client::protocol::wl_surface::WlSurface,
- wayland_client::{Attached, EventQueue, Proxy},
- winit::platform::wayland::{EventLoopWindowTargetExtWayland, WindowExtWayland},
-};
-
#[cfg(all(not(feature = "x11"), not(any(target_os = "macos", windows))))]
use winit::platform::wayland::WindowBuilderExtWayland;
@@ -13,8 +5,8 @@ use winit::platform::wayland::WindowBuilderExtWayland;
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
use {
std::io::Cursor,
-
- winit::platform::x11::{WindowExtX11, WindowBuilderExtX11},
+ winit::platform::x11::{WindowBuilderExtX11, EventLoopWindowTargetExtX11},
+ winit::window::raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle},
glutin::platform::x11::X11VisualInfo,
x11_dl::xlib::{Display as XDisplay, PropModeReplace, XErrorEvent, Xlib},
winit::window::Icon,
@@ -22,8 +14,6 @@ use {
};
use std::fmt::{self, Display, Formatter};
-use std::sync::atomic::AtomicBool;
-use std::sync::Arc;
#[cfg(target_os = "macos")]
use {
@@ -33,13 +23,12 @@ use {
winit::platform::macos::{OptionAsAlt, WindowBuilderExtMacOS, WindowExtMacOS},
};
-use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
-
use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::event_loop::EventLoopWindowTarget;
use winit::monitor::MonitorHandle;
#[cfg(windows)]
use winit::platform::windows::IconExtWindows;
+use winit::window::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use winit::window::{
CursorIcon, Fullscreen, ImePurpose, UserAttentionType, Window as WinitWindow, WindowBuilder,
WindowId,
@@ -107,15 +96,14 @@ impl From<crossfont::Error> for Error {
/// Wraps the underlying windowing library to provide a stable API in Alacritty.
pub struct Window {
/// Flag tracking that we have a frame we can draw.
- pub has_frame: Arc<AtomicBool>,
-
- /// Attached Wayland surface to request new frame events.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- pub wayland_surface: Option<Attached<WlSurface>>,
+ pub has_frame: bool,
/// Cached scale factor for quickly scaling pixel sizes.
pub scale_factor: f64,
+ /// Flag indicating whether redraw was requested.
+ pub requested_redraw: bool,
+
window: WinitWindow,
/// Current window title.
@@ -133,8 +121,6 @@ impl Window {
event_loop: &EventLoopWindowTarget<E>,
config: &UiConfig,
identity: &Identity,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue: Option<&EventQueue>,
#[rustfmt::skip]
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
x11_visual: Option<X11VisualInfo>,
@@ -161,12 +147,6 @@ impl Window {
.with_fullscreen(config.window.fullscreen())
.build(event_loop)?;
- // Check if we're running Wayland to disable vsync.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- let is_wayland = event_loop.is_wayland();
- #[cfg(all(not(feature = "wayland"), not(any(target_os = "macos", windows))))]
- let is_wayland = false;
-
// Text cursor.
let current_mouse_cursor = CursorIcon::Text;
window.set_cursor_icon(current_mouse_cursor);
@@ -181,35 +161,23 @@ impl Window {
#[cfg(target_os = "macos")]
use_srgb_color_space(&window);
+ // On X11, embed the window inside another if the parent ID has been set.
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
- if !is_wayland {
- // On X11, embed the window inside another if the parent ID has been set.
- if let Some(parent_window_id) = config.window.embed {
- x_embed_window(&window, parent_window_id);
- }
+ if let Some(parent_window_id) = event_loop.is_x11().then_some(config.window.embed).flatten()
+ {
+ x_embed_window(&window, parent_window_id);
}
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- let wayland_surface = if is_wayland {
- // Attach surface to Alacritty's internal wayland queue to handle frame callbacks.
- let surface = window.wayland_surface().unwrap();
- let proxy: Proxy<WlSurface> = unsafe { Proxy::from_c_ptr(surface as _) };
- Some(proxy.attach(wayland_event_queue.as_ref().unwrap().token()))
- } else {
- None
- };
-
let scale_factor = window.scale_factor();
log::info!("Window scale factor: {}", scale_factor);
Ok(Self {
current_mouse_cursor,
mouse_visible: true,
+ requested_redraw: false,
window,
title: identity.title,
- has_frame: Arc::new(AtomicBool::new(true)),
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_surface,
+ has_frame: true,
scale_factor,
})
}
@@ -220,8 +188,8 @@ impl Window {
}
#[inline]
- pub fn set_inner_size(&self, size: PhysicalSize<u32>) {
- self.window.set_inner_size(size);
+ pub fn request_inner_size(&self, size: PhysicalSize<u32>) {
+ let _ = self.window.request_inner_size(size);
}
#[inline]
@@ -248,8 +216,11 @@ impl Window {
}
#[inline]
- pub fn request_redraw(&self) {
- self.window.request_redraw();
+ pub fn request_redraw(&mut self) {
+ if !self.requested_redraw {
+ self.requested_redraw = true;
+ self.window.request_redraw();
+ }
}
#[inline]
@@ -296,7 +267,7 @@ impl Window {
#[cfg(feature = "x11")]
let builder = match x11_visual {
- Some(visual) => builder.with_x11_visual(visual.into_raw()),
+ Some(visual) => builder.with_x11_visual(visual.visual_id() as u32),
None => builder,
};
@@ -367,6 +338,13 @@ impl Window {
self.set_maximized(!self.window.is_maximized());
}
+ /// Inform windowing system about presenting to the window.
+ ///
+ /// Should be called right before presenting to the window with e.g. `eglSwapBuffers`.
+ pub fn pre_present_notify(&self) {
+ self.window.pre_present_notify();
+ }
+
#[cfg(target_os = "macos")]
pub fn toggle_simple_fullscreen(&self) {
self.set_simple_fullscreen(!self.window.simple_fullscreen());
@@ -394,11 +372,6 @@ impl Window {
self.window.set_simple_fullscreen(simple_fullscreen);
}
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- pub fn wayland_surface(&self) -> Option<&Attached<WlSurface>> {
- self.wayland_surface.as_ref()
- }
-
pub fn set_ime_allowed(&self, allowed: bool) {
self.window.set_ime_allowed(allowed);
}
@@ -437,8 +410,12 @@ impl Window {
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
fn x_embed_window(window: &WinitWindow, parent_id: std::os::raw::c_ulong) {
- let (xlib_display, xlib_window) = match (window.xlib_display(), window.xlib_window()) {
- (Some(display), Some(window)) => (display, window),
+ let xlib_display = window.raw_display_handle();
+ let xlib_window = window.raw_window_handle();
+ let (xlib_display, xlib_window) = match (xlib_display, xlib_window) {
+ (RawDisplayHandle::Xlib(display), RawWindowHandle::Xlib(window)) => {
+ (display.display, window.window)
+ },
_ => return,
};
@@ -448,7 +425,7 @@ fn x_embed_window(window: &WinitWindow, parent_id: std::os::raw::c_ulong) {
let atom = (xlib.XInternAtom)(xlib_display as *mut _, "_XEMBED".as_ptr() as *const _, 0);
(xlib.XChangeProperty)(
xlib_display as _,
- xlib_window as _,
+ xlib_window,
atom,
atom,
32,
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index add30722..6717e0ab 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -10,15 +10,12 @@ use std::fmt::Debug;
use std::os::unix::io::RawFd;
use std::path::PathBuf;
use std::rc::Rc;
-use std::sync::atomic::Ordering;
use std::time::{Duration, Instant};
use std::{env, f32, mem};
use ahash::RandomState;
+use crossfont::{self, Size};
use log::{debug, error, info, warn};
-#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use wayland_client::{Display as WaylandDisplay, EventQueue};
-use winit::dpi::PhysicalSize;
use winit::event::{
ElementState, Event as WinitEvent, Ime, Modifiers, MouseButton, StartCause,
Touch as TouchEvent, WindowEvent,
@@ -26,13 +23,9 @@ use winit::event::{
use winit::event_loop::{
ControlFlow, DeviceEvents, EventLoop, EventLoopProxy, EventLoopWindowTarget,
};
-use winit::platform::run_return::EventLoopExtRunReturn;
-#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use winit::platform::wayland::EventLoopWindowTargetExtWayland;
+use winit::window::raw_window_handle::HasRawDisplayHandle;
use winit::window::WindowId;
-use crossfont::{self, Size};
-
use alacritty_terminal::config::LOG_TARGET_CONFIG;
use alacritty_terminal::event::{Event as TerminalEvent, EventListener, Notify};
use alacritty_terminal::event_loop::Notifier;
@@ -87,7 +80,7 @@ impl Event {
}
}
-impl From<Event> for WinitEvent<'_, Event> {
+impl From<Event> for WinitEvent<Event> {
fn from(event: Event) -> Self {
WinitEvent::UserEvent(event)
}
@@ -96,7 +89,6 @@ impl From<Event> for WinitEvent<'_, Event> {
/// Alacritty events.
#[derive(Debug, Clone)]
pub enum EventType {
- ScaleFactorChanged(f64, (u32, u32)),
Terminal(TerminalEvent),
ConfigReload(PathBuf),
Message(Message),
@@ -1178,30 +1170,9 @@ pub struct AccumulatedScroll {
impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
/// Handle events from winit.
- pub fn handle_event(&mut self, event: WinitEvent<'_, Event>) {
+ pub fn handle_event(&mut self, event: WinitEvent<Event>) {
match event {
WinitEvent::UserEvent(Event { payload, .. }) => match payload {
- EventType::ScaleFactorChanged(scale_factor, (width, height)) => {
- self.ctx.window().scale_factor = scale_factor;
-
- let display_update_pending = &mut self.ctx.display.pending_update;
-
- // Push current font to update its scale factor.
- let font = self.ctx.config.font.clone();
- display_update_pending.set_font(font.with_size(*self.ctx.font_size));
-
- // Ignore resize events to zero in any dimension, to avoid issues with Winit
- // and the ConPTY. A 0x0 resize will also occur when the window is minimized
- // on Windows.
- if width != 0 && height != 0 {
- // Resize to event's dimensions, since no resize event is emitted on
- // Wayland.
- display_update_pending.set_dimensions(PhysicalSize::new(width, height));
- }
- },
- EventType::Frame => {
- self.ctx.display.window.has_frame.store(true, Ordering::Relaxed);
- },
EventType::SearchNext => self.ctx.goto_match(None),
EventType::Scroll(scroll) => self.ctx.scroll(scroll),
EventType::BlinkCursor => {
@@ -1233,7 +1204,6 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
self.ctx.display.window.set_title(window_config.identity.title.clone());
}
},
- TerminalEvent::Wakeup => *self.ctx.dirty = true,
TerminalEvent::Bell => {
// Set window urgency hint when window is not focused.
let focused = self.ctx.terminal.is_focused;
@@ -1271,18 +1241,28 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
},
TerminalEvent::PtyWrite(text) => self.ctx.write_to_pty(text.into_bytes()),
TerminalEvent::MouseCursorDirty => self.reset_mouse_cursor(),
- TerminalEvent::Exit => (),
TerminalEvent::CursorBlinkingChange => self.ctx.update_cursor_blinking(),
+ TerminalEvent::Exit | TerminalEvent::Wakeup => (),
},
#[cfg(unix)]
EventType::IpcConfig(_) => (),
- EventType::ConfigReload(_) | EventType::CreateWindow(_) | EventType::Message(_) => {
- },
+ EventType::Message(_)
+ | EventType::ConfigReload(_)
+ | EventType::CreateWindow(_)
+ | EventType::Frame => (),
},
- WinitEvent::RedrawRequested(_) => *self.ctx.dirty = true,
WinitEvent::WindowEvent { event, .. } => {
match event {
WindowEvent::CloseRequested => self.ctx.terminal.exit(),
+ WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
+ self.ctx.window().scale_factor = scale_factor;
+
+ let display_update_pending = &mut self.ctx.display.pending_update;
+
+ // Push current font to update its scale factor.
+ let font = self.ctx.config.font.clone();
+ display_update_pending.set_font(font.with_size(*self.ctx.font_size));
+ },
WindowEvent::Resized(size) => {
// Ignore resize events to zero in any dimension, to avoid issues with Winit
// and the ConPTY. A 0x0 resize will also occur when the window is minimized
@@ -1370,11 +1350,11 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
},
},
WindowEvent::KeyboardInput { is_synthetic: true, .. }
+ | WindowEvent::ActivationTokenDone { .. }
| WindowEvent::TouchpadPressure { .. }
| WindowEvent::TouchpadMagnify { .. }
| WindowEvent::TouchpadRotate { .. }
| WindowEvent::SmartMagnify { .. }
- | WindowEvent::ScaleFactorChanged { .. }
| WindowEvent::CursorEntered { .. }
| WindowEvent::AxisMotion { .. }
| WindowEvent::HoveredFileCancelled
@@ -1387,10 +1367,10 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
WinitEvent::Suspended { .. }
| WinitEvent::NewEvents { .. }
| WinitEvent::DeviceEvent { .. }
- | WinitEvent::MainEventsCleared
- | WinitEvent::RedrawEventsCleared
+ | WinitEvent::LoopExiting
| WinitEvent::Resumed
- | WinitEvent::LoopDestroyed => (),
+ | WinitEvent::AboutToWait
+ | WinitEvent::RedrawRequested(_) => (),
}
}
}
@@ -1400,8 +1380,6 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
/// Stores some state from received events and dispatches actions when they are
/// triggered.
pub struct Processor {
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue: Option<EventQueue>,
windows: HashMap<WindowId, WindowContext, RandomState>,
#[cfg(unix)]
global_ipc_options: Vec<String>,
@@ -1418,21 +1396,12 @@ impl Processor {
cli_options: CliOptions,
_event_loop: &EventLoop<Event>,
) -> Processor {
- // Initialize Wayland event queue, to handle Wayland callbacks.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- let wayland_event_queue = _event_loop.wayland_display().map(|display| {
- let display = unsafe { WaylandDisplay::from_external_display(display as _) };
- display.create_event_queue()
- });
-
Processor {
- config: Rc::new(config),
cli_options,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue,
+ config: Rc::new(config),
+ windows: Default::default(),
#[cfg(unix)]
global_ipc_options: Default::default(),
- windows: Default::default(),
}
}
@@ -1446,14 +1415,8 @@ impl Processor {
proxy: EventLoopProxy<Event>,
options: WindowOptions,
) -> Result<(), Box<dyn Error>> {
- let window_context = WindowContext::initial(
- event_loop,
- proxy,
- self.config.clone(),
- options,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- self.wayland_event_queue.as_ref(),
- )?;
+ let window_context =
+ WindowContext::initial(event_loop, proxy, self.config.clone(), options)?;
self.windows.insert(window_context.id(), window_context);
@@ -1470,14 +1433,8 @@ impl Processor {
let window = self.windows.iter().next().as_ref().unwrap().1;
#[allow(unused_mut)]
- let mut window_context = window.additional(
- event_loop,
- proxy,
- self.config.clone(),
- options,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- self.wayland_event_queue.as_ref(),
- )?;
+ let mut window_context =
+ window.additional(event_loop, proxy, self.config.clone(), options)?;
// Apply global IPC options.
#[cfg(unix)]
@@ -1496,7 +1453,7 @@ impl Processor {
/// The result is exit code generate from the loop.
pub fn run(
&mut self,
- mut event_loop: EventLoop<Event>,
+ event_loop: EventLoop<Event>,
initial_window_options: WindowOptions,
) -> Result<(), Box<dyn Error>> {
let proxy = event_loop.create_proxy();
@@ -1504,15 +1461,12 @@ impl Processor {
let mut initial_window_options = Some(initial_window_options);
// NOTE: Since this takes a pointer to the winit event loop, it MUST be dropped first.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- let mut clipboard = unsafe { Clipboard::new(event_loop.wayland_display()) };
- #[cfg(any(not(feature = "wayland"), target_os = "macos", windows))]
- let mut clipboard = Clipboard::new();
+ let mut clipboard = unsafe { Clipboard::new(event_loop.raw_display_handle()) };
// Disable all device events, since we don't care about them.
event_loop.listen_device_events(DeviceEvents::Never);
- let exit_code = event_loop.run_return(move |event, event_loop, control_flow| {
+ let result = event_loop.run(move |event, event_loop, control_flow| {
if self.config.debug.print_events {
info!("winit event: {:?}", event);
}
@@ -1526,8 +1480,8 @@ impl Processor {
// The event loop just got initialized. Create a window.
WinitEvent::Resumed => {
// Creating window inside event loop is required for platforms like macOS to
- // properly initialize state, like tab management. Othwerwise the first window
- // won't handle tabs.
+ // properly initialize state, like tab management. Othwerwise the first
+ // window won't handle tabs.
let initial_window_options = match initial_window_options.take() {
Some(initial_window_options) => initial_window_options,
None => return,
@@ -1546,6 +1500,30 @@ impl Processor {
info!("Initialisation complete");
},
+ // NOTE: This event bypasses batching to minimize input latency.
+ WinitEvent::UserEvent(Event {
+ window_id: Some(window_id),
+ payload: EventType::Terminal(TerminalEvent::Wakeup),
+ }) => {
+ if let Some(window_context) = self.windows.get_mut(&window_id) {
+ window_context.dirty = true;
+ if window_context.display.window.has_frame {
+ window_context.display.window.request_redraw();
+ }
+ }
+ },
+ // NOTE: This event bypasses batching to minimize input latency.
+ WinitEvent::UserEvent(Event {
+ window_id: Some(window_id),
+ payload: EventType::Frame,
+ }) => {
+ if let Some(window_context) = self.windows.get_mut(&window_id) {
+ window_context.display.window.has_frame = true;
+ if window_context.dirty {
+ window_context.display.window.request_redraw();
+ }
+ }
+ },
// Check for shutdown.
WinitEvent::UserEvent(Event {
window_id: Some(window_id),
@@ -1570,16 +1548,24 @@ impl Processor {
*control_flow = ControlFlow::Exit;
}
},
- // Process all pending events.
- WinitEvent::RedrawEventsCleared => {
- // Check for pending frame callbacks on Wayland.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- if let Some(wayland_event_queue) = self.wayland_event_queue.as_mut() {
- wayland_event_queue
- .dispatch_pending(&mut (), |_, _, _| {})
- .expect("failed to dispatch wayland event queue");
- }
+ WinitEvent::RedrawRequested(window_id) => {
+ let window_context = match self.windows.get_mut(&window_id) {
+ Some(window_context) => window_context,
+ None => return,
+ };
+
+ window_context.handle_event(
+ event_loop,
+ &proxy,
+ &mut clipboard,
+ &mut scheduler,
+ WinitEvent::RedrawRequested(window_id),
+ );
+ window_context.draw(&mut scheduler);
+ },
+ // Process all pending events.
+ WinitEvent::AboutToWait => {
// Dispatch event to all windows.
for window_context in self.windows.values_mut() {
window_context.handle_event(
@@ -1587,7 +1573,7 @@ impl Processor {
&proxy,
&mut clipboard,
&mut scheduler,
- WinitEvent::RedrawEventsCleared,
+ WinitEvent::AboutToWait,
);
}
@@ -1644,8 +1630,9 @@ impl Processor {
WinitEvent::UserEvent(Event {
payload: EventType::CreateWindow(options), ..
}) => {
- // XXX Ensure that no context is current when creating a new window, otherwise
- // it may lock the backing buffer of the surface of current context when asking
+ // XXX Ensure that no context is current when creating a new window,
+ // otherwise it may lock the backing buffer of the
+ // surface of current context when asking
// e.g. EGL on Wayland to create a new context.
for window_context in self.windows.values_mut() {
window_context.display.make_not_current();
@@ -1669,8 +1656,7 @@ impl Processor {
},
// Process window-specific events.
WinitEvent::WindowEvent { window_id, .. }
- | WinitEvent::UserEvent(Event { window_id: Some(window_id), .. })
- | WinitEvent::RedrawRequested(window_id) => {
+ | WinitEvent::UserEvent(Event { window_id: Some(window_id), .. }) => {
if let Some(window_context) = self.windows.get_mut(&window_id) {
window_context.handle_event(
event_loop,
@@ -1685,15 +1671,11 @@ impl Processor {
}
});
- if exit_code == 0 {
- Ok(())
- } else {
- Err(format!("Event loop terminated with code: {}", exit_code).into())
- }
+ result.map_err(Into::into)
}
/// Check if an event is irrelevant and can be skipped.
- fn skip_event(event: &WinitEvent<'_, Event>) -> bool {
+ fn skip_event(event: &WinitEvent<Event>) -> bool {
match event {
WinitEvent::NewEvents(StartCause::Init) => false,
WinitEvent::WindowEvent { event, .. } => matches!(
@@ -1709,8 +1691,7 @@ impl Processor {
),
WinitEvent::Suspended { .. }
| WinitEvent::NewEvents { .. }
- | WinitEvent::MainEventsCleared
- | WinitEvent::LoopDestroyed => true,
+ | WinitEvent::LoopExiting => true,
_ => false,
}
}
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 5075729b..54580fa6 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -1325,7 +1325,7 @@ mod tests {
let mut processor = Processor::new(context);
- let event: WinitEvent::<'_, TerminalEvent> = $input;
+ let event: WinitEvent::<TerminalEvent> = $input;
if let WinitEvent::WindowEvent {
event: WindowEvent::MouseInput {
state,
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 55f81502..ea4cd281 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -126,7 +126,7 @@ impl Drop for TemporaryFiles {
/// config change monitor, and runs the main display loop.
fn alacritty(options: Options) -> Result<(), Box<dyn Error>> {
// Setup winit event loop.
- let window_event_loop = WinitEventLoopBuilder::<Event>::with_user_event().build();
+ let window_event_loop = WinitEventLoopBuilder::<Event>::with_user_event().build()?;
// Initialize the logger as soon as possible as to capture output from other subsystems.
let log_file = logging::initialize(&options, window_event_loop.create_proxy())
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index 98e29542..87ccf2f6 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -254,7 +254,6 @@ impl Renderer {
}
}
- #[cfg(not(any(target_os = "macos", windows)))]
pub fn finish(&self) {
unsafe {
gl::Finish();
diff --git a/alacritty/src/renderer/platform.rs b/alacritty/src/renderer/platform.rs
index 10c17cb7..495e837e 100644
--- a/alacritty/src/renderer/platform.rs
+++ b/alacritty/src/renderer/platform.rs
@@ -12,10 +12,10 @@ use glutin::prelude::*;
use glutin::surface::{Surface, SurfaceAttributesBuilder, WindowSurface};
use log::{debug, LevelFilter};
-use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use winit::dpi::PhysicalSize;
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
use winit::platform::x11;
+use winit::window::raw_window_handle::{RawDisplayHandle, RawWindowHandle};
/// Create the GL display.
pub fn create_gl_display(
diff --git a/alacritty/src/window_context.rs b/alacritty/src/window_context.rs
index 8935a9cc..0dd4b4bb 100644
--- a/alacritty/src/window_context.rs
+++ b/alacritty/src/window_context.rs
@@ -7,7 +7,6 @@ use std::mem;
#[cfg(not(windows))]
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::Rc;
-use std::sync::atomic::Ordering;
use std::sync::Arc;
use crossfont::Size;
@@ -17,12 +16,10 @@ use glutin::display::GetGlDisplay;
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
use glutin::platform::x11::X11GlConfigExt;
use log::{error, info};
-use raw_window_handle::HasRawDisplayHandle;
use serde_json as json;
-#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use wayland_client::EventQueue;
-use winit::event::{Event as WinitEvent, Modifiers, WindowEvent};
+use winit::event::{Event as WinitEvent, Modifiers};
use winit::event_loop::{EventLoopProxy, EventLoopWindowTarget};
+use winit::window::raw_window_handle::HasRawDisplayHandle;
use winit::window::WindowId;
use alacritty_config::SerdeReplace;
@@ -42,7 +39,7 @@ use crate::clipboard::Clipboard;
use crate::config::UiConfig;
use crate::display::window::Window;
use crate::display::Display;
-use crate::event::{ActionContext, Event, EventProxy, EventType, Mouse, SearchState, TouchPurpose};
+use crate::event::{ActionContext, Event, EventProxy, Mouse, SearchState, TouchPurpose};
use crate::logging::LOG_TARGET_IPC_CONFIG;
use crate::message_bar::MessageBuffer;
use crate::scheduler::Scheduler;
@@ -52,7 +49,8 @@ use crate::{input, renderer};
pub struct WindowContext {
pub message_buffer: MessageBuffer,
pub display: Display,
- event_queue: Vec<WinitEvent<'static, Event>>,
+ pub dirty: bool,
+ event_queue: Vec<WinitEvent<Event>>,
terminal: Arc<FairMutex<Term<EventProxy>>>,
cursor_blink_timed_out: bool,
modifiers: Modifiers,
@@ -61,7 +59,6 @@ pub struct WindowContext {
font_size: Size,
mouse: Mouse,
touch: TouchPurpose,
- dirty: bool,
occluded: bool,
preserve_title: bool,
#[cfg(not(windows))]
@@ -79,8 +76,6 @@ impl WindowContext {
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
options: WindowOptions,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue: Option<&EventQueue>,
) -> Result<Self, Box<dyn Error>> {
let raw_display_handle = event_loop.raw_display_handle();
@@ -106,8 +101,6 @@ impl WindowContext {
event_loop,
&config,
&identity,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue,
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
gl_config.x11_visual(),
)?;
@@ -126,8 +119,6 @@ impl WindowContext {
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
options: WindowOptions,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue: Option<&EventQueue>,
) -> Result<Self, Box<dyn Error>> {
// Get any window and take its GL config and display to build a new context.
let (gl_display, gl_config) = {
@@ -142,8 +133,6 @@ impl WindowContext {
event_loop,
&config,
&identity,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue,
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
gl_config.x11_visual(),
)?;
@@ -377,6 +366,35 @@ impl WindowContext {
self.update_config(config);
}
+ /// Draw the window.
+ pub fn draw(&mut self, scheduler: &mut Scheduler) {
+ self.display.window.requested_redraw = false;
+
+ if self.occluded {
+ return;
+ }
+
+ self.dirty = false;
+
+ // Force the display to process any pending display update.
+ self.display.process_renderer_update();
+
+ // Request immediate re-draw if visual bell animation is not finished yet.
+ if !self.display.visual_bell.completed() {
+ self.display.window.request_redraw();
+ }
+
+ // Redraw the window.
+ let terminal = self.terminal.lock();
+ self.display.draw(
+ terminal,
+ scheduler,
+ &self.message_buffer,
+ &self.config,
+ &self.search_state,
+ );
+ }
+
/// Process events for this terminal window.
pub fn handle_event(
&mut self,
@@ -384,30 +402,19 @@ impl WindowContext {
event_proxy: &EventLoopProxy<Event>,
clipboard: &mut Clipboard,
scheduler: &mut Scheduler,
- event: WinitEvent<'_, Event>,
+ event: WinitEvent<Event>,
) {
match event {
- // Skip further event handling with no staged updates.
- WinitEvent::RedrawEventsCleared if self.event_queue.is_empty() && !self.dirty => {
- return;
- },
- // Continue to process all pending events.
- WinitEvent::RedrawEventsCleared => (),
- // Remap scale_factor change event to remove the lifetime.
- WinitEvent::WindowEvent {
- event: WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size },
- window_id,
- } => {
- let size = (new_inner_size.width, new_inner_size.height);
- let event =
- Event::new(EventType::ScaleFactorChanged(scale_factor, size), window_id);
- self.event_queue.push(event.into());
- return;
+ WinitEvent::AboutToWait | WinitEvent::RedrawRequested(_) => {
+ // Skip further event handling with no staged updates.
+ if self.event_queue.is_empty() {
+ return;
+ }
+
+ // Continue to process all pending events.
},
- // Transmute to extend lifetime, which exists only for `ScaleFactorChanged` event.
- // Since we remap that event to remove the lifetime, this is safe.
- event => unsafe {
- self.event_queue.push(mem::transmute(event));
+ event => {
+ self.event_queue.push(event);
return;
},
}
@@ -470,30 +477,12 @@ impl WindowContext {
self.mouse.hint_highlight_dirty = false;
}
- // Skip rendering until we get a new frame.
- if !self.display.window.has_frame.load(Ordering::Relaxed) {
- return;
- }
-
- if self.dirty && !self.occluded {
- // Force the display to process any pending display update.
- self.display.process_renderer_update();
-
- self.dirty = false;
-
- // Request immediate re-draw if visual bell animation is not finished yet.
- if !self.display.visual_bell.completed() {
- self.display.window.request_redraw();
- }
-
- // Redraw the window.
- self.display.draw(
- terminal,
- scheduler,
- &self.message_buffer,
- &self.config,
- &self.search_state,
- );
+ // Request a redraw.
+ //
+ // Even though redraw requests are squashed in winit, we try not to
+ // request more if we haven't received a new frame request yet.
+ if self.dirty && !self.occluded && !matches!(event, WinitEvent::RedrawRequested(_)) {
+ self.display.window.request_redraw();
}
}