aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src
diff options
context:
space:
mode:
authorKirill Chibisov <contact@kchibisov.com>2022-01-03 21:55:22 +0300
committerGitHub <noreply@github.com>2022-01-03 18:55:22 +0000
commitce59fa4165500d8e242ae7a73e3da065e11e461e (patch)
treedfaaec5872d59d4c2b2e4907e3213134bea7125d /alacritty/src
parente2b5219eb40eaf36d8255cd87c5202bbb8ba0825 (diff)
downloadr-alacritty-ce59fa4165500d8e242ae7a73e3da065e11e461e.tar.gz
r-alacritty-ce59fa4165500d8e242ae7a73e3da065e11e461e.tar.bz2
r-alacritty-ce59fa4165500d8e242ae7a73e3da065e11e461e.zip
Add title/class CLI parameters to create-window
This adds the ability to pass title and class over IPC via the create-window subcommand, so users can run only one instance for windows of different spurposes in the window managers of their choice.
Diffstat (limited to 'alacritty/src')
-rw-r--r--alacritty/src/cli.rs68
-rw-r--r--alacritty/src/config/window.rs30
-rw-r--r--alacritty/src/display/mod.rs4
-rw-r--r--alacritty/src/display/window.rs44
-rw-r--r--alacritty/src/event.rs24
-rw-r--r--alacritty/src/main.rs4
-rw-r--r--alacritty/src/window_context.rs31
7 files changed, 135 insertions, 70 deletions
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index 69200039..4c8a307a 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -8,7 +8,7 @@ use structopt::StructOpt;
use alacritty_terminal::config::{Program, PtyConfig};
-use crate::config::window::{Class, DEFAULT_NAME};
+use crate::config::window::{Class, Identity, DEFAULT_NAME};
use crate::config::{serde_utils, UiConfig};
/// CLI options for the main Alacritty executable.
@@ -23,14 +23,6 @@ pub struct Options {
#[structopt(long)]
pub ref_test: bool,
- /// Defines the window title [default: Alacritty].
- #[structopt(short, long)]
- pub title: Option<String>,
-
- /// Defines window class/app_id on X11/Wayland [default: Alacritty].
- #[structopt(long, value_name = "instance> | <instance>,<general", parse(try_from_str = parse_class))]
- pub class: Option<Class>,
-
/// Defines the X11 window ID (as a decimal integer) to embed Alacritty within.
#[structopt(long)]
pub embed: Option<String>,
@@ -71,9 +63,9 @@ pub struct Options {
#[structopt(skip)]
pub config_options: Value,
- /// Terminal options which could be passed via IPC.
+ /// Options which could be passed via IPC.
#[structopt(flatten)]
- pub terminal_options: TerminalOptions,
+ pub window_options: WindowOptions,
/// Subcommand passed to the CLI.
#[cfg(unix)]
@@ -100,19 +92,12 @@ impl Options {
/// Override configuration file with options from the CLI.
pub fn override_config(&self, config: &mut UiConfig) {
- if let Some(title) = self.title.clone() {
- config.window.title = title
- }
- if let Some(class) = &self.class {
- config.window.class = class.clone();
- }
-
#[cfg(unix)]
{
config.ipc_socket |= self.socket.is_some();
}
- config.window.dynamic_title &= self.title.is_none();
+ config.window.dynamic_title &= self.window_options.window_identity.title.is_none();
config.window.embed = self.embed.as_ref().and_then(|embed| embed.parse().ok());
config.debug.print_events |= self.print_events;
config.debug.log_level = max(config.debug.log_level, self.log_level());
@@ -237,6 +222,30 @@ impl From<TerminalOptions> for PtyConfig {
}
}
+/// Window specific cli options which can be passed to new windows via IPC.
+#[derive(Serialize, Deserialize, StructOpt, Default, Debug, Clone, PartialEq)]
+pub struct WindowIdentity {
+ /// Defines the window title [default: Alacritty].
+ #[structopt(short, long)]
+ pub title: Option<String>,
+
+ /// Defines window class/app_id on X11/Wayland [default: Alacritty].
+ #[structopt(long, value_name = "instance> | <instance>,<general", parse(try_from_str = parse_class))]
+ pub class: Option<Class>,
+}
+
+impl WindowIdentity {
+ /// Override the [`WindowIdentityConfig`]'s fields with the [`WindowOptions`].
+ pub fn override_identity_config(&self, identity: &mut Identity) {
+ if let Some(title) = &self.title {
+ identity.title = title.clone();
+ }
+ if let Some(class) = &self.class {
+ identity.class = class.clone();
+ }
+ }
+}
+
/// Available CLI subcommands.
#[cfg(unix)]
#[derive(StructOpt, Debug)]
@@ -262,7 +271,19 @@ pub struct MessageOptions {
#[derive(StructOpt, Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum SocketMessage {
/// Create a new window in the same Alacritty process.
- CreateWindow(TerminalOptions),
+ CreateWindow(WindowOptions),
+}
+
+/// Subset of options that we pass to a 'create-window' subcommand.
+#[derive(StructOpt, Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
+pub struct WindowOptions {
+ /// Terminal options which can be passed via IPC.
+ #[structopt(flatten)]
+ pub terminal_options: TerminalOptions,
+
+ #[structopt(flatten)]
+ /// Window options which could be passed via IPC.
+ pub window_identity: WindowIdentity,
}
#[cfg(test)]
@@ -292,7 +313,10 @@ mod tests {
fn dynamic_title_overridden_by_options() {
let mut config = UiConfig::default();
- let options = Options { title: Some("foo".to_owned()), ..Options::default() };
+ let title = Some(String::from("foo"));
+ let window_identity = WindowIdentity { title, ..WindowIdentity::default() };
+ let new_window_options = WindowOptions { window_identity, ..WindowOptions::default() };
+ let options = Options { window_options: new_window_options, ..Options::default() };
options.override_config(&mut config);
assert!(!config.window.dynamic_title);
@@ -302,7 +326,7 @@ mod tests {
fn dynamic_title_not_overridden_by_config() {
let mut config = UiConfig::default();
- config.window.title = "foo".to_owned();
+ config.window.identity.title = "foo".to_owned();
Options::default().override_config(&mut config);
assert!(config.window.dynamic_title);
diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs
index f7a7511c..507a4f2c 100644
--- a/alacritty/src/config/window.rs
+++ b/alacritty/src/config/window.rs
@@ -4,7 +4,7 @@ use std::os::raw::c_ulong;
use glutin::window::Fullscreen;
use log::error;
use serde::de::{self, MapAccess, Visitor};
-use serde::{Deserialize, Deserializer};
+use serde::{Deserialize, Deserializer, Serialize};
use alacritty_config_derive::ConfigDeserialize;
use alacritty_terminal::config::{Percentage, LOG_TARGET_CONFIG};
@@ -39,11 +39,9 @@ pub struct WindowConfig {
/// Use dynamic title.
pub dynamic_title: bool,
- /// Window title.
- pub title: String,
-
- /// Window class.
- pub class: Class,
+ /// Information to identify a particular window.
+ #[config(flatten)]
+ pub identity: Identity,
/// Background opacity from 0.0 to 1.0.
pub opacity: Percentage,
@@ -59,14 +57,13 @@ impl Default for WindowConfig {
fn default() -> Self {
Self {
dynamic_title: true,
- title: DEFAULT_NAME.into(),
position: Default::default(),
decorations: Default::default(),
startup_mode: Default::default(),
embed: Default::default(),
gtk_theme_variant: Default::default(),
dynamic_padding: Default::default(),
- class: Default::default(),
+ identity: Identity::default(),
opacity: Default::default(),
padding: Default::default(),
dimensions: Default::default(),
@@ -109,6 +106,21 @@ impl WindowConfig {
}
}
+#[derive(ConfigDeserialize, Debug, Clone, PartialEq)]
+pub struct Identity {
+ /// Window title.
+ pub title: String,
+
+ /// Window class.
+ pub class: Class,
+}
+
+impl Default for Identity {
+ fn default() -> Self {
+ Self { title: DEFAULT_NAME.into(), class: Default::default() }
+ }
+}
+
#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub enum StartupMode {
Windowed,
@@ -153,7 +165,7 @@ pub struct Dimensions {
}
/// Window class hint.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
pub struct Class {
pub instance: String,
pub general: String,
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index cd465913..d89b1076 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -32,9 +32,9 @@ use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::{SizeInfo, Term, TermMode, MIN_COLUMNS, MIN_SCREEN_LINES};
use crate::config::font::Font;
-use crate::config::window::Dimensions;
#[cfg(not(windows))]
use crate::config::window::StartupMode;
+use crate::config::window::{Dimensions, Identity};
use crate::config::UiConfig;
use crate::display::bell::VisualBell;
use crate::display::color::List;
@@ -202,6 +202,7 @@ impl Display {
pub fn new<E>(
config: &UiConfig,
event_loop: &EventLoopWindowTarget<E>,
+ identity: &Identity,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
wayland_event_queue: Option<&EventQueue>,
) -> Result<Display, Error> {
@@ -236,6 +237,7 @@ impl Display {
let mut window = Window::new(
event_loop,
config,
+ identity,
estimated_size,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
wayland_event_queue,
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 84ef2b07..ee2e74fc 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -50,7 +50,7 @@ use winapi::shared::minwindef::WORD;
use alacritty_terminal::index::Point;
use alacritty_terminal::term::SizeInfo;
-use crate::config::window::{Decorations, WindowConfig};
+use crate::config::window::{Decorations, Identity, WindowConfig};
use crate::config::UiConfig;
use crate::gl;
@@ -154,6 +154,9 @@ pub struct Window {
/// Cached DPR for quickly scaling pixel sizes.
pub dpr: f64,
+ /// Current window title.
+ title: String,
+
windowed_context: Replaceable<WindowedContext<PossiblyCurrent>>,
current_mouse_cursor: CursorIcon,
mouse_visible: bool,
@@ -166,12 +169,13 @@ impl Window {
pub fn new<E>(
event_loop: &EventLoopWindowTarget<E>,
config: &UiConfig,
+ identity: &Identity,
size: Option<PhysicalSize<u32>>,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
wayland_event_queue: Option<&EventQueue>,
) -> Result<Window> {
- let window_config = &config.window;
- let window_builder = Window::get_platform_window(&window_config.title, window_config);
+ let identity = identity.clone();
+ let window_builder = Window::get_platform_window(&identity, &config.window);
// Check if we're running Wayland to disable vsync.
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@@ -195,7 +199,7 @@ impl Window {
#[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) = window_config.embed {
+ if let Some(parent_window_id) = config.window.embed {
x_embed_window(windowed_context.window(), parent_window_id);
}
}
@@ -216,6 +220,7 @@ impl Window {
current_mouse_cursor,
mouse_visible: true,
windowed_context: Replaceable::new(windowed_context),
+ title: identity.title,
#[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,8 +246,15 @@ impl Window {
/// Set the window title.
#[inline]
- pub fn set_title(&self, title: &str) {
- self.window().set_title(title);
+ pub fn set_title(&mut self, title: String) {
+ self.title = title;
+ self.window().set_title(&self.title);
+ }
+
+ /// Get the window title.
+ #[inline]
+ pub fn title(&self) -> &str {
+ &self.title
}
#[inline]
@@ -267,7 +279,7 @@ impl Window {
}
#[cfg(not(any(target_os = "macos", windows)))]
- pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
+ pub fn get_platform_window(identity: &Identity, window_config: &WindowConfig) -> WindowBuilder {
#[cfg(feature = "x11")]
let icon = {
let decoder = Decoder::new(Cursor::new(WINDOW_ICON));
@@ -278,7 +290,7 @@ impl Window {
};
let builder = WindowBuilder::new()
- .with_title(title)
+ .with_title(&identity.title)
.with_visible(false)
.with_transparent(true)
.with_decorations(window_config.decorations != Decorations::None)
@@ -289,13 +301,11 @@ impl Window {
let builder = builder.with_window_icon(icon.ok());
#[cfg(feature = "wayland")]
- let builder = builder.with_app_id(window_config.class.instance.to_owned());
+ let builder = builder.with_app_id(identity.class.instance.to_owned());
#[cfg(feature = "x11")]
- let builder = builder.with_class(
- window_config.class.instance.to_owned(),
- window_config.class.general.to_owned(),
- );
+ let builder = builder
+ .with_class(identity.class.instance.to_owned(), identity.class.general.to_owned());
#[cfg(feature = "x11")]
let builder = match &window_config.gtk_theme_variant {
@@ -307,11 +317,11 @@ impl Window {
}
#[cfg(windows)]
- pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
+ pub fn get_platform_window(identity: &Identity, window_config: &WindowConfig) -> WindowBuilder {
let icon = glutin::window::Icon::from_resource(IDI_ICON, None);
WindowBuilder::new()
- .with_title(title)
+ .with_title(&identity.title)
.with_visible(false)
.with_decorations(window_config.decorations != Decorations::None)
.with_transparent(true)
@@ -321,9 +331,9 @@ impl Window {
}
#[cfg(target_os = "macos")]
- pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
+ pub fn get_platform_window(identity: &Identity, window_config: &WindowConfig) -> WindowBuilder {
let window = WindowBuilder::new()
- .with_title(title)
+ .with_title(&identity.title)
.with_visible(false)
.with_transparent(true)
.with_maximized(window_config.maximized())
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index c2baddf8..462c9416 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -34,7 +34,7 @@ use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::term::search::{Match, RegexSearch};
use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode};
-use crate::cli::{Options as CliOptions, TerminalOptions};
+use crate::cli::{Options as CliOptions, WindowOptions};
use crate::clipboard::Clipboard;
use crate::config::ui_config::{HintAction, HintInternalAction};
use crate::config::{self, UiConfig};
@@ -88,7 +88,7 @@ pub enum EventType {
ConfigReload(PathBuf),
Message(Message),
Scroll(Scroll),
- CreateWindow(TerminalOptions),
+ CreateWindow(WindowOptions),
BlinkCursor,
SearchNext,
}
@@ -379,9 +379,9 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
#[cfg(not(windows))]
fn create_new_window(&mut self) {
- let mut options = TerminalOptions::default();
+ let mut options = WindowOptions::default();
if let Ok(working_directory) = foreground_process_path(self.master_fd, self.shell_pid) {
- options.working_directory = Some(working_directory);
+ options.terminal_options.working_directory = Some(working_directory);
}
let _ = self.event_proxy.send_event(Event::new(EventType::CreateWindow(options), None));
@@ -391,7 +391,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
fn create_new_window(&mut self) {
let _ = self
.event_proxy
- .send_event(Event::new(EventType::CreateWindow(TerminalOptions::default()), None));
+ .send_event(Event::new(EventType::CreateWindow(WindowOptions::default()), None));
}
fn spawn_daemon<I, S>(&self, program: &str, args: I)
@@ -1040,12 +1040,13 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
EventType::Terminal(event) => match event {
TerminalEvent::Title(title) => {
if self.ctx.config.window.dynamic_title {
- self.ctx.window().set_title(&title);
+ self.ctx.window().set_title(title);
}
},
TerminalEvent::ResetTitle => {
- if self.ctx.config.window.dynamic_title {
- self.ctx.display.window.set_title(&self.ctx.config.window.title);
+ let window_config = &self.ctx.config.window;
+ if window_config.dynamic_title {
+ self.ctx.display.window.set_title(window_config.identity.title.clone());
}
},
TerminalEvent::Wakeup => *self.ctx.dirty = true,
@@ -1206,14 +1207,11 @@ impl Processor {
&mut self,
event_loop: &EventLoopWindowTarget<Event>,
proxy: EventLoopProxy<Event>,
- options: TerminalOptions,
+ options: WindowOptions,
) -> Result<(), Box<dyn Error>> {
- let mut pty_config = self.config.terminal_config.pty_config.clone();
- options.override_pty_config(&mut pty_config);
-
let window_context = WindowContext::new(
&self.config,
- &pty_config,
+ &options,
event_loop,
proxy,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 0af1c01b..6a86fcb1 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -178,13 +178,13 @@ fn alacritty(options: Options) -> Result<(), String> {
};
// Event processor.
- let cli_options = options.terminal_options.clone();
+ let window_options = options.window_options.clone();
let mut processor = Processor::new(config, options, &window_event_loop);
// Create the first Alacritty window.
let proxy = window_event_loop.create_proxy();
processor
- .create_window(&window_event_loop, proxy, cli_options)
+ .create_window(&window_event_loop, proxy, window_options)
.map_err(|err| err.to_string())?;
info!("Initialisation complete");
diff --git a/alacritty/src/window_context.rs b/alacritty/src/window_context.rs
index 130f42d6..795b3f73 100644
--- a/alacritty/src/window_context.rs
+++ b/alacritty/src/window_context.rs
@@ -19,7 +19,6 @@ use serde_json as json;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use wayland_client::EventQueue;
-use alacritty_terminal::config::PtyConfig;
use alacritty_terminal::event::Event as TerminalEvent;
use alacritty_terminal::event_loop::{EventLoop as PtyEventLoop, Msg, Notifier};
use alacritty_terminal::grid::{Dimensions, Scroll};
@@ -28,6 +27,7 @@ use alacritty_terminal::sync::FairMutex;
use alacritty_terminal::term::{Term, TermMode};
use alacritty_terminal::tty;
+use crate::cli::WindowOptions;
use crate::clipboard::Clipboard;
use crate::config::UiConfig;
use crate::display::Display;
@@ -50,6 +50,7 @@ pub struct WindowContext {
font_size: Size,
mouse: Mouse,
dirty: bool,
+ preserve_title: bool,
#[cfg(not(windows))]
master_fd: RawFd,
#[cfg(not(windows))]
@@ -60,18 +61,26 @@ impl WindowContext {
/// Create a new terminal window context.
pub fn new(
config: &UiConfig,
- pty_config: &PtyConfig,
+ options: &WindowOptions,
window_event_loop: &EventLoopWindowTarget<Event>,
proxy: EventLoopProxy<Event>,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
wayland_event_queue: Option<&EventQueue>,
) -> Result<Self, Box<dyn Error>> {
+ let mut pty_config = config.terminal_config.pty_config.clone();
+ options.terminal_options.override_pty_config(&mut pty_config);
+
+ let mut identity = config.window.identity.clone();
+ let preserve_title = options.window_identity.title.is_some();
+ options.window_identity.override_identity_config(&mut identity);
+
// Create a display.
//
// The display manages a window and can draw the terminal.
let display = Display::new(
config,
window_event_loop,
+ &identity,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
wayland_event_queue,
)?;
@@ -97,7 +106,7 @@ impl WindowContext {
// The PTY forks a process to run the shell on the slave side of the
// pseudoterminal. A file descriptor for the master side is retained for
// reading/writing to the shell.
- let pty = tty::new(pty_config, &display.size_info, display.window.x11_window_id())?;
+ let pty = tty::new(&pty_config, &display.size_info, display.window.x11_window_id())?;
#[cfg(not(windows))]
let master_fd = pty.file().as_raw_fd();
@@ -136,6 +145,7 @@ impl WindowContext {
notifier: Notifier(loop_tx),
terminal,
display,
+ preserve_title,
#[cfg(not(windows))]
master_fd,
#[cfg(not(windows))]
@@ -183,9 +193,18 @@ impl WindowContext {
self.display.pending_update.dirty = true;
}
- // Live title reload.
- if !config.window.dynamic_title || old_config.window.title != config.window.title {
- self.display.window.set_title(&config.window.title);
+ // Update title on config reload according to the following table.
+ //
+ // │cli │ dynamic_title │ current_title == old_config ││ set_title │
+ // │ Y │ _ │ _ ││ N │
+ // │ N │ Y │ Y ││ Y │
+ // │ N │ Y │ N ││ N │
+ // │ N │ N │ _ ││ Y │
+ if !self.preserve_title
+ && (!config.window.dynamic_title
+ || self.display.window.title() == old_config.window.identity.title)
+ {
+ self.display.window.set_title(config.window.identity.title.clone());
}
// Set subpixel anti-aliasing.