summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--Cargo.lock7
-rw-r--r--alacritty.yml5
-rw-r--r--alacritty/Cargo.toml2
-rw-r--r--alacritty/src/cli.rs51
-rw-r--r--alacritty/src/config/bindings.rs5
-rw-r--r--alacritty/src/config/monitor.rs10
-rw-r--r--alacritty/src/config/ui_config.rs8
-rw-r--r--alacritty/src/display/mod.rs64
-rw-r--r--alacritty/src/display/window.rs68
-rw-r--r--alacritty/src/event.rs831
-rw-r--r--alacritty/src/input.rs36
-rw-r--r--alacritty/src/ipc.rs145
-rw-r--r--alacritty/src/logging.rs21
-rw-r--r--alacritty/src/main.rs210
-rw-r--r--alacritty/src/message_bar.rs35
-rw-r--r--alacritty/src/renderer/mod.rs29
-rw-r--r--alacritty/src/scheduler.rs69
-rw-r--r--alacritty/src/window_context.rs374
-rw-r--r--alacritty_terminal/src/event.rs10
-rw-r--r--alacritty_terminal/src/event_loop.rs6
-rw-r--r--alacritty_terminal/src/term/mod.rs12
-rw-r--r--alacritty_terminal/src/tty/unix.rs42
-rw-r--r--docs/features.md6
-rw-r--r--extra/alacritty-msg.man31
-rw-r--r--extra/alacritty.man9
-rw-r--r--extra/completions/_alacritty74
-rw-r--r--extra/completions/alacritty.bash9
-rw-r--r--extra/completions/alacritty.fish62
29 files changed, 1421 insertions, 811 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f337f601..4f464608 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Option `colors.transparent_background_colors` to allow applying opacity to all background colors
+- Support for running multiple windows from a single Alacritty instance (see docs/features.md)
### Changed
diff --git a/Cargo.lock b/Cargo.lock
index 38a44a21..fee60d82 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1989,9 +1989,12 @@ dependencies = [
[[package]]
name = "xdg"
-version = "2.2.0"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
+checksum = "3a23fe958c70412687039c86f578938b4a0bb50ec788e96bce4d6ab00ddd5803"
+dependencies = [
+ "dirs",
+]
[[package]]
name = "xml-rs"
diff --git a/alacritty.yml b/alacritty.yml
index 04654e56..09abce3c 100644
--- a/alacritty.yml
+++ b/alacritty.yml
@@ -440,6 +440,9 @@
# Send ESC (\x1b) before characters when alt is pressed.
#alt_send_esc: true
+# Offer IPC using `alacritty msg` (unix only)
+#ipc_socket: true
+
#mouse:
# Click settings
#
@@ -595,6 +598,8 @@
# - ToggleFullscreen
# - SpawnNewInstance
# Spawn a new instance of Alacritty.
+# - CreateNewWindow
+# Create a new Alacritty window from the current process.
# - ClearLogNotice
# Clear Alacritty's UI warning and error notice.
# - ClearSelection
diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml
index b1fee0c2..5d02d19c 100644
--- a/alacritty/Cargo.toml
+++ b/alacritty/Cargo.toml
@@ -39,7 +39,7 @@ dirs = "3.0.1"
gl_generator = "0.14.0"
[target.'cfg(not(windows))'.dependencies]
-xdg = "2"
+xdg = "2.4.0"
[target.'cfg(not(target_os = "macos"))'.dependencies]
png = { version = "0.16.8", default-features = false, optional = true }
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index b1e12007..ce0563ff 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -10,7 +10,7 @@ use alacritty_terminal::config::Program;
use crate::config::window::{Class, DEFAULT_NAME};
use crate::config::{serde_utils, Config};
-/// Options specified on the command line.
+/// CLI options for the main Alacritty executable.
#[derive(StructOpt, Debug)]
#[structopt(author, about, version = env!("VERSION"))]
pub struct Options {
@@ -57,9 +57,10 @@ pub struct Options {
#[structopt(long)]
pub hold: bool,
- /// CLI options for config overrides.
- #[structopt(skip)]
- pub config_options: Value,
+ /// Path for IPC socket creation.
+ #[cfg(unix)]
+ #[structopt(long)]
+ pub socket: Option<PathBuf>,
/// Reduces the level of verbosity (the min level is -qq).
#[structopt(short, conflicts_with("verbose"), parse(from_occurrences))]
@@ -76,6 +77,15 @@ pub struct Options {
/// Override configuration file options [example: cursor.style=Beam].
#[structopt(short = "o", long)]
option: Vec<String>,
+
+ /// CLI options for config overrides.
+ #[structopt(skip)]
+ pub config_options: Value,
+
+ /// Subcommand passed to the CLI.
+ #[cfg(unix)]
+ #[structopt(subcommand)]
+ pub subcommands: Option<Subcommands>,
}
impl Options {
@@ -118,6 +128,11 @@ impl Options {
config.ui_config.window.class = class.clone();
}
+ #[cfg(unix)]
+ {
+ config.ui_config.ipc_socket |= self.socket.is_some();
+ }
+
config.ui_config.window.dynamic_title &= self.title.is_none();
config.ui_config.window.embed = self.embed.as_ref().and_then(|embed| embed.parse().ok());
config.ui_config.debug.print_events |= self.print_events;
@@ -199,6 +214,34 @@ fn parse_class(input: &str) -> Result<Class, String> {
}
}
+/// Available CLI subcommands.
+#[cfg(unix)]
+#[derive(StructOpt, Debug)]
+pub enum Subcommands {
+ Msg(MessageOptions),
+}
+
+/// Send a message to the Alacritty socket.
+#[cfg(unix)]
+#[derive(StructOpt, Debug)]
+pub struct MessageOptions {
+ /// IPC socket connection path override.
+ #[structopt(long, short)]
+ pub socket: Option<PathBuf>,
+
+ /// Message which should be sent.
+ #[structopt(subcommand)]
+ pub message: SocketMessage,
+}
+
+/// Available socket messages.
+#[cfg(unix)]
+#[derive(StructOpt, Debug)]
+pub enum SocketMessage {
+ /// Create a new window in the same Alacritty process.
+ CreateWindow,
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/alacritty/src/config/bindings.rs b/alacritty/src/config/bindings.rs
index 8289fc20..533573c8 100644
--- a/alacritty/src/config/bindings.rs
+++ b/alacritty/src/config/bindings.rs
@@ -180,6 +180,9 @@ pub enum Action {
/// Spawn a new instance of Alacritty.
SpawnNewInstance,
+ /// Create a new Alacritty window.
+ CreateNewWindow,
+
/// Toggle fullscreen.
ToggleFullscreen,
@@ -1099,7 +1102,7 @@ impl<'a> Deserialize<'a> for RawBinding {
let mode = mode.unwrap_or_else(BindingMode::empty);
let not_mode = not_mode.unwrap_or_else(BindingMode::empty);
- let mods = mods.unwrap_or_else(ModifiersState::default);
+ let mods = mods.unwrap_or_default();
let action = match (action, chars, command) {
(Some(action @ Action::ViMotion(_)), None, None)
diff --git a/alacritty/src/config/monitor.rs b/alacritty/src/config/monitor.rs
index e3dd0556..9d37172e 100644
--- a/alacritty/src/config/monitor.rs
+++ b/alacritty/src/config/monitor.rs
@@ -2,19 +2,20 @@ use std::path::PathBuf;
use std::sync::mpsc;
use std::time::Duration;
+use glutin::event_loop::EventLoopProxy;
use log::{debug, error};
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use alacritty_terminal::thread;
-use crate::event::{Event, EventProxy};
+use crate::event::{Event, EventType};
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
const DEBOUNCE_DELAY: Duration = Duration::from_millis(10);
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
const DEBOUNCE_DELAY: Duration = Duration::from_millis(1000);
-pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventProxy) {
+pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventLoopProxy<Event>) {
// Don't monitor config if there is no path to watch.
if paths.is_empty() {
return;
@@ -77,9 +78,10 @@ pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventProxy) {
if paths.contains(&path) =>
{
// Always reload the primary configuration file.
- event_proxy.send_event(Event::ConfigReload(paths[0].clone()));
+ let event = Event::new(EventType::ConfigReload(paths[0].clone()), None);
+ let _ = event_proxy.send_event(event);
}
- _ => {},
+ _ => (),
}
}
});
diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs
index 3ce02161..3ba59ea8 100644
--- a/alacritty/src/config/ui_config.rs
+++ b/alacritty/src/config/ui_config.rs
@@ -62,6 +62,10 @@ pub struct UiConfig {
/// Regex hints for interacting with terminal content.
pub hints: Hints,
+ /// Offer IPC through a unix socket.
+ #[cfg(unix)]
+ pub ipc_socket: bool,
+
/// Keybindings.
key_bindings: KeyBindings,
@@ -76,8 +80,10 @@ pub struct UiConfig {
impl Default for UiConfig {
fn default() -> Self {
Self {
- alt_send_esc: true,
live_config_reload: true,
+ alt_send_esc: true,
+ #[cfg(unix)]
+ ipc_socket: true,
font: Default::default(),
window: Default::default(),
mouse: Default::default(),
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index 946c27f9..a942a88d 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -3,15 +3,15 @@
use std::cmp::min;
use std::convert::TryFrom;
-use std::f64;
use std::fmt::{self, Formatter};
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use std::sync::atomic::Ordering;
use std::time::Instant;
+use std::{f64, mem};
use glutin::dpi::{PhysicalPosition, PhysicalSize};
use glutin::event::ModifiersState;
-use glutin::event_loop::EventLoop;
+use glutin::event_loop::EventLoopWindowTarget;
#[cfg(not(any(target_os = "macos", windows)))]
use glutin::platform::unix::EventLoopWindowTargetExtUnix;
use glutin::window::CursorIcon;
@@ -19,7 +19,7 @@ use log::{debug, info};
use parking_lot::MutexGuard;
use unicode_width::UnicodeWidthChar;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
-use wayland_client::{Display as WaylandDisplay, EventQueue};
+use wayland_client::EventQueue;
use crossfont::{self, Rasterize, Rasterizer};
@@ -178,9 +178,6 @@ pub struct Display {
/// Hint highlighted by the vi mode cursor.
pub vi_highlighted_hint: Option<HintMatch>,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- pub wayland_event_queue: Option<EventQueue>,
-
#[cfg(not(any(target_os = "macos", windows)))]
pub is_x11: bool,
@@ -195,13 +192,21 @@ pub struct Display {
/// State of the keyboard hints.
pub hint_state: HintState,
+ /// Unprocessed display updates.
+ pub pending_update: DisplayUpdate,
+
renderer: QuadRenderer,
glyph_cache: GlyphCache,
meter: Meter,
}
impl Display {
- pub fn new<E>(config: &Config, event_loop: &EventLoop<E>) -> Result<Display, Error> {
+ pub fn new<E>(
+ config: &Config,
+ event_loop: &EventLoopWindowTarget<E>,
+ #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
+ wayland_event_queue: Option<&EventQueue>,
+ ) -> Result<Display, Error> {
#[cfg(any(not(feature = "x11"), target_os = "macos", windows))]
let is_x11 = false;
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
@@ -229,23 +234,13 @@ impl Display {
debug!("Estimated window size: {:?}", estimated_size);
debug!("Estimated cell size: {} x {}", cell_width, cell_height);
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- let mut wayland_event_queue = None;
-
- // Initialize Wayland event queue, to handle Wayland callbacks.
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- if let Some(display) = event_loop.wayland_display() {
- let display = unsafe { WaylandDisplay::from_external_display(display as _) };
- wayland_event_queue = Some(display.create_event_queue());
- }
-
// Spawn the Alacritty window.
let mut window = Window::new(
event_loop,
config,
estimated_size,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue.as_ref(),
+ wayland_event_queue,
)?;
info!("Device pixel ratio: {}", window.dpr);
@@ -344,11 +339,10 @@ impl Display {
vi_highlighted_hint: None,
#[cfg(not(any(target_os = "macos", windows)))]
is_x11,
- #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
- wayland_event_queue,
cursor_hidden: false,
visual_bell: VisualBell::from(&config.ui_config.bell),
colors: List::from(&config.ui_config.colors),
+ pending_update: Default::default(),
})
}
@@ -414,26 +408,30 @@ impl Display {
message_buffer: &MessageBuffer,
search_active: bool,
config: &Config,
- update_pending: DisplayUpdate,
) where
T: EventListener,
{
+ let pending_update = mem::take(&mut self.pending_update);
+
let (mut cell_width, mut cell_height) =
(self.size_info.cell_width(), self.size_info.cell_height());
+ // Ensure we're modifying the correct OpenGL context.
+ self.window.make_current();
+
// Update font size and cell dimensions.
- if let Some(font) = update_pending.font() {
+ if let Some(font) = pending_update.font() {
let cell_dimensions = self.update_glyph_cache(config, font);
cell_width = cell_dimensions.0;
cell_height = cell_dimensions.1;
info!("Cell size: {} x {}", cell_width, cell_height);
- } else if update_pending.cursor_dirty() {
+ } else if pending_update.cursor_dirty() {
self.clear_glyph_cache();
}
let (mut width, mut height) = (self.size_info.width(), self.size_info.height());
- if let Some(dimensions) = update_pending.dimensions() {
+ if let Some(dimensions) = pending_update.dimensions() {
width = dimensions.width as f32;
height = dimensions.height as f32;
}
@@ -463,8 +461,7 @@ impl Display {
terminal.resize(self.size_info);
// Resize renderer.
- let physical =
- PhysicalSize::new(self.size_info.width() as u32, self.size_info.height() as u32);
+ let physical = PhysicalSize::new(self.size_info.width() as _, self.size_info.height() as _);
self.window.resize(physical);
self.renderer.resize(&self.size_info);
@@ -505,6 +502,9 @@ impl Display {
// Drop terminal as early as possible to free lock.
drop(terminal);
+ // Make sure this window's OpenGL context is active.
+ self.window.make_current();
+
self.renderer.with_api(&config.ui_config, &size_info, |api| {
api.clear(background_color);
});
@@ -515,6 +515,10 @@ impl Display {
{
let _sampler = self.meter.sampler();
+ // Ensure macOS hasn't reset our viewport.
+ #[cfg(target_os = "macos")]
+ self.renderer.set_viewport(&size_info);
+
let glyph_cache = &mut self.glyph_cache;
let highlighted_hint = &self.highlighted_hint;
let vi_highlighted_hint = &self.vi_highlighted_hint;
@@ -819,6 +823,14 @@ impl Display {
}
}
+impl Drop for Display {
+ fn drop(&mut self) {
+ // Switch OpenGL context before dropping, otherwise objects (like programs) from other
+ // contexts might be deleted.
+ self.window.make_current()
+ }
+}
+
/// Convert a terminal point to a viewport relative point.
pub fn point_to_viewport(display_offset: usize, point: Point) -> Option<Point<usize>> {
let viewport_line = point.line.0 + display_offset as i32;
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 12416700..16932dc4 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -29,11 +29,12 @@ use {
};
use std::fmt::{self, Display, Formatter};
+use std::ops::{Deref, DerefMut};
#[cfg(target_os = "macos")]
use cocoa::base::{id, NO, YES};
use glutin::dpi::{PhysicalPosition, PhysicalSize};
-use glutin::event_loop::EventLoop;
+use glutin::event_loop::EventLoopWindowTarget;
#[cfg(target_os = "macos")]
use glutin::platform::macos::{WindowBuilderExtMacOS, WindowExtMacOS};
#[cfg(windows)]
@@ -124,7 +125,7 @@ impl From<crossfont::Error> for Error {
fn create_gl_window<E>(
mut window: WindowBuilder,
- event_loop: &EventLoop<E>,
+ event_loop: &EventLoopWindowTarget<E>,
srgb: bool,
vsync: bool,
dimensions: Option<PhysicalSize<u32>>,
@@ -160,7 +161,7 @@ pub struct Window {
/// Cached DPR for quickly scaling pixel sizes.
pub dpr: f64,
- windowed_context: WindowedContext<PossiblyCurrent>,
+ windowed_context: Replaceable<WindowedContext<PossiblyCurrent>>,
current_mouse_cursor: CursorIcon,
mouse_visible: bool,
}
@@ -170,7 +171,7 @@ impl Window {
///
/// This creates a window and fully initializes a window.
pub fn new<E>(
- event_loop: &EventLoop<E>,
+ event_loop: &EventLoopWindowTarget<E>,
config: &Config,
size: Option<PhysicalSize<u32>>,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@@ -232,7 +233,7 @@ impl Window {
Ok(Self {
current_mouse_cursor,
mouse_visible: true,
- windowed_context,
+ windowed_context: Replaceable::new(windowed_context),
#[cfg(not(any(target_os = "macos", windows)))]
should_draw: Arc::new(AtomicBool::new(true)),
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@@ -241,10 +242,12 @@ impl Window {
})
}
+ #[inline]
pub fn set_inner_size(&mut self, size: PhysicalSize<u32>) {
self.window().set_inner_size(size);
}
+ #[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.window().inner_size()
}
@@ -261,6 +264,11 @@ impl Window {
}
#[inline]
+ pub fn request_redraw(&self) {
+ self.window().request_redraw();
+ }
+
+ #[inline]
pub fn set_mouse_cursor(&mut self, cursor: CursorIcon) {
if cursor != self.current_mouse_cursor {
self.current_mouse_cursor = cursor;
@@ -374,7 +382,7 @@ impl Window {
None
}
- pub fn window_id(&self) -> WindowId {
+ pub fn id(&self) -> WindowId {
self.window().id()
}
@@ -436,6 +444,13 @@ impl Window {
self.windowed_context.resize(size);
}
+ pub fn make_current(&mut self) {
+ if !self.windowed_context.is_current() {
+ self.windowed_context
+ .replace_with(|context| unsafe { context.make_current().expect("context swap") });
+ }
+ }
+
/// Disable macOS window shadows.
///
/// This prevents rendering artifacts from showing up when the window is transparent.
@@ -496,3 +511,44 @@ unsafe extern "C" fn xembed_error_handler(_: *mut XDisplay, _: *mut XErrorEvent)
log::error!("Could not embed into specified window.");
std::process::exit(1);
}
+
+/// Struct for safe in-place replacement.
+///
+/// This struct allows easily replacing struct fields that provide `self -> Self` methods in-place,
+/// without having to deal with constantly unwrapping the underlying [`Option`].
+struct Replaceable<T>(Option<T>);
+
+impl<T> Replaceable<T> {
+ pub fn new(inner: T) -> Self {
+ Self(Some(inner))
+ }
+
+ /// Replace the contents of the container.
+ pub fn replace_with<F: FnMut(T) -> T>(&mut self, f: F) {
+ self.0 = self.0.take().map(f);
+ }
+
+ /// Get immutable access to the wrapped value.
+ pub fn get(&self) -> &T {
+ self.0.as_ref().unwrap()
+ }
+
+ /// Get mutable access to the wrapped value.
+ pub fn get_mut(&mut self) -> &mut T {
+ self.0.as_mut().unwrap()
+ }
+}
+
+impl<T> Deref for Replaceable<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ self.get()
+ }
+}
+
+impl<T> DerefMut for Replaceable<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.get_mut()
+ }
+}
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 8e8fac08..09e74a9d 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -2,16 +2,12 @@
use std::borrow::Cow;
use std::cmp::{max, min};
-use std::collections::VecDeque;
+use std::collections::{HashMap, VecDeque};
+use std::error::Error;
use std::fmt::Debug;
#[cfg(not(any(target_os = "macos", windows)))]
use std::fs;
-use std::fs::File;
-use std::io::Write;
-use std::path::{Path, PathBuf};
-#[cfg(not(any(target_os = "macos", windows)))]
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
+use std::path::PathBuf;
use std::time::{Duration, Instant};
use std::{env, f32, mem};
@@ -21,35 +17,38 @@ use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindow
use glutin::platform::run_return::EventLoopExtRunReturn;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use glutin::platform::unix::EventLoopWindowTargetExtUnix;
-use log::info;
-use serde_json as json;
+use glutin::window::WindowId;
+use log::{error, info};
+#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
+use wayland_client::{Display as WaylandDisplay, EventQueue};
use crossfont::{self, Size};
use alacritty_terminal::config::LOG_TARGET_CONFIG;
-use alacritty_terminal::event::{Event as TerminalEvent, EventListener, Notify, OnResize};
+use alacritty_terminal::event::{Event as TerminalEvent, EventListener, Notify};
+use alacritty_terminal::event_loop::Notifier;
use alacritty_terminal::grid::{Dimensions, Scroll};
use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point, Side};
use alacritty_terminal::selection::{Selection, SelectionType};
-use alacritty_terminal::sync::FairMutex;
use alacritty_terminal::term::search::{Match, RegexSearch};
use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode};
#[cfg(not(windows))]
use alacritty_terminal::tty;
-use crate::cli::Options as CLIOptions;
+use crate::cli::Options as CliOptions;
use crate::clipboard::Clipboard;
use crate::config::ui_config::{HintAction, HintInternalAction};
use crate::config::{self, Config};
use crate::daemon::start_daemon;
use crate::display::hint::HintMatch;
use crate::display::window::Window;
-use crate::display::{self, Display, DisplayUpdate};
+use crate::display::{self, Display};
use crate::input::{self, ActionContext as _, FONT_SIZE_STEP};
#[cfg(target_os = "macos")]
use crate::macos;
use crate::message_bar::{Message, MessageBuffer};
-use crate::scheduler::{Scheduler, TimerId};
+use crate::scheduler::{Scheduler, TimerId, Topic};
+use crate::window_context::WindowContext;
/// Duration after the last user input until an unlimited search is performed.
pub const TYPING_SEARCH_DELAY: Duration = Duration::from_millis(500);
@@ -60,16 +59,20 @@ const MAX_SEARCH_WHILE_TYPING: Option<usize> = Some(1000);
/// Maximum number of search terms stored in the history.
const MAX_SEARCH_HISTORY_SIZE: usize = 255;
-/// Events dispatched through the UI event loop.
+/// Alacritty events.
#[derive(Debug, Clone)]
-pub enum Event {
- Terminal(TerminalEvent),
- DprChanged(f64, (u32, u32)),
- Scroll(Scroll),
- ConfigReload(PathBuf),
- Message(Message),
- BlinkCursor,
- SearchNext,
+pub struct Event {
+ /// Limit event to a specific window.
+ window_id: Option<WindowId>,
+
+ /// Event payload.
+ payload: EventType,
+}
+
+impl Event {
+ pub fn new<I: Into<Option<WindowId>>>(payload: EventType, window_id: I) -> Self {
+ Self { window_id: window_id.into(), payload }
+ }
}
impl From<Event> for GlutinEvent<'_, Event> {
@@ -78,16 +81,32 @@ impl From<Event> for GlutinEvent<'_, Event> {
}
}
-impl From<TerminalEvent> for Event {
+/// Alacritty events.
+#[derive(Debug, Clone)]
+pub enum EventType {
+ DprChanged(f64, (u32, u32)),
+ Terminal(TerminalEvent),
+ ConfigReload(PathBuf),
+ Message(Message),
+ Scroll(Scroll),
+ CreateWindow,
+ BlinkCursor,
+ SearchNext,
+}
+
+impl From<TerminalEvent> for EventType {
fn from(event: TerminalEvent) -> Self {
- Event::Terminal(event)
+ Self::Terminal(event)
}
}
/// Regex search state.
pub struct SearchState {
/// Search direction.
- direction: Direction,
+ pub direction: Direction,
+
+ /// Current position in the search history.
+ pub history_index: Option<usize>,
/// Change in display offset since the beginning of the search.
display_offset_delta: i32,
@@ -106,9 +125,6 @@ pub struct SearchState {
/// in history which is currently being previewed.
history: VecDeque<String>,
- /// Current position in the search history.
- history_index: Option<usize>,
-
/// Compiled search automatons.
dfas: Option<RegexSearch>,
}
@@ -164,14 +180,13 @@ pub struct ActionContext<'a, N, T> {
pub modifiers: &'a mut ModifiersState,
pub display: &'a mut Display,
pub message_buffer: &'a mut MessageBuffer,
- pub display_update_pending: &'a mut DisplayUpdate,
pub config: &'a mut Config,
pub event_loop: &'a EventLoopWindowTarget<Event>,
+ pub event_proxy: &'a EventLoopProxy<Event>,
pub scheduler: &'a mut Scheduler,
pub search_state: &'a mut SearchState,
- cli_options: &'a CLIOptions,
- font_size: &'a mut Size,
- dirty: &'a mut bool,
+ pub font_size: &'a mut Size,
+ pub dirty: &'a mut bool,
}
impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionContext<'a, N, T> {
@@ -380,23 +395,27 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
start_daemon(&alacritty, &args);
}
+ fn create_new_window(&mut self) {
+ let _ = self.event_proxy.send_event(Event::new(EventType::CreateWindow, None));
+ }
+
fn change_font_size(&mut self, delta: f32) {
*self.font_size = max(*self.font_size + delta, Size::new(FONT_SIZE_STEP));
let font = self.config.ui_config.font.clone().with_size(*self.font_size);
- self.display_update_pending.set_font(font);
+ self.display.pending_update.set_font(font);
*self.dirty = true;
}