From 8bd2c13490f8cb6ad6b0c1104f9586b3554efea2 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 10 Jul 2020 22:32:44 +0300 Subject: Add option to run command on bell Fixes #1528. --- alacritty/Cargo.toml | 1 + alacritty/src/config/mod.rs | 7 ++++ alacritty/src/config/monitor.rs | 4 +-- alacritty/src/daemon.rs | 76 +++++++++++++++++++++++++++++++++++++++++ alacritty/src/display.rs | 2 +- alacritty/src/event.rs | 21 +++++------- alacritty/src/input.rs | 9 ++--- alacritty/src/main.rs | 1 + alacritty/src/renderer/mod.rs | 4 +-- 9 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 alacritty/src/daemon.rs (limited to 'alacritty') diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml index 6cd63867..9ed2d9ce 100644 --- a/alacritty/Cargo.toml +++ b/alacritty/Cargo.toml @@ -23,6 +23,7 @@ parking_lot = "0.10.2" font = { path = "../font", features = ["force_system_fontconfig"] } urlocator = "0.1.3" copypasta = { version = "0.7.0", default-features = false } +libc = "0.2" unicode-width = "0.1" [build-dependencies] diff --git a/alacritty/src/config/mod.rs b/alacritty/src/config/mod.rs index f416039c..ffa7cbd3 100644 --- a/alacritty/src/config/mod.rs +++ b/alacritty/src/config/mod.rs @@ -217,6 +217,13 @@ fn print_deprecation_warnings(config: &Config) { the config" ); } + + if config.visual_bell.is_some() { + warn!( + target: LOG_TARGET_CONFIG, + "Config visual_bell has been deprecated; please use bell instead" + ) + } } #[cfg(test)] diff --git a/alacritty/src/config/monitor.rs b/alacritty/src/config/monitor.rs index 42603c7e..2ed0c426 100644 --- a/alacritty/src/config/monitor.rs +++ b/alacritty/src/config/monitor.rs @@ -4,7 +4,7 @@ use std::time::Duration; use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; -use alacritty_terminal::util; +use alacritty_terminal::thread; use crate::event::{Event, EventProxy}; @@ -20,7 +20,7 @@ impl Monitor { let path = path.into(); Monitor { - _thread: util::thread::spawn_named("config watcher", move || { + _thread: thread::spawn_named("config watcher", move || { let (tx, rx) = mpsc::channel(); // The Duration argument is a debouncing period. let mut watcher = diff --git a/alacritty/src/daemon.rs b/alacritty/src/daemon.rs new file mode 100644 index 00000000..4a6b6f83 --- /dev/null +++ b/alacritty/src/daemon.rs @@ -0,0 +1,76 @@ +use std::ffi::OsStr; +use std::fmt::Debug; +use std::io; +#[cfg(not(windows))] +use std::os::unix::process::CommandExt; +#[cfg(windows)] +use std::os::windows::process::CommandExt; +use std::process::{Command, Stdio}; + +use log::{debug, warn}; + +#[cfg(windows)] +use winapi::um::winbase::{CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW}; + +/// Start the daemon and log error on failure. +pub fn start_daemon(program: &str, args: I) +where + I: IntoIterator + Debug + Copy, + S: AsRef, +{ + match spawn_daemon(program, args) { + Ok(_) => debug!("Launched {} with args {:?}", program, args), + Err(_) => warn!("Unable to launch {} with args {:?}", program, args), + } +} + +#[cfg(windows)] +fn spawn_daemon(program: &str, args: I) -> io::Result<()> +where + I: IntoIterator + Copy, + S: AsRef, +{ + // Setting all the I/O handles to null and setting the + // CREATE_NEW_PROCESS_GROUP and CREATE_NO_WINDOW has the effect + // that console applications will run without opening a new + // console window. + Command::new(program) + .args(args) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .creation_flags(CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW) + .spawn() + .map(|_| ()) +} + +#[cfg(not(windows))] +fn spawn_daemon(program: &str, args: I) -> io::Result<()> +where + I: IntoIterator + Copy, + S: AsRef, +{ + unsafe { + Command::new(program) + .args(args) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .pre_exec(|| { + match libc::fork() { + -1 => return Err(io::Error::last_os_error()), + 0 => (), + _ => libc::_exit(0), + } + + if libc::setsid() == -1 { + return Err(io::Error::last_os_error()); + } + + Ok(()) + }) + .spawn()? + .wait() + .map(|_| ()) + } +} diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs index 53e6fc58..0a3bea34 100644 --- a/alacritty/src/display.rs +++ b/alacritty/src/display.rs @@ -540,7 +540,7 @@ impl Display { 0., size_info.width, size_info.height, - config.visual_bell.color, + config.bell().color, visual_bell_intensity as f32, ); rects.push(visual_bell_rect); diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index edbc4086..f264aab5 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cmp::{max, min}; use std::env; +use std::fmt::Debug; #[cfg(unix)] use std::fs; use std::fs::File; @@ -20,7 +21,7 @@ use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindow use glutin::platform::desktop::EventLoopExtDesktop; #[cfg(not(any(target_os = "macos", windows)))] use glutin::platform::unix::EventLoopWindowTargetExtUnix; -use log::{debug, info, warn}; +use log::info; use serde_json as json; #[cfg(target_os = "macos")] @@ -38,12 +39,12 @@ use alacritty_terminal::term::cell::Cell; use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode}; #[cfg(not(windows))] use alacritty_terminal::tty; -use alacritty_terminal::util::start_daemon; use crate::cli::Options; use crate::clipboard::Clipboard; use crate::config; use crate::config::Config; +use crate::daemon::start_daemon; use crate::display::{Display, DisplayUpdate}; use crate::input::{self, ActionContext as _, FONT_SIZE_STEP}; use crate::scheduler::{Scheduler, TimerId}; @@ -290,10 +291,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext for ActionCon #[cfg(not(unix))] let args: Vec = Vec::new(); - match start_daemon(&alacritty, &args) { - Ok(_) => debug!("Started new Alacritty process: {} {:?}", alacritty, args), - Err(_) => warn!("Unable to start new Alacritty process: {} {:?}", alacritty, args), - } + start_daemon(&alacritty, &args); } /// Spawn URL launcher when clicking on URLs. @@ -308,10 +306,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext for ActionCon let end = self.terminal.visible_to_buffer(url.end()); args.push(self.terminal.bounds_to_string(start, end)); - match start_daemon(launcher.program(), &args) { - Ok(_) => debug!("Launched {} with args {:?}", launcher.program(), args), - Err(_) => warn!("Unable to launch {} with args {:?}", launcher.program(), args), - } + start_daemon(launcher.program(), &args); } } @@ -839,8 +834,10 @@ impl Processor { Event::TerminalEvent(event) => match event { TerminalEvent::Title(title) => processor.ctx.window.set_title(&title), TerminalEvent::Wakeup => processor.ctx.terminal.dirty = true, - TerminalEvent::Urgent => { - processor.ctx.window.set_urgent(!processor.ctx.terminal.is_focused) + TerminalEvent::Bell => { + let bell_command = processor.ctx.config.bell().command.as_ref(); + let _ = bell_command.map(|cmd| start_daemon(cmd.program(), cmd.args())); + processor.ctx.window.set_urgent(!processor.ctx.terminal.is_focused); }, TerminalEvent::ClipboardStore(clipboard_type, content) => { processor.ctx.clipboard.store(clipboard_type, content); diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 48450b12..cab0f0e2 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -10,7 +10,7 @@ use std::cmp::{max, min, Ordering}; use std::marker::PhantomData; use std::time::{Duration, Instant}; -use log::{debug, trace, warn}; +use log::trace; use glutin::dpi::PhysicalPosition; use glutin::event::{ @@ -30,11 +30,11 @@ use alacritty_terminal::message_bar::{self, Message}; use alacritty_terminal::selection::SelectionType; use alacritty_terminal::term::mode::TermMode; use alacritty_terminal::term::{ClipboardType, SizeInfo, Term}; -use alacritty_terminal::util::start_daemon; use alacritty_terminal::vi_mode::ViMotion; use crate::clipboard::Clipboard; use crate::config::{Action, Binding, Config, Key, ViAction}; +use crate::daemon::start_daemon; use crate::event::{ClickState, Event, Mouse, TYPING_SEARCH_DELAY}; use crate::scheduler::{Scheduler, TimerId}; use crate::url::{Url, Urls}; @@ -160,10 +160,7 @@ impl Execute for Action { let program = program.program(); trace!("Running command {} with args {:?}", program, args); - match start_daemon(program, args) { - Ok(_) => debug!("Spawned new proc"), - Err(err) => warn!("Couldn't run command {}", err), - } + start_daemon(program, args); }, Action::ClearSelection => ctx.clear_selection(), Action::ToggleViMode => ctx.terminal_mut().toggle_vi_mode(), diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs index ab4acaa7..9fbcab55 100644 --- a/alacritty/src/main.rs +++ b/alacritty/src/main.rs @@ -36,6 +36,7 @@ mod cli; mod clipboard; mod config; mod cursor; +mod daemon; mod display; mod event; mod input; diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index 7dc037a1..bd9f4ae7 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -24,7 +24,7 @@ use alacritty_terminal::index::{Column, Line}; use alacritty_terminal::term::cell::{self, Flags}; use alacritty_terminal::term::color::Rgb; use alacritty_terminal::term::{self, CursorKey, RenderableCell, RenderableCellContent, SizeInfo}; -use alacritty_terminal::util; +use alacritty_terminal::thread; use std::fmt::{self, Display, Formatter}; pub mod rects; @@ -660,7 +660,7 @@ impl QuadRenderer { let (msg_tx, msg_rx) = mpsc::channel(); if cfg!(feature = "live-shader-reload") { - util::thread::spawn_named("live shader reload", move || { + thread::spawn_named("live shader reload", move || { let (tx, rx) = std::sync::mpsc::channel(); // The Duration argument is a debouncing period. let mut watcher = -- cgit