mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-25 14:05:41 -05:00
Allow setting gtk variant and general class on X11
This commit is contained in:
parent
e398eb8406
commit
228c641769
7 changed files with 107 additions and 53 deletions
|
@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Block selection mode when Control is held while starting a selection
|
- Block selection mode when Control is held while starting a selection
|
||||||
|
- Allow setting general window class on X11 using CLI or config (`window.class.general`)
|
||||||
|
- Config option `window.gtk_theme_variant` to set GTK theme variant
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,17 @@ window:
|
||||||
#title: Alacritty
|
#title: Alacritty
|
||||||
|
|
||||||
# Window class (Linux only):
|
# Window class (Linux only):
|
||||||
#class: Alacritty
|
class:
|
||||||
|
# Application instance name
|
||||||
|
instance: Alacritty
|
||||||
|
# General application class
|
||||||
|
general: Alacritty
|
||||||
|
|
||||||
|
# GTK theme variant (Linux only)
|
||||||
|
#
|
||||||
|
# Override the variant of the GTK theme. Commonly supported values are `dark` and `light`.
|
||||||
|
# Set this to `None` to use the default theme variant.
|
||||||
|
gtk_theme_variant: None
|
||||||
|
|
||||||
scrolling:
|
scrolling:
|
||||||
# Maximum number of lines in the scrollback buffer.
|
# Maximum number of lines in the scrollback buffer.
|
||||||
|
|
|
@ -250,7 +250,14 @@ impl Options {
|
||||||
config.window.dimensions = self.dimensions.unwrap_or(config.window.dimensions);
|
config.window.dimensions = self.dimensions.unwrap_or(config.window.dimensions);
|
||||||
config.window.position = self.position.or(config.window.position);
|
config.window.position = self.position.or(config.window.position);
|
||||||
config.window.title = self.title.or(config.window.title);
|
config.window.title = self.title.or(config.window.title);
|
||||||
config.window.class = self.class.or(config.window.class);
|
|
||||||
|
if let Some(class) = self.class {
|
||||||
|
let parts : Vec<_> = class.split(',').collect();
|
||||||
|
config.window.class.instance = parts[0].into();
|
||||||
|
if let Some(&general) = parts.get(1) {
|
||||||
|
config.window.class.general = general.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config.set_dynamic_title(config.dynamic_title() && config.window.title.is_none());
|
config.set_dynamic_title(config.dynamic_title() && config.window.title.is_none());
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use serde_yaml::Value;
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
mod colors;
|
mod colors;
|
||||||
|
@ -92,7 +94,7 @@ pub struct Config {
|
||||||
pub mouse: Mouse,
|
pub mouse: Mouse,
|
||||||
|
|
||||||
/// Path to a shell program to run on startup
|
/// Path to a shell program to run on startup
|
||||||
#[serde(default, deserialize_with = "failure_default")]
|
#[serde(default, deserialize_with = "from_string_or_deserialize")]
|
||||||
pub shell: Option<Shell<'static>>,
|
pub shell: Option<Shell<'static>>,
|
||||||
|
|
||||||
/// Path where config was loaded from
|
/// Path where config was loaded from
|
||||||
|
@ -134,8 +136,8 @@ pub struct Config {
|
||||||
alt_send_esc: DefaultTrueBool,
|
alt_send_esc: DefaultTrueBool,
|
||||||
|
|
||||||
/// Shell startup directory
|
/// Shell startup directory
|
||||||
#[serde(default, deserialize_with = "failure_default")]
|
#[serde(default, deserialize_with = "option_explicit_none")]
|
||||||
working_directory: WorkingDirectory,
|
working_directory: Option<PathBuf>,
|
||||||
|
|
||||||
/// Debug options
|
/// Debug options
|
||||||
#[serde(default, deserialize_with = "failure_default")]
|
#[serde(default, deserialize_with = "failure_default")]
|
||||||
|
@ -212,37 +214,12 @@ impl Config {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn working_directory(&self) -> &Option<PathBuf> {
|
pub fn working_directory(&self) -> &Option<PathBuf> {
|
||||||
&self.working_directory.0
|
&self.working_directory
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_working_directory(&mut self, working_directory: Option<PathBuf>) {
|
pub fn set_working_directory(&mut self, working_directory: Option<PathBuf>) {
|
||||||
self.working_directory.0 = working_directory;
|
self.working_directory = working_directory;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Eq)]
|
|
||||||
struct WorkingDirectory(Option<PathBuf>);
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for WorkingDirectory {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<WorkingDirectory, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let value = serde_yaml::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
// Accept `None` to use the default path
|
|
||||||
if value.as_str().filter(|v| v.to_lowercase() == "none").is_some() {
|
|
||||||
return Ok(WorkingDirectory(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(match PathBuf::deserialize(value) {
|
|
||||||
Ok(path) => WorkingDirectory(Some(path)),
|
|
||||||
Err(err) => {
|
|
||||||
error!("Problem with config: {}; using None", err);
|
|
||||||
WorkingDirectory(None)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +334,12 @@ impl<'a> Shell<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromString for Option<Shell<'_>> {
|
||||||
|
fn from(input: String) -> Self {
|
||||||
|
Some(Shell::new(input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A delta for a point in a 2 dimensional plane
|
/// A delta for a point in a 2 dimensional plane
|
||||||
#[serde(default, bound(deserialize = "T: Deserialize<'de> + Default"))]
|
#[serde(default, bound(deserialize = "T: Deserialize<'de> + Default"))]
|
||||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
|
||||||
|
@ -418,17 +401,40 @@ impl Default for DefaultTrueBool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fallback_default<T, E>(err: E) -> T
|
||||||
|
where T: Default, E: Display
|
||||||
|
{
|
||||||
|
error!("Problem with config: {}; using default value", err);
|
||||||
|
T::default()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn failure_default<'a, D, T>(deserializer: D) -> Result<T, D::Error>
|
pub fn failure_default<'a, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'a>,
|
D: Deserializer<'a>,
|
||||||
T: Deserialize<'a> + Default,
|
T: Deserialize<'a> + Default,
|
||||||
{
|
{
|
||||||
let value = serde_yaml::Value::deserialize(deserializer)?;
|
Ok(T::deserialize(Value::deserialize(deserializer)?).unwrap_or_else(fallback_default))
|
||||||
match T::deserialize(value) {
|
}
|
||||||
Ok(value) => Ok(value),
|
|
||||||
Err(err) => {
|
pub fn option_explicit_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||||
error!("Problem with config: {}; using default value", err);
|
where D: Deserializer<'de>, T: Deserialize<'de> + Default
|
||||||
Ok(T::default())
|
{
|
||||||
},
|
Ok(match Value::deserialize(deserializer)? {
|
||||||
}
|
Value::String(ref value) if value.to_lowercase() == "none" => None,
|
||||||
|
value => Some(T::deserialize(value).unwrap_or_else(fallback_default))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_string_or_deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||||
|
where D: Deserializer<'de>, T: Deserialize<'de> + FromString + Default
|
||||||
|
{
|
||||||
|
Ok(match Value::deserialize(deserializer)? {
|
||||||
|
Value::String(value) => T::from(value),
|
||||||
|
value => T::deserialize(value).unwrap_or_else(fallback_default)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used over From<String>, to allow implementation for foreign types
|
||||||
|
pub trait FromString {
|
||||||
|
fn from(input: String) -> Self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::config::{failure_default, Delta};
|
use crate::config::{failure_default, option_explicit_none, from_string_or_deserialize, Delta, FromString};
|
||||||
use crate::index::{Column, Line};
|
use crate::index::{Column, Line};
|
||||||
|
use crate::window::DEFAULT_NAME;
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||||
|
@ -33,8 +34,12 @@ pub struct WindowConfig {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
|
|
||||||
/// Window class
|
/// Window class
|
||||||
#[serde(deserialize_with = "failure_default")]
|
#[serde(deserialize_with = "from_string_or_deserialize")]
|
||||||
pub class: Option<String>,
|
pub class: Class,
|
||||||
|
|
||||||
|
/// GTK theme variant
|
||||||
|
#[serde(deserialize_with = "option_explicit_none")]
|
||||||
|
pub gtk_theme_variant: Option<String>,
|
||||||
|
|
||||||
/// TODO: DEPRECATED
|
/// TODO: DEPRECATED
|
||||||
#[serde(deserialize_with = "failure_default")]
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
@ -117,3 +122,23 @@ impl Dimensions {
|
||||||
self.columns.0 as u32
|
self.columns.0 as u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Window class hint
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Class {
|
||||||
|
pub instance: String,
|
||||||
|
pub general: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Class {
|
||||||
|
fn default() -> Self {
|
||||||
|
Class { instance: DEFAULT_NAME.into(), general: DEFAULT_NAME.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromString for Class {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Class { instance: value, general: DEFAULT_NAME.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -151,9 +151,8 @@ impl Window {
|
||||||
dimensions: Option<LogicalSize>,
|
dimensions: Option<LogicalSize>,
|
||||||
) -> Result<Window> {
|
) -> Result<Window> {
|
||||||
let title = config.window.title.as_ref().map_or(DEFAULT_NAME, |t| t);
|
let title = config.window.title.as_ref().map_or(DEFAULT_NAME, |t| t);
|
||||||
let class = config.window.class.as_ref().map_or(DEFAULT_NAME, |c| c);
|
|
||||||
|
|
||||||
let window_builder = Window::get_platform_window(title, class, &config.window);
|
let window_builder = Window::get_platform_window(title, &config.window);
|
||||||
let windowed_context =
|
let windowed_context =
|
||||||
create_gl_window(window_builder.clone(), &event_loop, false, dimensions)
|
create_gl_window(window_builder.clone(), &event_loop, false, dimensions)
|
||||||
.or_else(|_| create_gl_window(window_builder, &event_loop, true, dimensions))?;
|
.or_else(|_| create_gl_window(window_builder, &event_loop, true, dimensions))?;
|
||||||
|
@ -255,7 +254,6 @@ impl Window {
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
pub fn get_platform_window(
|
pub fn get_platform_window(
|
||||||
title: &str,
|
title: &str,
|
||||||
class: &str,
|
|
||||||
window_config: &WindowConfig,
|
window_config: &WindowConfig,
|
||||||
) -> WindowBuilder {
|
) -> WindowBuilder {
|
||||||
use glutin::os::unix::WindowBuilderExt;
|
use glutin::os::unix::WindowBuilderExt;
|
||||||
|
@ -267,7 +265,9 @@ impl Window {
|
||||||
|
|
||||||
let icon = Icon::from_bytes_with_format(WINDOW_ICON, ImageFormat::ICO);
|
let icon = Icon::from_bytes_with_format(WINDOW_ICON, ImageFormat::ICO);
|
||||||
|
|
||||||
WindowBuilder::new()
|
let class = &window_config.class;
|
||||||
|
|
||||||
|
let mut builder = WindowBuilder::new()
|
||||||
.with_title(title)
|
.with_title(title)
|
||||||
.with_visibility(false)
|
.with_visibility(false)
|
||||||
.with_transparency(true)
|
.with_transparency(true)
|
||||||
|
@ -275,15 +275,20 @@ impl Window {
|
||||||
.with_maximized(window_config.startup_mode() == StartupMode::Maximized)
|
.with_maximized(window_config.startup_mode() == StartupMode::Maximized)
|
||||||
.with_window_icon(icon.ok())
|
.with_window_icon(icon.ok())
|
||||||
// X11
|
// X11
|
||||||
.with_class(class.into(), DEFAULT_NAME.into())
|
.with_class(class.instance.clone(), class.general.clone())
|
||||||
// Wayland
|
// Wayland
|
||||||
.with_app_id(class.into())
|
.with_app_id(class.instance.clone());
|
||||||
|
|
||||||
|
if let Some(ref val) = window_config.gtk_theme_variant {
|
||||||
|
builder = builder.with_gtk_theme_variant(val.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
builder
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn get_platform_window(
|
pub fn get_platform_window(
|
||||||
title: &str,
|
title: &str,
|
||||||
_class: &str,
|
|
||||||
window_config: &WindowConfig,
|
window_config: &WindowConfig,
|
||||||
) -> WindowBuilder {
|
) -> WindowBuilder {
|
||||||
let decorations = match window_config.decorations {
|
let decorations = match window_config.decorations {
|
||||||
|
@ -305,7 +310,6 @@ impl Window {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn get_platform_window(
|
pub fn get_platform_window(
|
||||||
title: &str,
|
title: &str,
|
||||||
_class: &str,
|
|
||||||
window_config: &WindowConfig,
|
window_config: &WindowConfig,
|
||||||
) -> WindowBuilder {
|
) -> WindowBuilder {
|
||||||
use glutin::os::macos::WindowBuilderExt;
|
use glutin::os::macos::WindowBuilderExt;
|
||||||
|
|
|
@ -39,8 +39,8 @@ Increases the level of verbosity (the max level is \fB\-vvv\fR)
|
||||||
Prints version information
|
Prints version information
|
||||||
.SH "OPTIONS"
|
.SH "OPTIONS"
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-class\fR <class>
|
\fB\-\-class\fR [ <instance> | <instance>,<general> ]
|
||||||
Defines the window class on Linux [default: Alacritty]
|
Defines the window class hint on Linux [default: Alacritty,Alacritty ]
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-command\fR <command>...
|
\fB\-e\fR, \fB\-\-command\fR <command>...
|
||||||
Command and args to execute (must be last argument)
|
Command and args to execute (must be last argument)
|
||||||
|
|
Loading…
Reference in a new issue