diff --git a/CHANGELOG.md b/CHANGELOG.md index a71e218b..19e827e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Block cursor is no longer inverted at the start/end of a selection - Preserve selection on non-LMB or mouse mode clicks +- Wayland client side decorations are now based on config colorscheme ### Fixed - Tabstops not being reset with `reset` diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 9757893d..89aa8be6 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -7,6 +7,7 @@ use std::fs; use std::fs::File; use std::io::Write; use std::mem; +use std::path::PathBuf; use std::sync::Arc; use std::time::Instant; @@ -14,6 +15,8 @@ use glutin::dpi::PhysicalSize; use glutin::event::{ElementState, Event as GlutinEvent, ModifiersState, MouseButton, WindowEvent}; use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}; use glutin::platform::desktop::EventLoopExtDesktop; +#[cfg(not(any(target_os = "macos", windows)))] +use glutin::platform::unix::EventLoopWindowTargetExtUnix; use log::{debug, info, warn}; use serde_json as json; @@ -522,31 +525,7 @@ impl Processor { Event::Urgent => { processor.ctx.window.set_urgent(!processor.ctx.terminal.is_focused) }, - Event::ConfigReload(path) => { - processor.ctx.message_buffer.remove_target(LOG_TARGET_CONFIG); - processor.ctx.display_update_pending.message_buffer = Some(()); - - if let Ok(config) = config::reload_from(&path) { - let options = Options::new(); - let config = options.into_config(config); - - processor.ctx.terminal.update_config(&config); - - if processor.ctx.config.font != config.font { - // Do not update font size if it has been changed at runtime - if *processor.ctx.font_size == processor.ctx.config.font.size { - *processor.ctx.font_size = config.font.size; - } - - let font = config.font.clone().with_size(*processor.ctx.font_size); - processor.ctx.display_update_pending.font = Some(font); - } - - *processor.ctx.config = config; - - processor.ctx.terminal.dirty = true; - } - }, + Event::ConfigReload(path) => Self::reload_config(&path, processor), Event::Message(message) => { processor.ctx.message_buffer.push(message); processor.ctx.display_update_pending.message_buffer = Some(()); @@ -675,6 +654,47 @@ impl Processor { } } + pub fn reload_config( + path: &PathBuf, + processor: &mut input::Processor>, + ) where + T: EventListener, + { + processor.ctx.message_buffer.remove_target(LOG_TARGET_CONFIG); + processor.ctx.display_update_pending.message_buffer = Some(()); + + let config = match config::reload_from(&path) { + Ok(config) => config, + Err(_) => return, + }; + + let options = Options::new(); + let config = options.into_config(config); + + processor.ctx.terminal.update_config(&config); + + if processor.ctx.config.font != config.font { + // Do not update font size if it has been changed at runtime + if *processor.ctx.font_size == processor.ctx.config.font.size { + *processor.ctx.font_size = config.font.size; + } + + let font = config.font.clone().with_size(*processor.ctx.font_size); + processor.ctx.display_update_pending.font = Some(font); + } + + #[cfg(not(any(target_os = "macos", windows)))] + { + if processor.ctx.event_loop.is_wayland() { + processor.ctx.window.set_wayland_theme(&config.colors); + } + } + + *processor.ctx.config = config; + + processor.ctx.terminal.dirty = true; + } + // Write the ref test results to the disk pub fn write_ref_test_results(&self, terminal: &Term) { if !self.config.debug.ref_test { diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs index db08245a..ca912943 100644 --- a/alacritty/src/main.rs +++ b/alacritty/src/main.rs @@ -58,6 +58,9 @@ mod renderer; mod url; mod window; +#[cfg(not(any(target_os = "macos", windows)))] +mod wayland_theme; + mod gl { #![allow(clippy::all)] include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); diff --git a/alacritty/src/wayland_theme.rs b/alacritty/src/wayland_theme.rs new file mode 100644 index 00000000..b1d4b44c --- /dev/null +++ b/alacritty/src/wayland_theme.rs @@ -0,0 +1,82 @@ +use glutin::platform::unix::{ButtonState, Theme as WaylandTheme}; + +use alacritty_terminal::config::Colors; +use alacritty_terminal::term::color::{Rgb, DIM_FACTOR}; + +#[derive(Debug, Clone)] +pub struct AlacrittyWaylandTheme { + pub background: Rgb, + pub foreground: Rgb, + pub dim_foreground: Rgb, + pub hovered_close_icon: Rgb, + pub hovered_maximize_icon: Rgb, + pub hovered_minimize_icon: Rgb, +} + +impl AlacrittyWaylandTheme { + pub fn new(colors: &Colors) -> Self { + let hovered_close_icon = colors.normal().red; + let hovered_maximize_icon = colors.normal().green; + let hovered_minimize_icon = colors.normal().yellow; + let foreground = colors.primary.foreground; + let background = colors.primary.background; + let dim_foreground = colors.primary.dim_foreground.unwrap_or(foreground * DIM_FACTOR); + + Self { + foreground, + background, + dim_foreground, + hovered_close_icon, + hovered_minimize_icon, + hovered_maximize_icon, + } + } + + fn color_icon_color(&self, color: Rgb, status: ButtonState) -> [u8; 4] { + match status { + ButtonState::Hovered => [0xff, color.r, color.g, color.b], + ButtonState::Idle => [0xff, self.foreground.r, self.foreground.g, self.foreground.b], + ButtonState::Disabled => { + [0xff, self.dim_foreground.r, self.dim_foreground.g, self.dim_foreground.b] + }, + } + } +} + +impl WaylandTheme for AlacrittyWaylandTheme { + fn primary_color(&self, _window_active: bool) -> [u8; 4] { + [0xff, self.background.r, self.background.g, self.background.b] + } + + fn secondary_color(&self, window_active: bool) -> [u8; 4] { + if window_active { + [0xff, self.foreground.r, self.foreground.g, self.foreground.b] + } else { + [0xff, self.dim_foreground.r, self.dim_foreground.g, self.dim_foreground.b] + } + } + + fn close_button_color(&self, _status: ButtonState) -> [u8; 4] { + [0x00, self.background.r, self.background.g, self.background.b] + } + + fn close_button_icon_color(&self, status: ButtonState) -> [u8; 4] { + self.color_icon_color(self.hovered_close_icon, status) + } + + fn maximize_button_color(&self, _status: ButtonState) -> [u8; 4] { + [0x00, self.background.r, self.background.g, self.background.b] + } + + fn maximize_button_icon_color(&self, status: ButtonState) -> [u8; 4] { + self.color_icon_color(self.hovered_maximize_icon, status) + } + + fn minimize_button_color(&self, _status: ButtonState) -> [u8; 4] { + [0x00, self.background.r, self.background.g, self.background.b] + } + + fn minimize_button_icon_color(&self, status: ButtonState) -> [u8; 4] { + self.color_icon_color(self.hovered_minimize_icon, status) + } +} diff --git a/alacritty/src/window.rs b/alacritty/src/window.rs index 71327bac..feb09c61 100644 --- a/alacritty/src/window.rs +++ b/alacritty/src/window.rs @@ -33,6 +33,8 @@ use image::ImageFormat; #[cfg(not(any(target_os = "macos", windows)))] use x11_dl::xlib::{Display as XDisplay, PropModeReplace, XErrorEvent, Xlib}; +#[cfg(not(any(target_os = "macos", windows)))] +use alacritty_terminal::config::Colors; use alacritty_terminal::config::{Decorations, StartupMode, WindowConfig}; use alacritty_terminal::event::Event; #[cfg(not(windows))] @@ -40,6 +42,8 @@ use alacritty_terminal::term::{SizeInfo, Term}; use crate::config::Config; use crate::gl; +#[cfg(not(any(target_os = "macos", windows)))] +use crate::wayland_theme::AlacrittyWaylandTheme; // It's required to be in this directory due to the `windows.rc` file #[cfg(not(target_os = "macos"))] @@ -158,6 +162,9 @@ impl Window { if let Some(parent_window_id) = config.window.embed { x_embed_window(windowed_context.window(), parent_window_id); } + } else { + let theme = AlacrittyWaylandTheme::new(&config.colors); + windowed_context.window().set_wayland_theme(theme); } } @@ -361,6 +368,11 @@ impl Window { self.window().wayland_display() } + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + pub fn set_wayland_theme(&mut self, colors: &Colors) { + self.window().set_wayland_theme(AlacrittyWaylandTheme::new(colors)); + } + /// Adjust the IME editor position according to the new location of the cursor #[cfg(not(windows))] pub fn update_ime_position(&mut self, terminal: &Term, size_info: &SizeInfo) { diff --git a/alacritty_terminal/src/term/color.rs b/alacritty_terminal/src/term/color.rs index b452245e..f9d7cf3a 100644 --- a/alacritty_terminal/src/term/color.rs +++ b/alacritty_terminal/src/term/color.rs @@ -11,6 +11,9 @@ use crate::config::{Colors, LOG_TARGET_CONFIG}; pub const COUNT: usize = 269; +/// Factor for automatic computation of dim colors used by terminal. +pub const DIM_FACTOR: f32 = 0.66; + pub const RED: Rgb = Rgb { r: 0xff, g: 0x0, b: 0x0 }; pub const YELLOW: Rgb = Rgb { r: 0xff, g: 0xff, b: 0x0 }; @@ -181,7 +184,7 @@ impl List { // Dims self[ansi::NamedColor::DimForeground] = - colors.primary.dim_foreground.unwrap_or(colors.primary.foreground * 0.66); + colors.primary.dim_foreground.unwrap_or(colors.primary.foreground * DIM_FACTOR); match colors.dim { Some(ref dim) => { trace!("Using config-provided dim colors"); @@ -196,14 +199,14 @@ impl List { }, None => { trace!("Deriving dim colors from normal colors"); - self[ansi::NamedColor::DimBlack] = colors.normal().black * 0.66; - self[ansi::NamedColor::DimRed] = colors.normal().red * 0.66; - self[ansi::NamedColor::DimGreen] = colors.normal().green * 0.66; - self[ansi::NamedColor::DimYellow] = colors.normal().yellow * 0.66; - self[ansi::NamedColor::DimBlue] = colors.normal().blue * 0.66; - self[ansi::NamedColor::DimMagenta] = colors.normal().magenta * 0.66; - self[ansi::NamedColor::DimCyan] = colors.normal().cyan * 0.66; - self[ansi::NamedColor::DimWhite] = colors.normal().white * 0.66; + self[ansi::NamedColor::DimBlack] = colors.normal().black * DIM_FACTOR; + self[ansi::NamedColor::DimRed] = colors.normal().red * DIM_FACTOR; + self[ansi::NamedColor::DimGreen] = colors.normal().green * DIM_FACTOR; + self[ansi::NamedColor::DimYellow] = colors.normal().yellow * DIM_FACTOR; + self[ansi::NamedColor::DimBlue] = colors.normal().blue * DIM_FACTOR; + self[ansi::NamedColor::DimMagenta] = colors.normal().magenta * DIM_FACTOR; + self[ansi::NamedColor::DimCyan] = colors.normal().cyan * DIM_FACTOR; + self[ansi::NamedColor::DimWhite] = colors.normal().white * DIM_FACTOR; }, } }