diff options
Diffstat (limited to 'alacritty/src')
-rw-r--r-- | alacritty/src/clipboard.rs | 19 | ||||
-rw-r--r-- | alacritty/src/display/mod.rs | 48 | ||||
-rw-r--r-- | alacritty/src/display/window.rs | 93 | ||||
-rw-r--r-- | alacritty/src/event.rs | 183 | ||||
-rw-r--r-- | alacritty/src/input.rs | 2 | ||||
-rw-r--r-- | alacritty/src/main.rs | 2 | ||||
-rw-r--r-- | alacritty/src/renderer/mod.rs | 1 | ||||
-rw-r--r-- | alacritty/src/renderer/platform.rs | 2 | ||||
-rw-r--r-- | alacritty/src/window_context.rs | 111 |
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(); } } |