aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2024-10-15 18:32:50 +0000
committerGitHub <noreply@github.com>2024-10-15 18:32:50 +0000
commit2a2db5b6fd23adea88906b8c2ee81512cd44cd53 (patch)
tree46c314a8cfb6a94e2693f5e3e5e79e02877875f0
parent6ba69f8dd469e1a9aff0b48b3ae10ce4510ca1e3 (diff)
downloadalacritty-2a2db5b6fd23adea88906b8c2ee81512cd44cd53.tar.gz
alacritty-2a2db5b6fd23adea88906b8c2ee81512cd44cd53.zip
Add headless mode
This patch adds a daemon mode to Alacritty which allows starting the Alacritty process without spawning an initial window. While this does not provide any significant advantage over the existing behavior of always spawning a window, it does integrate nicer with some setups and is a pretty trivial addition.
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty/src/cli.rs6
-rw-r--r--alacritty/src/event.rs50
-rw-r--r--alacritty/src/ipc.rs9
-rw-r--r--alacritty/src/window_context.rs17
-rw-r--r--extra/completions/_alacritty3
-rw-r--r--extra/completions/alacritty.bash2
-rw-r--r--extra/completions/alacritty.fish3
-rw-r--r--extra/man/alacritty.1.scd4
9 files changed, 58 insertions, 37 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7dff2d54..8d9d463a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its
- Support relative path imports from config files
- `alacritty migrate` support for TOML configuration changes
- Support for Unicode 16 characters
+- Headless mode using `alacritty --daemon`
### Changed
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index 2b4afa02..bb0a24f4 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -26,7 +26,7 @@ pub struct Options {
pub print_events: bool,
/// Generates ref test.
- #[clap(long)]
+ #[clap(long, conflicts_with("daemon"))]
pub ref_test: bool,
/// X11 window ID to embed Alacritty within (decimal or hexadecimal with "0x" prefix).
@@ -62,6 +62,10 @@ pub struct Options {
#[clap(short, conflicts_with("quiet"), action = ArgAction::Count)]
verbose: u8,
+ /// Do not spawn an initial window.
+ #[clap(long)]
+ pub daemon: bool,
+
/// CLI options for config overrides.
#[clap(skip)]
pub config_options: ParsedOptions,
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 23575e21..f0159060 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -1,6 +1,7 @@
//! Process window events.
use crate::ConfigMonitor;
+use glutin::config::GetGlConfig;
use std::borrow::Cow;
use std::cmp::min;
use std::collections::{HashMap, HashSet, VecDeque};
@@ -16,7 +17,8 @@ use std::{env, f32, mem};
use ahash::RandomState;
use crossfont::Size as FontSize;
-use glutin::display::{Display as GlutinDisplay, GetGlDisplay};
+use glutin::config::Config as GlutinConfig;
+use glutin::display::GetGlDisplay;
use log::{debug, error, info, warn};
use winit::application::ApplicationHandler;
use winit::event::{
@@ -80,7 +82,7 @@ pub struct Processor {
initial_window_error: Option<Box<dyn Error>>,
windows: HashMap<WindowId, WindowContext, RandomState>,
proxy: EventLoopProxy<Event>,
- gl_display: Option<GlutinDisplay>,
+ gl_config: Option<GlutinConfig>,
#[cfg(unix)]
global_ipc_options: ParsedOptions,
cli_options: CliOptions,
@@ -121,7 +123,7 @@ impl Processor {
cli_options,
proxy,
scheduler,
- gl_display: None,
+ gl_config: None,
config: Rc::new(config),
clipboard,
windows: Default::default(),
@@ -138,12 +140,16 @@ impl Processor {
pub fn create_initial_window(
&mut self,
event_loop: &ActiveEventLoop,
- options: WindowOptions,
) -> Result<(), Box<dyn Error>> {
+ let options = match self.initial_window_options.take() {
+ Some(options) => options,
+ None => return Ok(()),
+ };
+
let window_context =
WindowContext::initial(event_loop, self.proxy.clone(), self.config.clone(), options)?;
- self.gl_display = Some(window_context.display.gl_context().display());
+ self.gl_config = Some(window_context.display.gl_context().config());
self.windows.insert(window_context.id(), window_context);
Ok(())
@@ -155,7 +161,7 @@ impl Processor {
event_loop: &ActiveEventLoop,
options: WindowOptions,
) -> Result<(), Box<dyn Error>> {
- let window = self.windows.iter().next().as_ref().unwrap().1;
+ let gl_config = self.gl_config.as_ref().unwrap();
// Override config with CLI/IPC options.
let mut config_overrides = options.config_overrides();
@@ -164,9 +170,14 @@ impl Processor {
let mut config = self.config.clone();
config = config_overrides.override_config_rc(config);
- #[allow(unused_mut)]
- let mut window_context =
- window.additional(event_loop, self.proxy.clone(), config, options, config_overrides)?;
+ let window_context = WindowContext::additional(
+ gl_config,
+ event_loop,
+ self.proxy.clone(),
+ config,
+ options,
+ config_overrides,
+ )?;
self.windows.insert(window_context.id(), window_context);
Ok(())
@@ -210,16 +221,11 @@ impl ApplicationHandler<Event> for Processor {
fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
- if cause != StartCause::Init {
+ if cause != StartCause::Init || self.cli_options.daemon {
return;
}
- let initial_window_options = match self.initial_window_options.take() {
- Some(initial_window_options) => initial_window_options,
- None => return,
- };
-
- if let Err(err) = self.create_initial_window(event_loop, initial_window_options) {
+ if let Err(err) = self.create_initial_window(event_loop) {
self.initial_window_error = Some(err);
event_loop.exit();
return;
@@ -338,7 +344,13 @@ impl ApplicationHandler<Event> for Processor {
window_context.display.make_not_current();
}
- if let Err(err) = self.create_window(event_loop, options.clone()) {
+ if self.gl_config.is_none() {
+ // Handle initial window creation in daemon mode.
+ if let Err(err) = self.create_initial_window(event_loop) {
+ self.initial_window_error = Some(err);
+ event_loop.exit();
+ }
+ } else if let Err(err) = self.create_window(event_loop, options.clone()) {
error!("Could not open window: {:?}", err);
}
},
@@ -375,7 +387,7 @@ impl ApplicationHandler<Event> for Processor {
self.scheduler.unschedule_window(window_context.id());
// Shutdown if no more terminals are open.
- if self.windows.is_empty() {
+ if self.windows.is_empty() && !self.cli_options.daemon {
// Write ref tests of last window to disk.
if self.config.debug.ref_test {
window_context.write_ref_test_results();
@@ -439,7 +451,7 @@ impl ApplicationHandler<Event> for Processor {
info!("Exiting the event loop");
}
- match self.gl_display.take() {
+ match self.gl_config.take().map(|config| config.display()) {
#[cfg(not(target_os = "macos"))]
Some(glutin::display::Display::Egl(display)) => {
// Ensure that all the windows are dropped, so the destructors for
diff --git a/alacritty/src/ipc.rs b/alacritty/src/ipc.rs
index d06d395e..3d14c4ce 100644
--- a/alacritty/src/ipc.rs
+++ b/alacritty/src/ipc.rs
@@ -20,13 +20,13 @@ const ALACRITTY_SOCKET_ENV: &str = "ALACRITTY_SOCKET";
/// Create an IPC socket.
pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -> Option<PathBuf> {
- // Create the IPC socket and export its path as env variable if necessary.
+ // Create the IPC socket and export its path as env.
+
let socket_path = options.socket.clone().unwrap_or_else(|| {
let mut path = socket_dir();
path.push(format!("{}-{}.sock", socket_prefix(), process::id()));
path
});
- env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str());
let listener = match UnixListener::bind(&socket_path) {
Ok(listener) => listener,
@@ -36,6 +36,11 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -
},
};
+ env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str());
+ if options.daemon {
+ println!("ALACRITTY_SOCKET={}; export ALACRITTY_SOCKET", socket_path.display());
+ }
+
// Spawn a thread to listen on the IPC socket.
thread::spawn_named("socket listener", move || {
let mut data = String::new();
diff --git a/alacritty/src/window_context.rs b/alacritty/src/window_context.rs
index 062f9ef0..cfc3cd96 100644
--- a/alacritty/src/window_context.rs
+++ b/alacritty/src/window_context.rs
@@ -9,7 +9,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::Rc;
use std::sync::Arc;
-use glutin::config::GetGlConfig;
+use glutin::config::Config as GlutinConfig;
use glutin::display::GetGlDisplay;
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
use glutin::platform::x11::X11GlConfigExt;
@@ -119,18 +119,14 @@ impl WindowContext {
/// Create additional context with the graphics platform other windows are using.
pub fn additional(
- &self,
+ gl_config: &GlutinConfig,
event_loop: &ActiveEventLoop,
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
options: WindowOptions,
config_overrides: ParsedOptions,
) -> 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) = {
- let gl_context = self.display.gl_context();
- (gl_context.display(), gl_context.config())
- };
+ let gl_display = gl_config.display();
let mut identity = config.window.identity.clone();
options.window_identity.override_identity_config(&mut identity);
@@ -147,11 +143,8 @@ impl WindowContext {
// Create context.
let raw_window_handle = window.raw_window_handle();
- let gl_context = renderer::platform::create_gl_context(
- &gl_display,
- &gl_config,
- Some(raw_window_handle),
- )?;
+ let gl_context =
+ renderer::platform::create_gl_context(&gl_display, gl_config, Some(raw_window_handle))?;
// Check if new window will be opened as a tab.
#[cfg(target_os = "macos")]
diff --git a/extra/completions/_alacritty b/extra/completions/_alacritty
index a9260d5c..0ccce66f 100644
--- a/extra/completions/_alacritty
+++ b/extra/completions/_alacritty
@@ -27,9 +27,10 @@ _alacritty() {
'*-o+[Override configuration file options \[example\: '\''cursor.style="Beam"'\''\]]:OPTION: ' \
'*--option=[Override configuration file options \[example\: '\''cursor.style="Beam"'\''\]]:OPTION: ' \
'--print-events[Print all events to STDOUT]' \
-'--ref-test[Generates ref test]' \
+'(--daemon)--ref-test[Generates ref test]' \
'(-v)*-q[Reduces the level of verbosity (the min level is -qq)]' \
'(-q)*-v[Increases the level of verbosity (the max level is -vvv)]' \
+'--daemon[Do not spawn an initial window]' \
'--hold[Remain open after child process exit]' \
'-h[Print help]' \
'--help[Print help]' \
diff --git a/extra/completions/alacritty.bash b/extra/completions/alacritty.bash
index 2c10d47c..e2213b75 100644
--- a/extra/completions/alacritty.bash
+++ b/extra/completions/alacritty.bash
@@ -61,7 +61,7 @@ _alacritty() {
case "${cmd}" in
alacritty)
- opts="-q -v -e -T -o -h -V --print-events --ref-test --embed --config-file --socket --working-directory --hold --command --title --class --option --help --version msg migrate help"
+ opts="-q -v -e -T -o -h -V --print-events --ref-test --embed --config-file --socket --daemon --working-directory --hold --command --title --class --option --help --version msg migrate help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
diff --git a/extra/completions/alacritty.fish b/extra/completions/alacritty.fish
index b7fa8ce6..7cfc3337 100644
--- a/extra/completions/alacritty.fish
+++ b/extra/completions/alacritty.fish
@@ -1,6 +1,6 @@
# Print an optspec for argparse to handle cmd's options that are independent of any subcommand.
function __fish_alacritty_global_optspecs
- string join \n print-events ref-test embed= config-file= socket= q v working-directory= hold e/command= T/title= class= o/option= h/help V/version
+ string join \n print-events ref-test embed= config-file= socket= q v daemon working-directory= hold e/command= T/title= class= o/option= h/help V/version
end
function __fish_alacritty_needs_command
@@ -36,6 +36,7 @@ complete -c alacritty -n "__fish_alacritty_needs_command" -l print-events -d 'Pr
complete -c alacritty -n "__fish_alacritty_needs_command" -l ref-test -d 'Generates ref test'
complete -c alacritty -n "__fish_alacritty_needs_command" -s q -d 'Reduces the level of verbosity (the min level is -qq)'
complete -c alacritty -n "__fish_alacritty_needs_command" -s v -d 'Increases the level of verbosity (the max level is -vvv)'
+complete -c alacritty -n "__fish_alacritty_needs_command" -l daemon -d 'Do not spawn an initial window'
complete -c alacritty -n "__fish_alacritty_needs_command" -l hold -d 'Remain open after child process exit'
complete -c alacritty -n "__fish_alacritty_needs_command" -s h -l help -d 'Print help'
complete -c alacritty -n "__fish_alacritty_needs_command" -s V -l version -d 'Print version'
diff --git a/extra/man/alacritty.1.scd b/extra/man/alacritty.1.scd
index c8a67bb8..86630a65 100644
--- a/extra/man/alacritty.1.scd
+++ b/extra/man/alacritty.1.scd
@@ -21,6 +21,10 @@ set of features with high performance.
Remain open after child process exits.
+*--daemon*
+
+ Do not spawn an initial window.
+
*--print-events*
Print all events to STDOUT.