mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
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.
This commit is contained in:
parent
a720a765b4
commit
f5add2b77c
9 changed files with 58 additions and 37 deletions
|
@ -19,6 +19,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its
|
||||||
- Support relative path imports from config files
|
- Support relative path imports from config files
|
||||||
- `alacritty migrate` support for TOML configuration changes
|
- `alacritty migrate` support for TOML configuration changes
|
||||||
- Support for Unicode 16 characters
|
- Support for Unicode 16 characters
|
||||||
|
- Headless mode using `alacritty --daemon`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub struct Options {
|
||||||
pub print_events: bool,
|
pub print_events: bool,
|
||||||
|
|
||||||
/// Generates ref test.
|
/// Generates ref test.
|
||||||
#[clap(long)]
|
#[clap(long, conflicts_with("daemon"))]
|
||||||
pub ref_test: bool,
|
pub ref_test: bool,
|
||||||
|
|
||||||
/// X11 window ID to embed Alacritty within (decimal or hexadecimal with "0x" prefix).
|
/// 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)]
|
#[clap(short, conflicts_with("quiet"), action = ArgAction::Count)]
|
||||||
verbose: u8,
|
verbose: u8,
|
||||||
|
|
||||||
|
/// Do not spawn an initial window.
|
||||||
|
#[clap(long)]
|
||||||
|
pub daemon: bool,
|
||||||
|
|
||||||
/// CLI options for config overrides.
|
/// CLI options for config overrides.
|
||||||
#[clap(skip)]
|
#[clap(skip)]
|
||||||
pub config_options: ParsedOptions,
|
pub config_options: ParsedOptions,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! Process window events.
|
//! Process window events.
|
||||||
|
|
||||||
use crate::ConfigMonitor;
|
use crate::ConfigMonitor;
|
||||||
|
use glutin::config::GetGlConfig;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
@ -16,7 +17,8 @@ use std::{env, f32, mem};
|
||||||
|
|
||||||
use ahash::RandomState;
|
use ahash::RandomState;
|
||||||
use crossfont::Size as FontSize;
|
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 log::{debug, error, info, warn};
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::{
|
use winit::event::{
|
||||||
|
@ -80,7 +82,7 @@ pub struct Processor {
|
||||||
initial_window_error: Option<Box<dyn Error>>,
|
initial_window_error: Option<Box<dyn Error>>,
|
||||||
windows: HashMap<WindowId, WindowContext, RandomState>,
|
windows: HashMap<WindowId, WindowContext, RandomState>,
|
||||||
proxy: EventLoopProxy<Event>,
|
proxy: EventLoopProxy<Event>,
|
||||||
gl_display: Option<GlutinDisplay>,
|
gl_config: Option<GlutinConfig>,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
global_ipc_options: ParsedOptions,
|
global_ipc_options: ParsedOptions,
|
||||||
cli_options: CliOptions,
|
cli_options: CliOptions,
|
||||||
|
@ -121,7 +123,7 @@ impl Processor {
|
||||||
cli_options,
|
cli_options,
|
||||||
proxy,
|
proxy,
|
||||||
scheduler,
|
scheduler,
|
||||||
gl_display: None,
|
gl_config: None,
|
||||||
config: Rc::new(config),
|
config: Rc::new(config),
|
||||||
clipboard,
|
clipboard,
|
||||||
windows: Default::default(),
|
windows: Default::default(),
|
||||||
|
@ -138,12 +140,16 @@ impl Processor {
|
||||||
pub fn create_initial_window(
|
pub fn create_initial_window(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
options: WindowOptions,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let options = match self.initial_window_options.take() {
|
||||||
|
Some(options) => options,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
let window_context =
|
let window_context =
|
||||||
WindowContext::initial(event_loop, self.proxy.clone(), self.config.clone(), options)?;
|
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);
|
self.windows.insert(window_context.id(), window_context);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -155,7 +161,7 @@ impl Processor {
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> 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.
|
// Override config with CLI/IPC options.
|
||||||
let mut config_overrides = options.config_overrides();
|
let mut config_overrides = options.config_overrides();
|
||||||
|
@ -164,9 +170,14 @@ impl Processor {
|
||||||
let mut config = self.config.clone();
|
let mut config = self.config.clone();
|
||||||
config = config_overrides.override_config_rc(config);
|
config = config_overrides.override_config_rc(config);
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
let window_context = WindowContext::additional(
|
||||||
let mut window_context =
|
gl_config,
|
||||||
window.additional(event_loop, self.proxy.clone(), config, options, config_overrides)?;
|
event_loop,
|
||||||
|
self.proxy.clone(),
|
||||||
|
config,
|
||||||
|
options,
|
||||||
|
config_overrides,
|
||||||
|
)?;
|
||||||
|
|
||||||
self.windows.insert(window_context.id(), window_context);
|
self.windows.insert(window_context.id(), window_context);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -210,16 +221,11 @@ impl ApplicationHandler<Event> for Processor {
|
||||||
fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
|
fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
|
||||||
|
|
||||||
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
||||||
if cause != StartCause::Init {
|
if cause != StartCause::Init || self.cli_options.daemon {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let initial_window_options = match self.initial_window_options.take() {
|
if let Err(err) = self.create_initial_window(event_loop) {
|
||||||
Some(initial_window_options) => initial_window_options,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = self.create_initial_window(event_loop, initial_window_options) {
|
|
||||||
self.initial_window_error = Some(err);
|
self.initial_window_error = Some(err);
|
||||||
event_loop.exit();
|
event_loop.exit();
|
||||||
return;
|
return;
|
||||||
|
@ -338,7 +344,13 @@ impl ApplicationHandler<Event> for Processor {
|
||||||
window_context.display.make_not_current();
|
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);
|
error!("Could not open window: {:?}", err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -375,7 +387,7 @@ impl ApplicationHandler<Event> for Processor {
|
||||||
self.scheduler.unschedule_window(window_context.id());
|
self.scheduler.unschedule_window(window_context.id());
|
||||||
|
|
||||||
// Shutdown if no more terminals are open.
|
// 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.
|
// Write ref tests of last window to disk.
|
||||||
if self.config.debug.ref_test {
|
if self.config.debug.ref_test {
|
||||||
window_context.write_ref_test_results();
|
window_context.write_ref_test_results();
|
||||||
|
@ -439,7 +451,7 @@ impl ApplicationHandler<Event> for Processor {
|
||||||
info!("Exiting the event loop");
|
info!("Exiting the event loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.gl_display.take() {
|
match self.gl_config.take().map(|config| config.display()) {
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
Some(glutin::display::Display::Egl(display)) => {
|
Some(glutin::display::Display::Egl(display)) => {
|
||||||
// Ensure that all the windows are dropped, so the destructors for
|
// Ensure that all the windows are dropped, so the destructors for
|
||||||
|
|
|
@ -20,13 +20,13 @@ const ALACRITTY_SOCKET_ENV: &str = "ALACRITTY_SOCKET";
|
||||||
|
|
||||||
/// Create an IPC socket.
|
/// Create an IPC socket.
|
||||||
pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -> Option<PathBuf> {
|
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 socket_path = options.socket.clone().unwrap_or_else(|| {
|
||||||
let mut path = socket_dir();
|
let mut path = socket_dir();
|
||||||
path.push(format!("{}-{}.sock", socket_prefix(), process::id()));
|
path.push(format!("{}-{}.sock", socket_prefix(), process::id()));
|
||||||
path
|
path
|
||||||
});
|
});
|
||||||
env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str());
|
|
||||||
|
|
||||||
let listener = match UnixListener::bind(&socket_path) {
|
let listener = match UnixListener::bind(&socket_path) {
|
||||||
Ok(listener) => listener,
|
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.
|
// Spawn a thread to listen on the IPC socket.
|
||||||
thread::spawn_named("socket listener", move || {
|
thread::spawn_named("socket listener", move || {
|
||||||
let mut data = String::new();
|
let mut data = String::new();
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use glutin::config::GetGlConfig;
|
use glutin::config::Config as GlutinConfig;
|
||||||
use glutin::display::GetGlDisplay;
|
use glutin::display::GetGlDisplay;
|
||||||
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
|
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
|
||||||
use glutin::platform::x11::X11GlConfigExt;
|
use glutin::platform::x11::X11GlConfigExt;
|
||||||
|
@ -119,18 +119,14 @@ impl WindowContext {
|
||||||
|
|
||||||
/// Create additional context with the graphics platform other windows are using.
|
/// Create additional context with the graphics platform other windows are using.
|
||||||
pub fn additional(
|
pub fn additional(
|
||||||
&self,
|
gl_config: &GlutinConfig,
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
proxy: EventLoopProxy<Event>,
|
proxy: EventLoopProxy<Event>,
|
||||||
config: Rc<UiConfig>,
|
config: Rc<UiConfig>,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
config_overrides: ParsedOptions,
|
config_overrides: ParsedOptions,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> 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.display();
|
||||||
let (gl_display, gl_config) = {
|
|
||||||
let gl_context = self.display.gl_context();
|
|
||||||
(gl_context.display(), gl_context.config())
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut identity = config.window.identity.clone();
|
let mut identity = config.window.identity.clone();
|
||||||
options.window_identity.override_identity_config(&mut identity);
|
options.window_identity.override_identity_config(&mut identity);
|
||||||
|
@ -147,11 +143,8 @@ impl WindowContext {
|
||||||
|
|
||||||
// Create context.
|
// Create context.
|
||||||
let raw_window_handle = window.raw_window_handle();
|
let raw_window_handle = window.raw_window_handle();
|
||||||
let gl_context = renderer::platform::create_gl_context(
|
let gl_context =
|
||||||
&gl_display,
|
renderer::platform::create_gl_context(&gl_display, gl_config, Some(raw_window_handle))?;
|
||||||
&gl_config,
|
|
||||||
Some(raw_window_handle),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Check if new window will be opened as a tab.
|
// Check if new window will be opened as a tab.
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
|
|
@ -27,9 +27,10 @@ _alacritty() {
|
||||||
'*-o+[Override configuration file options \[example\: '\''cursor.style="Beam"'\''\]]:OPTION: ' \
|
'*-o+[Override configuration file options \[example\: '\''cursor.style="Beam"'\''\]]:OPTION: ' \
|
||||||
'*--option=[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]' \
|
'--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)]' \
|
'(-v)*-q[Reduces the level of verbosity (the min level is -qq)]' \
|
||||||
'(-q)*-v[Increases the level of verbosity (the max level is -vvv)]' \
|
'(-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]' \
|
'--hold[Remain open after child process exit]' \
|
||||||
'-h[Print help]' \
|
'-h[Print help]' \
|
||||||
'--help[Print help]' \
|
'--help[Print help]' \
|
||||||
|
|
|
@ -61,7 +61,7 @@ _alacritty() {
|
||||||
|
|
||||||
case "${cmd}" in
|
case "${cmd}" in
|
||||||
alacritty)
|
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
|
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Print an optspec for argparse to handle cmd's options that are independent of any subcommand.
|
# Print an optspec for argparse to handle cmd's options that are independent of any subcommand.
|
||||||
function __fish_alacritty_global_optspecs
|
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
|
end
|
||||||
|
|
||||||
function __fish_alacritty_needs_command
|
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" -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 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" -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" -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 h -l help -d 'Print help'
|
||||||
complete -c alacritty -n "__fish_alacritty_needs_command" -s V -l version -d 'Print version'
|
complete -c alacritty -n "__fish_alacritty_needs_command" -s V -l version -d 'Print version'
|
||||||
|
|
|
@ -21,6 +21,10 @@ set of features with high performance.
|
||||||
|
|
||||||
Remain open after child process exits.
|
Remain open after child process exits.
|
||||||
|
|
||||||
|
*--daemon*
|
||||||
|
|
||||||
|
Do not spawn an initial window.
|
||||||
|
|
||||||
*--print-events*
|
*--print-events*
|
||||||
|
|
||||||
Print all events to STDOUT.
|
Print all events to STDOUT.
|
||||||
|
|
Loading…
Reference in a new issue