mirror of
https://github.com/wez/wezterm.git
synced 2024-12-24 13:52:55 +03:00
bell: allow changing the cursor color when the bell is rung
I find this less distracting than both the audible and the default background color flashing.
This commit is contained in:
parent
3566b82458
commit
ca89181098
@ -48,9 +48,24 @@ pub struct VisualBell {
|
|||||||
pub fade_out_duration_ms: u64,
|
pub fade_out_duration_ms: u64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub fade_out_function: EasingFunction,
|
pub fade_out_function: EasingFunction,
|
||||||
|
#[serde(default)]
|
||||||
|
pub target: VisualBellTarget,
|
||||||
}
|
}
|
||||||
impl_lua_conversion!(VisualBell);
|
impl_lua_conversion!(VisualBell);
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||||
|
pub enum VisualBellTarget {
|
||||||
|
BackgroundColor,
|
||||||
|
CursorColor,
|
||||||
|
}
|
||||||
|
impl_lua_conversion!(VisualBellTarget);
|
||||||
|
|
||||||
|
impl Default for VisualBellTarget {
|
||||||
|
fn default() -> VisualBellTarget {
|
||||||
|
Self::BackgroundColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub enum AudibleBell {
|
pub enum AudibleBell {
|
||||||
SystemBeep,
|
SystemBeep,
|
||||||
|
@ -48,9 +48,8 @@ As features stabilize some brief notes about them will accumulate here.
|
|||||||
* Fixed: Wayland: panic with most recent wlroots. Thanks to [@unrelentingtech](https://github.com/unrelentingtech)! [#1144](https://github.com/wez/wezterm/issues/1144)
|
* Fixed: Wayland: panic with most recent wlroots. Thanks to [@unrelentingtech](https://github.com/unrelentingtech)! [#1144](https://github.com/wez/wezterm/issues/1144)
|
||||||
* Fixed: incorrect spacing for IDEOGRAPHIC SPACE. [#1161](https://github.com/wez/wezterm/issues/1161)
|
* Fixed: incorrect spacing for IDEOGRAPHIC SPACE. [#1161](https://github.com/wez/wezterm/issues/1161)
|
||||||
* Fixed: italic fonts weren't always recognized as being italic, resulting in italic variants being used instead of the non-italic variants in some cases! [#1162](https://github.com/wez/wezterm/issues/1162)
|
* Fixed: italic fonts weren't always recognized as being italic, resulting in italic variants being used instead of the non-italic variants in some cases! [#1162](https://github.com/wez/wezterm/issues/1162)
|
||||||
* New: [bell](config/lua/window-events/bell.md) event allows you to trigger lua code when the bell is run. [#3](https://github.com/wez/wezterm/issues/3)
|
|
||||||
* Fixed: Ask freetype for cell metrics in bitmap-only fonts, rather than simply taking the bitmap width. [#1165](https://github.com/wez/wezterm/issues/1165)
|
* Fixed: Ask freetype for cell metrics in bitmap-only fonts, rather than simply taking the bitmap width. [#1165](https://github.com/wez/wezterm/issues/1165)
|
||||||
* New: [visual_bell](config/lua/config/visual_bell.md) and [audible_bell](config/lua/config/audible_bell.md) configuration options
|
* New: [visual_bell](config/lua/config/visual_bell.md) and [audible_bell](config/lua/config/audible_bell.md) configuration options, as well as a [bell](config/lua/window-events/bell.md) event allows you to trigger lua code when the bell is run. [#3](https://github.com/wez/wezterm/issues/3)
|
||||||
* New: [wezterm.action_callback](config/lua/wezterm/action_callback.md) function to make it easier to use custom events. Thanks to [@bew](https://github.com/bew)! [#1151](https://github.com/wez/wezterm/pull/1151)
|
* New: [wezterm.action_callback](config/lua/wezterm/action_callback.md) function to make it easier to use custom events. Thanks to [@bew](https://github.com/bew)! [#1151](https://github.com/wez/wezterm/pull/1151)
|
||||||
* New: `wezterm connect` now also supports the `--class` parameter to override the window class
|
* New: `wezterm connect` now also supports the `--class` parameter to override the window class
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ There are four fields to the visual_bell config option:
|
|||||||
* `fade_out_duration_ms` - how long it should take for the bell color to fade out, in milliseconds. The default is 0.
|
* `fade_out_duration_ms` - how long it should take for the bell color to fade out, in milliseconds. The default is 0.
|
||||||
* `fade_in_function` - an easing function, similar to [CSS easing functions](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function), that affects how the bell color is faded in.
|
* `fade_in_function` - an easing function, similar to [CSS easing functions](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function), that affects how the bell color is faded in.
|
||||||
* `fade_out_function` - an easing function that affects how the bell color is faded out.
|
* `fade_out_function` - an easing function that affects how the bell color is faded out.
|
||||||
|
* `target` - can be `"BackgroundColor"` (the default) to have the background color of the terminal change when the bell is rung, or `"CursorColor"` to have the cursor color change when the bell is rung.
|
||||||
|
|
||||||
If the total fade in and out durations are 0, then there will be no visual bell indication.
|
If the total fade in and out durations are 0, then there will be no visual bell indication.
|
||||||
|
|
||||||
@ -43,4 +44,16 @@ return {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The follow configuration make the cursor briefly flare when the bell is run:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
return {
|
||||||
|
visual_bell = {
|
||||||
|
fade_in_duration_ms = 75,
|
||||||
|
fade_out_duration_ms = 75,
|
||||||
|
target = "CursorColor",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
See also [audible_bell](audible_bell.md) and [bell event](../window-events/bell.md).
|
See also [audible_bell](audible_bell.md) and [bell event](../window-events/bell.md).
|
||||||
|
@ -15,7 +15,7 @@ use ::window::glium::uniforms::{
|
|||||||
use ::window::glium::{uniform, BlendingFunction, LinearBlendingFactor, Surface};
|
use ::window::glium::{uniform, BlendingFunction, LinearBlendingFactor, Surface};
|
||||||
use ::window::WindowOps;
|
use ::window::WindowOps;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use config::{ConfigHandle, HsbTransform, TextStyle};
|
use config::{ConfigHandle, HsbTransform, TextStyle, VisualBellTarget};
|
||||||
use mux::pane::Pane;
|
use mux::pane::Pane;
|
||||||
use mux::renderable::{RenderableDimensions, StableCursorPosition};
|
use mux::renderable::{RenderableDimensions, StableCursorPosition};
|
||||||
use mux::tab::{PositionedPane, PositionedSplit, SplitDirection};
|
use mux::tab::{PositionedPane, PositionedSplit, SplitDirection};
|
||||||
@ -75,6 +75,7 @@ pub struct ComputeCellFgBgParams<'a> {
|
|||||||
pub selection_bg: LinearRgba,
|
pub selection_bg: LinearRgba,
|
||||||
pub cursor_fg: LinearRgba,
|
pub cursor_fg: LinearRgba,
|
||||||
pub cursor_bg: LinearRgba,
|
pub cursor_bg: LinearRgba,
|
||||||
|
pub pane: &'a Rc<dyn Pane>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ComputeCellFgBgResult {
|
pub struct ComputeCellFgBgResult {
|
||||||
@ -209,6 +210,59 @@ impl super::TermWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_intensity_if_bell_target_ringing(
|
||||||
|
&self,
|
||||||
|
pane: &Rc<dyn Pane>,
|
||||||
|
config: &ConfigHandle,
|
||||||
|
target: VisualBellTarget,
|
||||||
|
) -> Option<f32> {
|
||||||
|
let mut per_pane = self.pane_state(pane.pane_id());
|
||||||
|
if let Some(ringing) = per_pane.bell_start {
|
||||||
|
if config.visual_bell.target == target {
|
||||||
|
let elapsed = ringing.elapsed().as_secs_f32();
|
||||||
|
|
||||||
|
let in_duration =
|
||||||
|
Duration::from_millis(config.visual_bell.fade_in_duration_ms).as_secs_f32();
|
||||||
|
let out_duration =
|
||||||
|
Duration::from_millis(config.visual_bell.fade_out_duration_ms).as_secs_f32();
|
||||||
|
|
||||||
|
let intensity = if elapsed < in_duration {
|
||||||
|
Some(
|
||||||
|
config
|
||||||
|
.visual_bell
|
||||||
|
.fade_in_function
|
||||||
|
.evaluate_at_position(elapsed / in_duration),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let completion = (elapsed - in_duration) / out_duration;
|
||||||
|
if completion >= 1.0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
1.0 - config
|
||||||
|
.visual_bell
|
||||||
|
.fade_out_function
|
||||||
|
.evaluate_at_position(completion),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match intensity {
|
||||||
|
None => {
|
||||||
|
per_pane.bell_start.take();
|
||||||
|
}
|
||||||
|
Some(intensity) => {
|
||||||
|
self.update_next_frame_time(Some(
|
||||||
|
Instant::now() + Duration::from_millis(1000 / config.max_fps as u64),
|
||||||
|
));
|
||||||
|
return Some(intensity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn paint_pane_opengl(
|
pub fn paint_pane_opengl(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: &PositionedPane,
|
pos: &PositionedPane,
|
||||||
@ -386,101 +440,65 @@ impl super::TermWindow {
|
|||||||
{
|
{
|
||||||
// If the bell is ringing, we draw another background layer over the
|
// If the bell is ringing, we draw another background layer over the
|
||||||
// top of this in the configured bell color
|
// top of this in the configured bell color
|
||||||
let mut per_pane = self.pane_state(pos.pane.pane_id());
|
if let Some(intensity) = self.get_intensity_if_bell_target_ringing(
|
||||||
if let Some(ringing) = per_pane.bell_start {
|
&pos.pane,
|
||||||
let elapsed = ringing.elapsed().as_secs_f32();
|
config,
|
||||||
|
VisualBellTarget::BackgroundColor,
|
||||||
|
) {
|
||||||
|
// target background color
|
||||||
|
let (r, g, b, _) = config
|
||||||
|
.resolved_palette
|
||||||
|
.visual_bell
|
||||||
|
.unwrap_or(palette.foreground)
|
||||||
|
.to_linear_tuple_rgba();
|
||||||
|
|
||||||
let in_duration =
|
let background = if window_is_transparent {
|
||||||
Duration::from_millis(config.visual_bell.fade_in_duration_ms).as_secs_f32();
|
// for transparent windows, we fade in the target color
|
||||||
let out_duration =
|
// by adjusting its alpha
|
||||||
Duration::from_millis(config.visual_bell.fade_out_duration_ms).as_secs_f32();
|
LinearRgba::with_components(r, g, b, intensity)
|
||||||
|
|
||||||
let intensity = if elapsed < in_duration {
|
|
||||||
Some(
|
|
||||||
config
|
|
||||||
.visual_bell
|
|
||||||
.fade_in_function
|
|
||||||
.evaluate_at_position(elapsed / in_duration),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let completion = (elapsed - in_duration) / out_duration;
|
// otherwise We'll interpolate between the background color
|
||||||
if completion >= 1.0 {
|
// and the the target color
|
||||||
None
|
let (r1, g1, b1, a) = rgbcolor_alpha_to_window_color(
|
||||||
} else {
|
palette.background,
|
||||||
Some(
|
config.window_background_opacity,
|
||||||
1.0 - config
|
)
|
||||||
.visual_bell
|
.tuple();
|
||||||
.fade_out_function
|
LinearRgba::with_components(
|
||||||
.evaluate_at_position(completion),
|
r1 + (r - r1) * intensity,
|
||||||
)
|
g1 + (g - g1) * intensity,
|
||||||
}
|
b1 + (b - b1) * intensity,
|
||||||
|
a,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
log::trace!("bell color is {:?}", background);
|
||||||
|
|
||||||
match intensity {
|
let mut quad = layers[0].allocate()?;
|
||||||
None => {
|
let cell_width = self.render_metrics.cell_size.width as f32;
|
||||||
per_pane.bell_start.take();
|
let cell_height = self.render_metrics.cell_size.height as f32;
|
||||||
}
|
let pos_x = (self.dimensions.pixel_width as f32 / -2.)
|
||||||
Some(intensity) => {
|
+ (pos.left as f32 * cell_width)
|
||||||
// target background color
|
+ self.config.window_padding.left as f32;
|
||||||
let (r, g, b, _) = config
|
let pos_y = (self.dimensions.pixel_height as f32 / -2.)
|
||||||
.resolved_palette
|
+ ((first_line_offset + pos.top) as f32 * cell_height)
|
||||||
.visual_bell
|
+ self.config.window_padding.top as f32;
|
||||||
.unwrap_or(palette.foreground)
|
|
||||||
.to_linear_tuple_rgba();
|
|
||||||
|
|
||||||
let background = if window_is_transparent {
|
quad.set_position(
|
||||||
// for transparent windows, we fade in the target color
|
pos_x,
|
||||||
// by adjusting its alpha
|
pos_y,
|
||||||
LinearRgba::with_components(r, g, b, intensity)
|
pos_x + pos.width as f32 * cell_width,
|
||||||
} else {
|
pos_y + pos.height as f32 * cell_height,
|
||||||
// otherwise We'll interpolate between the background color
|
);
|
||||||
// and the the target color
|
|
||||||
let (r1, g1, b1, a) = rgbcolor_alpha_to_window_color(
|
|
||||||
palette.background,
|
|
||||||
config.window_background_opacity,
|
|
||||||
)
|
|
||||||
.tuple();
|
|
||||||
LinearRgba::with_components(
|
|
||||||
r1 + (r - r1) * intensity,
|
|
||||||
g1 + (g - g1) * intensity,
|
|
||||||
b1 + (b - b1) * intensity,
|
|
||||||
a,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
log::trace!("bell bg is {:?}", background);
|
|
||||||
|
|
||||||
self.update_next_frame_time(Some(
|
quad.set_texture_adjust(0., 0., 0., 0.);
|
||||||
Instant::now() + Duration::from_millis(1000 / config.max_fps as u64),
|
quad.set_texture(white_space);
|
||||||
));
|
quad.set_is_background();
|
||||||
|
quad.set_fg_color(background);
|
||||||
let mut quad = layers[0].allocate()?;
|
quad.set_hsv(if pos.is_active {
|
||||||
let cell_width = self.render_metrics.cell_size.width as f32;
|
None
|
||||||
let cell_height = self.render_metrics.cell_size.height as f32;
|
} else {
|
||||||
let pos_x = (self.dimensions.pixel_width as f32 / -2.)
|
Some(config.inactive_pane_hsb)
|
||||||
+ (pos.left as f32 * cell_width)
|
});
|
||||||
+ self.config.window_padding.left as f32;
|
|
||||||
let pos_y = (self.dimensions.pixel_height as f32 / -2.)
|
|
||||||
+ ((first_line_offset + pos.top) as f32 * cell_height)
|
|
||||||
+ self.config.window_padding.top as f32;
|
|
||||||
|
|
||||||
quad.set_position(
|
|
||||||
pos_x,
|
|
||||||
pos_y,
|
|
||||||
pos_x + pos.width as f32 * cell_width,
|
|
||||||
pos_y + pos.height as f32 * cell_height,
|
|
||||||
);
|
|
||||||
|
|
||||||
quad.set_texture_adjust(0., 0., 0., 0.);
|
|
||||||
quad.set_texture(white_space);
|
|
||||||
quad.set_is_background();
|
|
||||||
quad.set_fg_color(background);
|
|
||||||
quad.set_hsv(if pos.is_active {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(config.inactive_pane_hsb)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.show_tab_bar && pos.index == 0 {
|
if self.show_tab_bar && pos.index == 0 {
|
||||||
@ -1137,6 +1155,7 @@ impl super::TermWindow {
|
|||||||
selection_bg: params.selection_bg,
|
selection_bg: params.selection_bg,
|
||||||
cursor_fg: params.cursor_fg,
|
cursor_fg: params.cursor_fg,
|
||||||
cursor_bg: params.cursor_bg,
|
cursor_bg: params.cursor_bg,
|
||||||
|
pane: ¶ms.pos.pane,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pos_x = (self.dimensions.pixel_width as f32 / -2.)
|
let pos_x = (self.dimensions.pixel_width as f32 / -2.)
|
||||||
@ -1370,6 +1389,7 @@ impl super::TermWindow {
|
|||||||
selection_bg: params.selection_bg,
|
selection_bg: params.selection_bg,
|
||||||
cursor_fg: params.cursor_fg,
|
cursor_fg: params.cursor_fg,
|
||||||
cursor_bg: params.cursor_bg,
|
cursor_bg: params.cursor_bg,
|
||||||
|
pane: ¶ms.pos.pane,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pos_x = (self.dimensions.pixel_width as f32 / -2.)
|
let pos_x = (self.dimensions.pixel_width as f32 / -2.)
|
||||||
@ -1543,6 +1563,43 @@ impl super::TermWindow {
|
|||||||
let is_cursor =
|
let is_cursor =
|
||||||
params.stable_line_idx == Some(params.cursor.y) && params.cursor.x == params.cell_idx;
|
params.stable_line_idx == Some(params.cursor.y) && params.cursor.x == params.cell_idx;
|
||||||
|
|
||||||
|
if is_cursor {
|
||||||
|
if let Some(intensity) = self.get_intensity_if_bell_target_ringing(
|
||||||
|
params.pane,
|
||||||
|
params.config,
|
||||||
|
VisualBellTarget::CursorColor,
|
||||||
|
) {
|
||||||
|
let (fg_color, bg_color) = if self.config.force_reverse_video_cursor {
|
||||||
|
(params.bg_color, params.fg_color)
|
||||||
|
} else {
|
||||||
|
(params.cursor_fg, params.cursor_bg)
|
||||||
|
};
|
||||||
|
|
||||||
|
// interpolate between the background color
|
||||||
|
// and the the target color
|
||||||
|
let (r1, g1, b1, a) = bg_color.tuple();
|
||||||
|
let (r, g, b, _) = params
|
||||||
|
.config
|
||||||
|
.resolved_palette
|
||||||
|
.visual_bell
|
||||||
|
.map(|c| c.to_linear_tuple_rgba())
|
||||||
|
.unwrap_or_else(|| fg_color.tuple());
|
||||||
|
|
||||||
|
let bg_color = LinearRgba::with_components(
|
||||||
|
r1 + (r - r1) * intensity,
|
||||||
|
g1 + (g - g1) * intensity,
|
||||||
|
b1 + (b - b1) * intensity,
|
||||||
|
a,
|
||||||
|
);
|
||||||
|
|
||||||
|
return ComputeCellFgBgResult {
|
||||||
|
fg_color,
|
||||||
|
bg_color,
|
||||||
|
cursor_shape: Some(CursorShape::SteadyBlock),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (cursor_shape, visibility) =
|
let (cursor_shape, visibility) =
|
||||||
if is_cursor && params.cursor.visibility == CursorVisibility::Visible {
|
if is_cursor && params.cursor.visibility == CursorVisibility::Visible {
|
||||||
// This logic figures out whether the cursor is visible or not.
|
// This logic figures out whether the cursor is visible or not.
|
||||||
|
Loading…
Reference in New Issue
Block a user