2024-03-06 19:49:15 +00:00
|
|
|
|
use std::{borrow::BorrowMut, str::FromStr};
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
use log::trace;
|
|
|
|
|
use serde::{de::Expected, Deserialize, Serialize};
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
use crate::{
|
|
|
|
|
hlwm::{command::CommandParseError, parser::ArgParser},
|
|
|
|
|
split,
|
|
|
|
|
};
|
2024-02-29 20:36:38 +00:00
|
|
|
|
use strum::IntoEnumIterator;
|
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
use super::{
|
|
|
|
|
color::Color,
|
|
|
|
|
hlwmbool::ToggleBool,
|
|
|
|
|
parser::{FromCommandArgs, ParseError},
|
|
|
|
|
ToCommandString,
|
|
|
|
|
};
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, strum::Display, strum::EnumIter, PartialEq, strum::EnumDiscriminants)]
|
|
|
|
|
#[strum_discriminants(
|
|
|
|
|
name(SettingName),
|
|
|
|
|
derive(strum::Display, strum::EnumIter),
|
|
|
|
|
strum(serialize_all = "snake_case")
|
|
|
|
|
)]
|
|
|
|
|
#[strum(serialize_all = "snake_case")]
|
|
|
|
|
pub enum Setting {
|
|
|
|
|
/// If set, detect_monitors is automatically executed every time a monitor is connected, disconnected or resized.
|
|
|
|
|
AutoDetectMonitors(ToggleBool),
|
|
|
|
|
/// If set, EWMH panels are automatically detected and reserve space at the side of the monitors
|
|
|
|
|
/// they are on (via pad attributes of each monitor).
|
|
|
|
|
/// This setting is activated per default.
|
|
|
|
|
AutoDetectPanels(ToggleBool),
|
|
|
|
|
/// This setting controls the behaviour of focus and shift if no -e or -i argument is given.
|
|
|
|
|
/// If set, then focus and shift changes the focused frame even if there are other clients
|
|
|
|
|
/// in this frame in the specified direction.
|
|
|
|
|
/// Else, a client within current frame is selected if it is in the specified direction.
|
|
|
|
|
DefaultDirectionExternalOnly(ToggleBool),
|
|
|
|
|
/// Name of the layout algorithm, which is used if a new frame is created (on a new tag or by a non-trivial split).
|
|
|
|
|
DefaultFrameLayout(FrameLayout),
|
|
|
|
|
/// String to append when window or tab titles are shortened to fit in the available space
|
|
|
|
|
Ellipsis(String),
|
|
|
|
|
/// If set, commands [HlwmCommand::Focus] and [HlwmCommand::Shift] cross monitor boundaries.
|
|
|
|
|
/// If there is no client in the direction given to focus, then the monitor in the specified
|
|
|
|
|
/// direction is focused.
|
|
|
|
|
/// Similarly, if shift cannot move a window within a tag, the window is moved to the
|
|
|
|
|
/// neighbour monitor in the desired direction.
|
|
|
|
|
FocusCrossesMonitorBoundaries(ToggleBool),
|
|
|
|
|
/// If set and a window is focused by mouse cursor, this window is focused
|
|
|
|
|
/// (this feature is also known as sloppy focus).
|
|
|
|
|
/// If unset, you need to click to change the window focus by mouse.
|
|
|
|
|
///
|
|
|
|
|
/// If another window is hidden by the focus change
|
|
|
|
|
/// (e.g. when having pseudotiled windows in the max layout)
|
|
|
|
|
/// then an extra click is required to change the focus.
|
|
|
|
|
FocusFollowsMouse(ToggleBool),
|
|
|
|
|
/// If set, only pagers and taskbars are allowed to change the focus. If unset, all applications can request a
|
|
|
|
|
/// focus change
|
|
|
|
|
FocusStealingPrevention(ToggleBool),
|
|
|
|
|
/// Focused frame opacity in percent. Requires a running compositing manager to take actual effect.
|
|
|
|
|
FrameActiveOpacity(u8),
|
|
|
|
|
/// The fill color of a focused frame
|
|
|
|
|
FrameBgActiveColor(Color),
|
|
|
|
|
/// The fill color of an unfocused frame
|
|
|
|
|
/// It is only visible if non-focused frames are configured to be visible, see [ShowFrameDecoration].
|
|
|
|
|
FrameBgNormalColor(Color),
|
|
|
|
|
/// If set, the background of frames are transparent.
|
|
|
|
|
/// That means a rectangle is cut out from the inner such that only the frame border
|
|
|
|
|
/// and a stripe of width [Setting::FrameTransparentWidth] can be seen.
|
|
|
|
|
/// Use [Setting::FrameActiveOpacity] and [Setting::FrameNormalOpacity] for real transparency.
|
|
|
|
|
FrameBgTransparent(ToggleBool),
|
|
|
|
|
/// The border color of a focused frame
|
|
|
|
|
FrameBorderActiveColor(Color),
|
|
|
|
|
/// The color of the inner border of a frame
|
|
|
|
|
FrameBorderInnerColor(Color),
|
|
|
|
|
/// The width of the inner border of a frame.
|
|
|
|
|
/// Must be less than [Setting::FrameBorderWidth], since it does not add to the frame border width but is a
|
|
|
|
|
/// part of it.
|
|
|
|
|
FrameBorderInnerWidth(u32),
|
|
|
|
|
/// The border color of an unfocused frame
|
|
|
|
|
FrameBorderNormalColor(Color),
|
|
|
|
|
/// Border width of a frame
|
|
|
|
|
FrameBorderWidth(u32),
|
|
|
|
|
/// The gap between frames in the tiling mode
|
|
|
|
|
FrameGap(u32),
|
|
|
|
|
/// Unfocused frame opacity in percent.
|
|
|
|
|
/// Requires a running compositing manager to take actual effect
|
|
|
|
|
FrameNormalOpacity(u8),
|
|
|
|
|
/// The padding within a frame in the tiling mode
|
|
|
|
|
/// i.e. the space between the border of a frame and the windows within it
|
|
|
|
|
FramePadding(u32),
|
|
|
|
|
/// Specifies the width of the remaining frame colored with [Setting::FrameBgActiveColor]
|
|
|
|
|
/// if [Setting::FrameBgTransparent] is set
|
|
|
|
|
FrameTransparentWidth(u32),
|
|
|
|
|
/// This setting affects the size of the last client in a frame that is arranged by grid layout.
|
|
|
|
|
/// If set, then the last client always fills the gap within this frame.
|
|
|
|
|
/// If unset, then the last client has the same size as all other clients in this frame
|
|
|
|
|
GaplessGrid(ToggleBool),
|
|
|
|
|
/// If activated, windows are explicitly hidden when they are covered by another window in a frame with max layout.
|
|
|
|
|
/// This only has a visible effect if a compositor is used.
|
|
|
|
|
/// If activated, shadows do not stack up and transparent windows show the wallpaper behind them instead of
|
|
|
|
|
/// the other clients in the max layout.
|
|
|
|
|
HideCoveredWindows(ToggleBool),
|
|
|
|
|
/// If greater than 0, then the clients on all monitors aren’t moved or resized anymore.
|
|
|
|
|
/// If it is set to 0, then the arranging of monitors is enabled again, and all monitors are rearranged
|
|
|
|
|
/// if their content has changed in the meantime.
|
|
|
|
|
/// You should not change this setting manually due to concurrency issues;
|
|
|
|
|
/// use the commands [HlwmCommand::Lock] and [HlwmCommand::Unlock] instead.
|
|
|
|
|
MonitorsLocked(u8),
|
|
|
|
|
/// Specifies the gap around a monitor.
|
|
|
|
|
/// If the monitor is selected and the mouse position would be restored into this gap,
|
|
|
|
|
/// it is set to the center of the monitor.
|
|
|
|
|
/// This is useful, when the monitor was left via mouse movement, but is reselected by keyboard.
|
|
|
|
|
/// If the gap is 0 (default), the mouse is never recentered
|
|
|
|
|
MouseRecenterGap(u32),
|
|
|
|
|
/// If greater than 0, it specifies the least distance between a centered pseudotile window
|
|
|
|
|
/// and the border of the frame or tile it is assigned to.
|
|
|
|
|
/// If this distance is lower than pseudotile_center_threshold, it is aligned to the top left
|
|
|
|
|
/// of the client’s tile.
|
|
|
|
|
PseudotileCenterThreshold(u32),
|
|
|
|
|
/// If set, a window is raised if it is clicked. The value of this setting is only noticed in floating mode
|
|
|
|
|
RaiseOnClick(ToggleBool),
|
|
|
|
|
/// If set, a window is raised if it is focused. The value of this setting is only used in floating mode
|
|
|
|
|
RaiseOnFocus(ToggleBool),
|
|
|
|
|
/// If set, a window is raised temporarily if it is focused on its tag.
|
|
|
|
|
/// Temporarily in this case means that the window will return to its previous stacking position
|
|
|
|
|
/// if another window is focused
|
|
|
|
|
RaiseOnFocusTemporarily(ToggleBool),
|
|
|
|
|
/// This controls, which frame decorations are shown (or none at all)
|
|
|
|
|
ShowFrameDecorations(ShowFrameDecoration),
|
|
|
|
|
/// See the docs for members of [SmartFrameSurroundings]
|
|
|
|
|
SmartFrameSurroundings(SmartFrameSurroundings),
|
|
|
|
|
/// If set, window borders and gaps will be removed and minimal when there’s no
|
|
|
|
|
/// ambiguity regarding the focused window.
|
|
|
|
|
/// This minimal window decoration can be configured by the `theme.minimal` object.
|
|
|
|
|
SmartWindowSurroundings(ToggleBool),
|
|
|
|
|
/// If a client is dragged in floating mode, then it snaps to neighbour clients
|
|
|
|
|
/// if the distance between them is smaller than SnapDistance
|
|
|
|
|
SnapDistance(u32),
|
|
|
|
|
/// Specifies the remaining gap if a dragged client snaps to an edge in floating mode.
|
|
|
|
|
/// If SnapGap is set to 0, no gap will remain
|
|
|
|
|
SnapGap(u32),
|
|
|
|
|
/// If set: If you want to view a tag, that already is viewed on another monitor,
|
|
|
|
|
/// then the monitor contents will be swapped and you see the wanted tag on the focused monitor.
|
|
|
|
|
/// If not set, the other monitor is focused if it shows the desired tag.
|
|
|
|
|
SwapMonitorsToGetTag(ToggleBool),
|
|
|
|
|
/// If activated, multiple windows in a frame with the max layout algorithm are drawn as tabs
|
|
|
|
|
TabbedMax(ToggleBool),
|
|
|
|
|
/// It contains the chars that are used to print a nice ascii tree.
|
|
|
|
|
/// It must contain at least 8 characters. e.g. `X|:#+*-.` produces a tree like:
|
|
|
|
|
/// ```
|
|
|
|
|
/// X-.
|
|
|
|
|
/// #-. child 0
|
|
|
|
|
/// | #-* child 00
|
|
|
|
|
/// | +-* child 01
|
|
|
|
|
/// +-. child 1
|
|
|
|
|
/// : #-* child 10
|
|
|
|
|
/// : +-* child 11
|
|
|
|
|
/// ```
|
|
|
|
|
/// Useful values for tree_style are: `╾│ ├└╼─┐` or `-| |'--.` or `╾│ ├╰╼─╮.`
|
|
|
|
|
TreeStyle(String),
|
|
|
|
|
/// If set, a client's window content is resized immediately during resizing it with the mouse.
|
|
|
|
|
/// If unset, the client's content is resized after the mouse button is released.
|
|
|
|
|
UpdateDraggedClients(ToggleBool),
|
|
|
|
|
/// If set, verbose output is logged to herbstluftwm’s stderr.
|
|
|
|
|
/// The default value is controlled by the `--verbose` command line flag
|
|
|
|
|
Verbose(ToggleBool),
|
|
|
|
|
/// Border color of a focused window
|
|
|
|
|
/// **Warning:**
|
|
|
|
|
/// This only exists for compatibility reasons; it is only an alias for the attribute `theme.active.color`
|
|
|
|
|
WindowBorderActiveColor(Color),
|
|
|
|
|
/// Color of the inner border of a window.
|
|
|
|
|
/// **Warning:**
|
|
|
|
|
/// This only exists for compatibility reasons; it is only an alias for the attribute `theme.inner_color`
|
|
|
|
|
WindowBorderInnerColor(Color),
|
|
|
|
|
/// The width of the inner border of a window.
|
|
|
|
|
/// Must be less than window_border_width, since it does not add to the window border width but is a part of it.
|
|
|
|
|
/// **Warning:**
|
|
|
|
|
/// This only exists for compatibility reasons; it is only an alias for the attribute `theme.inner_width`
|
|
|
|
|
WindowBorderInnerWidth(u32),
|
|
|
|
|
/// Border color of an unfocused window
|
|
|
|
|
/// **Warning:**
|
|
|
|
|
/// This only exists for compatibility reasons; it is only an alias for the attribute `theme.normal.color`
|
|
|
|
|
WindowBorderNormalColor(Color),
|
|
|
|
|
/// Border color of an unfocused but urgent window.
|
|
|
|
|
/// **Warning:**
|
|
|
|
|
/// This only exists for compatibility reasons; it is only an alias for the attribute `theme.urgent.color`
|
|
|
|
|
WindowBorderUrgentColor(Color),
|
|
|
|
|
/// Border width of a window
|
|
|
|
|
/// **Warning:**
|
|
|
|
|
/// This only exists for compatibility reasons; it is only an alias for the attribute `theme.border_width`
|
|
|
|
|
WindowBorderWidth(u32),
|
|
|
|
|
/// The gap between windows within one frame in the tiling mode.
|
|
|
|
|
WindowGap(u32),
|
|
|
|
|
/// It controls the value of the `_NET_WM_NAME` property on the root window,
|
|
|
|
|
/// which specifies the name of the running window manager.
|
|
|
|
|
/// The value of this setting is not updated if the actual `_NET_WM_NAME` property
|
|
|
|
|
/// on the root window is changed externally. Example usage:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// cycle_value wmname herbstluftwm LG3D
|
|
|
|
|
/// ```
|
|
|
|
|
Wmname(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for SettingName {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
SettingName::AutoDetectMonitors
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FromStr for SettingName {
|
2024-03-06 19:49:15 +00:00
|
|
|
|
type Err = ParseError;
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
|
Self::iter()
|
|
|
|
|
.find(|i| i.to_string() == s)
|
2024-03-06 19:49:15 +00:00
|
|
|
|
.ok_or(ParseError::InvalidCommand(s.to_string()))
|
2024-02-29 20:36:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Serialize for Setting {
|
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
S: serde::Serializer,
|
|
|
|
|
{
|
|
|
|
|
serializer.serialize_str(&self.to_command_string().replace("\t", " = "))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for Setting {
|
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
|
where
|
|
|
|
|
D: serde::Deserializer<'de>,
|
|
|
|
|
{
|
2024-03-06 19:49:15 +00:00
|
|
|
|
pub enum Expect {
|
|
|
|
|
Command(String),
|
|
|
|
|
}
|
|
|
|
|
impl Expected for Expect {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
|
match self {
|
|
|
|
|
Expect::Command(err) => {
|
|
|
|
|
write!(f, "a valid [command][space/tab][value] string: {err}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-29 20:36:38 +00:00
|
|
|
|
let str_val: String = Deserialize::deserialize(deserializer)?;
|
|
|
|
|
let ((command, arg), _) = split::on_first_match(&str_val, &['='])
|
|
|
|
|
.ok_or(CommandParseError::InvalidArgumentCount(0, "setting".into()))
|
|
|
|
|
.map_err(|err| {
|
|
|
|
|
serde::de::Error::invalid_value(serde::de::Unexpected::Str(&str_val), &err)
|
|
|
|
|
})?;
|
|
|
|
|
Ok(
|
2024-03-06 19:49:15 +00:00
|
|
|
|
Self::from_command_args(&command.trim(), [arg.trim()].into_iter()).map_err(|err| {
|
|
|
|
|
serde::de::Error::invalid_value(
|
|
|
|
|
serde::de::Unexpected::Str(&str_val),
|
|
|
|
|
&Expect::Command(err.to_string()),
|
|
|
|
|
)
|
2024-02-29 20:36:38 +00:00
|
|
|
|
})?,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FromStr for Setting {
|
2024-03-06 19:49:15 +00:00
|
|
|
|
type Err = ParseError;
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
2024-03-06 19:49:15 +00:00
|
|
|
|
trace!("[from_str] beginning to parse [{s}] as setting");
|
|
|
|
|
let ((command, arg), _) =
|
|
|
|
|
split::on_first_match(s, &['\t', ' ']).ok_or(ParseError::InvalidValue {
|
|
|
|
|
value: s.to_string(),
|
|
|
|
|
expected: "[setting] [value]",
|
|
|
|
|
})?;
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
Self::from_command_args(&command.trim(), [arg].into_iter())
|
2024-02-29 20:36:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
impl FromCommandArgs for Setting {
|
|
|
|
|
fn from_command_args<S: Into<String>, I: Iterator<Item = S>>(
|
|
|
|
|
cmd: &str,
|
|
|
|
|
args: I,
|
|
|
|
|
) -> Result<Self, ParseError> {
|
|
|
|
|
let mut command = Self::iter()
|
|
|
|
|
.find(|s| s.to_string() == cmd)
|
|
|
|
|
.ok_or(ParseError::InvalidCommand(cmd.to_string()))?;
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
let mut parser = ArgParser::from_strings(args.map(|i| i.into()));
|
2024-02-29 20:36:38 +00:00
|
|
|
|
|
2024-03-06 19:49:15 +00:00
|
|
|
|
match command.borrow_mut() {
|
|
|
|
|
Setting::Verbose(arg)
|
|
|
|
|
| Setting::TabbedMax(arg)
|
|
|
|
|
| Setting::GaplessGrid(arg)
|
|
|
|
|
| Setting::RaiseOnClick(arg)
|
|
|
|
|
| Setting::RaiseOnFocus(arg)
|
|
|
|
|
| Setting::AutoDetectPanels(arg)
|
|
|
|
|
| Setting::FocusFollowsMouse(arg)
|
|
|
|
|
| Setting::HideCoveredWindows(arg)
|
|
|
|
|
| Setting::AutoDetectMonitors(arg)
|
|
|
|
|
| Setting::FrameBgTransparent(arg)
|
|
|
|
|
| Setting::SwapMonitorsToGetTag(arg)
|
|
|
|
|
| Setting::UpdateDraggedClients(arg)
|
|
|
|
|
| Setting::FocusStealingPrevention(arg)
|
|
|
|
|
| Setting::RaiseOnFocusTemporarily(arg)
|
|
|
|
|
| Setting::SmartWindowSurroundings(arg)
|
|
|
|
|
| Setting::DefaultDirectionExternalOnly(arg)
|
|
|
|
|
| Setting::FocusCrossesMonitorBoundaries(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::FrameBgActiveColor(arg)
|
|
|
|
|
| Setting::FrameBgNormalColor(arg)
|
|
|
|
|
| Setting::FrameBorderInnerColor(arg)
|
|
|
|
|
| Setting::FrameBorderActiveColor(arg)
|
|
|
|
|
| Setting::FrameBorderNormalColor(arg)
|
|
|
|
|
| Setting::WindowBorderInnerColor(arg)
|
|
|
|
|
| Setting::WindowBorderActiveColor(arg)
|
|
|
|
|
| Setting::WindowBorderNormalColor(arg)
|
|
|
|
|
| Setting::WindowBorderUrgentColor(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::DefaultFrameLayout(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::ShowFrameDecorations(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::SmartFrameSurroundings(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::MonitorsLocked(arg)
|
|
|
|
|
| Setting::FrameActiveOpacity(arg)
|
|
|
|
|
| Setting::FrameNormalOpacity(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::SnapGap(arg)
|
|
|
|
|
| Setting::FrameGap(arg)
|
|
|
|
|
| Setting::WindowGap(arg)
|
|
|
|
|
| Setting::SnapDistance(arg)
|
|
|
|
|
| Setting::FramePadding(arg)
|
|
|
|
|
| Setting::MouseRecenterGap(arg)
|
|
|
|
|
| Setting::FrameBorderWidth(arg)
|
|
|
|
|
| Setting::WindowBorderWidth(arg)
|
|
|
|
|
| Setting::FrameTransparentWidth(arg)
|
|
|
|
|
| Setting::FrameBorderInnerWidth(arg)
|
|
|
|
|
| Setting::WindowBorderInnerWidth(arg)
|
|
|
|
|
| Setting::PseudotileCenterThreshold(arg) => *arg = parser.next_from_str(cmd)?,
|
|
|
|
|
Setting::Wmname(arg) | Setting::Ellipsis(arg) | Setting::TreeStyle(arg) => {
|
|
|
|
|
*arg = parser.must_string(cmd)?
|
2024-02-29 20:36:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-06 19:49:15 +00:00
|
|
|
|
Ok(command)
|
2024-02-29 20:36:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Setting {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::AutoDetectMonitors(ToggleBool::Bool(true))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ToCommandString for Setting {
|
|
|
|
|
fn to_command_string(&self) -> String {
|
|
|
|
|
match self {
|
|
|
|
|
Setting::AutoDetectMonitors(value)
|
|
|
|
|
| Setting::AutoDetectPanels(value)
|
|
|
|
|
| Setting::DefaultDirectionExternalOnly(value)
|
|
|
|
|
| Setting::FocusCrossesMonitorBoundaries(value)
|
|
|
|
|
| Setting::FocusFollowsMouse(value)
|
|
|
|
|
| Setting::FocusStealingPrevention(value)
|
|
|
|
|
| Setting::FrameBgTransparent(value)
|
|
|
|
|
| Setting::GaplessGrid(value)
|
|
|
|
|
| Setting::HideCoveredWindows(value)
|
|
|
|
|
| Setting::RaiseOnClick(value)
|
|
|
|
|
| Setting::RaiseOnFocus(value)
|
|
|
|
|
| Setting::RaiseOnFocusTemporarily(value)
|
|
|
|
|
| Setting::SmartWindowSurroundings(value)
|
|
|
|
|
| Setting::TabbedMax(value)
|
|
|
|
|
| Setting::UpdateDraggedClients(value)
|
|
|
|
|
| Setting::Verbose(value)
|
|
|
|
|
| Setting::SwapMonitorsToGetTag(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
|
|
|
|
|
Setting::TreeStyle(value) | Setting::Wmname(value) | Setting::Ellipsis(value) => {
|
|
|
|
|
vec![self.to_string(), value.to_string()]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Setting::FrameActiveOpacity(value)
|
|
|
|
|
| Setting::FrameNormalOpacity(value)
|
|
|
|
|
| Setting::MonitorsLocked(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
|
|
|
|
|
Setting::FrameBorderInnerWidth(value)
|
|
|
|
|
| Setting::FrameBorderWidth(value)
|
|
|
|
|
| Setting::FrameGap(value)
|
|
|
|
|
| Setting::FramePadding(value)
|
|
|
|
|
| Setting::FrameTransparentWidth(value)
|
|
|
|
|
| Setting::MouseRecenterGap(value)
|
|
|
|
|
| Setting::PseudotileCenterThreshold(value)
|
|
|
|
|
| Setting::SnapDistance(value)
|
|
|
|
|
| Setting::SnapGap(value)
|
|
|
|
|
| Setting::WindowBorderInnerWidth(value)
|
|
|
|
|
| Setting::WindowBorderWidth(value)
|
|
|
|
|
| Setting::WindowGap(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
|
|
|
|
|
Setting::FrameBgActiveColor(value)
|
|
|
|
|
| Setting::FrameBgNormalColor(value)
|
|
|
|
|
| Setting::FrameBorderActiveColor(value)
|
|
|
|
|
| Setting::FrameBorderInnerColor(value)
|
|
|
|
|
| Setting::FrameBorderNormalColor(value)
|
|
|
|
|
| Setting::WindowBorderActiveColor(value)
|
|
|
|
|
| Setting::WindowBorderInnerColor(value)
|
|
|
|
|
| Setting::WindowBorderNormalColor(value)
|
|
|
|
|
| Setting::WindowBorderUrgentColor(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
|
|
|
|
|
Setting::DefaultFrameLayout(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
Setting::ShowFrameDecorations(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
Setting::SmartFrameSurroundings(value) => vec![self.to_string(), value.to_string()],
|
|
|
|
|
}
|
|
|
|
|
.join("\t")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumString, PartialEq)]
|
|
|
|
|
#[strum(serialize_all = "snake_case")]
|
|
|
|
|
pub enum ShowFrameDecoration {
|
|
|
|
|
/// Show no frame decorations at all
|
|
|
|
|
None,
|
|
|
|
|
/// Show decorations of frames that have client windows,
|
|
|
|
|
Nonempty,
|
|
|
|
|
/// Show decorations on the tags with at least two frames,
|
|
|
|
|
IfMultiple,
|
|
|
|
|
/// Show decorations of frames that have no client windows,
|
|
|
|
|
IfEmpty,
|
|
|
|
|
/// Show the decoration of focused and nonempty frames,
|
|
|
|
|
Focused,
|
|
|
|
|
/// Show decorations of focused and non-empty frames on tags with at least two frames.
|
|
|
|
|
FocusedIfMultiple,
|
|
|
|
|
/// Show all frame decorations.
|
|
|
|
|
All,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for ShowFrameDecoration {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::FocusedIfMultiple
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumString, PartialEq)]
|
|
|
|
|
#[strum(serialize_all = "snake_case")]
|
|
|
|
|
pub enum SmartFrameSurroundings {
|
|
|
|
|
/// Frame borders and gaps will be removed when there is no ambiguity regarding the focused frame
|
|
|
|
|
HideAll,
|
|
|
|
|
/// Only frame gaps will be removed when there is no ambiguity regarding the focused frame
|
|
|
|
|
HideGaps,
|
|
|
|
|
/// Always show frame borders and gaps
|
|
|
|
|
Off,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for SmartFrameSurroundings {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::Off
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumString, PartialEq)]
|
|
|
|
|
#[strum(serialize_all = "snake_case")]
|
|
|
|
|
pub enum FrameLayout {
|
|
|
|
|
/// clients are placed below each other
|
|
|
|
|
Vertical,
|
|
|
|
|
/// clients are placed next to each other
|
|
|
|
|
Horizontal,
|
|
|
|
|
/// all clients are maximized in this frame
|
|
|
|
|
Max,
|
|
|
|
|
/// clients are arranged in an almost quadratic grid
|
|
|
|
|
Grid,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for FrameLayout {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::Vertical
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test {
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
|
|
use crate::hlwm::{setting::SettingName, ToggleBool};
|
|
|
|
|
|
|
|
|
|
use super::Setting;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
|
pub struct SettingWrapper {
|
|
|
|
|
setting: Setting,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn setting_serialize_deserialize() {
|
|
|
|
|
let setting = SettingWrapper {
|
|
|
|
|
setting: Setting::AutoDetectMonitors(ToggleBool::Toggle),
|
|
|
|
|
};
|
|
|
|
|
let serialized = toml::to_string_pretty(&setting).expect("serializing");
|
|
|
|
|
let deserialized: SettingWrapper = toml::from_str(&serialized).expect("deserializing");
|
|
|
|
|
assert_eq!(setting.setting, deserialized.setting);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn setting_name() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
"auto_detect_monitors",
|
|
|
|
|
SettingName::AutoDetectMonitors.to_string()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|