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
|
||||
|
||||
- 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
|
||||
|
||||
|
|
|
@ -66,7 +66,17 @@ window:
|
|||
#title: Alacritty
|
||||
|
||||
# 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:
|
||||
# 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.position = self.position.or(config.window.position);
|
||||
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());
|
||||
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde_yaml::Value;
|
||||
|
||||
mod bindings;
|
||||
mod colors;
|
||||
|
@ -92,7 +94,7 @@ pub struct Config {
|
|||
pub mouse: Mouse,
|
||||
|
||||
/// 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>>,
|
||||
|
||||
/// Path where config was loaded from
|
||||
|
@ -134,8 +136,8 @@ pub struct Config {
|
|||
alt_send_esc: DefaultTrueBool,
|
||||
|
||||
/// Shell startup directory
|
||||
#[serde(default, deserialize_with = "failure_default")]
|
||||
working_directory: WorkingDirectory,
|
||||
#[serde(default, deserialize_with = "option_explicit_none")]
|
||||
working_directory: Option<PathBuf>,
|
||||
|
||||
/// Debug options
|
||||
#[serde(default, deserialize_with = "failure_default")]
|
||||
|
@ -212,37 +214,12 @@ impl Config {
|
|||
|
||||
#[inline]
|
||||
pub fn working_directory(&self) -> &Option<PathBuf> {
|
||||
&self.working_directory.0
|
||||
&self.working_directory
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_working_directory(&mut self, working_directory: Option<PathBuf>) {
|
||||
self.working_directory.0 = 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)
|
||||
},
|
||||
})
|
||||
self.working_directory = working_directory;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
#[serde(default, bound(deserialize = "T: Deserialize<'de> + Default"))]
|
||||
#[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>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
T: Deserialize<'a> + Default,
|
||||
{
|
||||
let value = serde_yaml::Value::deserialize(deserializer)?;
|
||||
match T::deserialize(value) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) => {
|
||||
error!("Problem with config: {}; using default value", err);
|
||||
Ok(T::default())
|
||||
},
|
||||
}
|
||||
Ok(T::deserialize(Value::deserialize(deserializer)?).unwrap_or_else(fallback_default))
|
||||
}
|
||||
|
||||
pub fn option_explicit_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||
where D: Deserializer<'de>, T: Deserialize<'de> + 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::window::DEFAULT_NAME;
|
||||
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
|
@ -33,8 +34,12 @@ pub struct WindowConfig {
|
|||
pub title: Option<String>,
|
||||
|
||||
/// Window class
|
||||
#[serde(deserialize_with = "failure_default")]
|
||||
pub class: Option<String>,
|
||||
#[serde(deserialize_with = "from_string_or_deserialize")]
|
||||
pub class: Class,
|
||||
|
||||
/// GTK theme variant
|
||||
#[serde(deserialize_with = "option_explicit_none")]
|
||||
pub gtk_theme_variant: Option<String>,
|
||||
|
||||
/// TODO: DEPRECATED
|
||||
#[serde(deserialize_with = "failure_default")]
|
||||
|
@ -117,3 +122,23 @@ impl Dimensions {
|
|||
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>,
|
||||
) -> Result<Window> {
|
||||
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 =
|
||||
create_gl_window(window_builder.clone(), &event_loop, false, 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)))]
|
||||
pub fn get_platform_window(
|
||||
title: &str,
|
||||
class: &str,
|
||||
window_config: &WindowConfig,
|
||||
) -> WindowBuilder {
|
||||
use glutin::os::unix::WindowBuilderExt;
|
||||
|
@ -267,7 +265,9 @@ impl Window {
|
|||
|
||||
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_visibility(false)
|
||||
.with_transparency(true)
|
||||
|
@ -275,15 +275,20 @@ impl Window {
|
|||
.with_maximized(window_config.startup_mode() == StartupMode::Maximized)
|
||||
.with_window_icon(icon.ok())
|
||||
// X11
|
||||
.with_class(class.into(), DEFAULT_NAME.into())
|
||||
.with_class(class.instance.clone(), class.general.clone())
|
||||
// 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)]
|
||||
pub fn get_platform_window(
|
||||
title: &str,
|
||||
_class: &str,
|
||||
window_config: &WindowConfig,
|
||||
) -> WindowBuilder {
|
||||
let decorations = match window_config.decorations {
|
||||
|
@ -305,7 +310,6 @@ impl Window {
|
|||
#[cfg(target_os = "macos")]
|
||||
pub fn get_platform_window(
|
||||
title: &str,
|
||||
_class: &str,
|
||||
window_config: &WindowConfig,
|
||||
) -> WindowBuilder {
|
||||
use glutin::os::macos::WindowBuilderExt;
|
||||
|
|
|
@ -39,8 +39,8 @@ Increases the level of verbosity (the max level is \fB\-vvv\fR)
|
|||
Prints version information
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
\fB\-\-class\fR <class>
|
||||
Defines the window class on Linux [default: Alacritty]
|
||||
\fB\-\-class\fR [ <instance> | <instance>,<general> ]
|
||||
Defines the window class hint on Linux [default: Alacritty,Alacritty ]
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-command\fR <command>...
|
||||
Command and args to execute (must be last argument)
|
||||
|
|
Loading…
Reference in a new issue