config: add initial-tile-state window rule
This commit is contained in:
parent
b1ca98b488
commit
5e3465d861
16 changed files with 258 additions and 26 deletions
|
|
@ -32,7 +32,7 @@ use {
|
||||||
Transform, VrrMode,
|
Transform, VrrMode,
|
||||||
connector_type::{CON_UNKNOWN, ConnectorType},
|
connector_type::{CON_UNKNOWN, ConnectorType},
|
||||||
},
|
},
|
||||||
window::{MatchedWindow, Window, WindowCriterion, WindowMatcher, WindowType},
|
window::{MatchedWindow, TileState, Window, WindowCriterion, WindowMatcher, WindowType},
|
||||||
xwayland::XScalingMode,
|
xwayland::XScalingMode,
|
||||||
},
|
},
|
||||||
bincode::Options,
|
bincode::Options,
|
||||||
|
|
@ -1708,6 +1708,17 @@ impl ConfigClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_window_matcher_initial_tile_state(
|
||||||
|
&self,
|
||||||
|
matcher: WindowMatcher,
|
||||||
|
tile_state: TileState,
|
||||||
|
) {
|
||||||
|
self.send(&ClientMessage::SetWindowMatcherInitialTileState {
|
||||||
|
matcher,
|
||||||
|
tile_state,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_window_matcher_latch_handler(
|
pub fn set_window_matcher_latch_handler(
|
||||||
&self,
|
&self,
|
||||||
matcher: WindowMatcher,
|
matcher: WindowMatcher,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use {
|
||||||
ColorSpace, Connector, DrmDevice, Format, GfxApi, TearingMode, TransferFunction,
|
ColorSpace, Connector, DrmDevice, Format, GfxApi, TearingMode, TransferFunction,
|
||||||
Transform, VrrMode, connector_type::ConnectorType,
|
Transform, VrrMode, connector_type::ConnectorType,
|
||||||
},
|
},
|
||||||
window::{Window, WindowMatcher, WindowType},
|
window::{TileState, Window, WindowMatcher, WindowType},
|
||||||
xwayland::XScalingMode,
|
xwayland::XScalingMode,
|
||||||
},
|
},
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
|
|
@ -702,6 +702,10 @@ pub enum ClientMessage<'a> {
|
||||||
matcher: WindowMatcher,
|
matcher: WindowMatcher,
|
||||||
auto_focus: bool,
|
auto_focus: bool,
|
||||||
},
|
},
|
||||||
|
SetWindowMatcherInitialTileState {
|
||||||
|
matcher: WindowMatcher,
|
||||||
|
tile_state: TileState,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,16 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The tile state of a window.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub enum TileState {
|
||||||
|
/// The window is tiled.
|
||||||
|
Tiled,
|
||||||
|
/// The window is floating.
|
||||||
|
Floating,
|
||||||
|
}
|
||||||
|
|
||||||
/// A window created by a client.
|
/// A window created by a client.
|
||||||
///
|
///
|
||||||
/// This is the same as `XDG_TOPLEVEL | X_WINDOW`.
|
/// This is the same as `XDG_TOPLEVEL | X_WINDOW`.
|
||||||
|
|
@ -306,6 +316,17 @@ impl WindowCriterion<'_> {
|
||||||
pub fn set_auto_focus(self, auto_focus: bool) {
|
pub fn set_auto_focus(self, auto_focus: bool) {
|
||||||
self.to_matcher().set_auto_focus(auto_focus);
|
self.to_matcher().set_auto_focus(auto_focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether newly mapped windows that match this matcher are mapped tiling or
|
||||||
|
/// floating.
|
||||||
|
///
|
||||||
|
/// If multiple such window matchers match a window, the used tile state is
|
||||||
|
/// unspecified.
|
||||||
|
///
|
||||||
|
/// This leaks the matcher.
|
||||||
|
pub fn set_initial_tile_state(self, tile_state: TileState) {
|
||||||
|
self.to_matcher().set_initial_tile_state(tile_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowMatcher {
|
impl WindowMatcher {
|
||||||
|
|
@ -330,6 +351,15 @@ impl WindowMatcher {
|
||||||
pub fn set_auto_focus(self, auto_focus: bool) {
|
pub fn set_auto_focus(self, auto_focus: bool) {
|
||||||
get!().set_window_matcher_auto_focus(self, auto_focus);
|
get!().set_window_matcher_auto_focus(self, auto_focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether newly mapped windows that match this matcher are mapped tiling or
|
||||||
|
/// floating.
|
||||||
|
///
|
||||||
|
/// If multiple such window matchers match a window, the used tile state is
|
||||||
|
/// unspecified.
|
||||||
|
pub fn set_initial_tile_state(self, tile_state: TileState) {
|
||||||
|
get!().set_window_matcher_initial_tile_state(self, tile_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchedWindow {
|
impl MatchedWindow {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use {
|
||||||
input::{InputDevice, Seat, SwitchEvent},
|
input::{InputDevice, Seat, SwitchEvent},
|
||||||
keyboard::{mods::Modifiers, syms::KeySym},
|
keyboard::{mods::Modifiers, syms::KeySym},
|
||||||
video::{Connector, DrmDevice},
|
video::{Connector, DrmDevice},
|
||||||
window,
|
window::{self, TileState},
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
std::{cell::Cell, io, mem, ptr, rc::Rc},
|
std::{cell::Cell, io, mem, ptr, rc::Rc},
|
||||||
|
|
@ -169,6 +169,10 @@ impl ConfigProxy {
|
||||||
};
|
};
|
||||||
handler.auto_focus(data)
|
handler.auto_focus(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initial_tile_state(&self, data: &ToplevelData) -> Option<TileState> {
|
||||||
|
self.handler.get()?.initial_tile_state(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ConfigProxy {
|
impl Drop for ConfigProxy {
|
||||||
|
|
@ -233,6 +237,7 @@ impl ConfigProxy {
|
||||||
window_matcher_leafs: Default::default(),
|
window_matcher_leafs: Default::default(),
|
||||||
window_matcher_std_kinds: state.tl_matcher_manager.kind(window::CLIENT_WINDOW),
|
window_matcher_std_kinds: state.tl_matcher_manager.kind(window::CLIENT_WINDOW),
|
||||||
window_matcher_no_auto_focus: Default::default(),
|
window_matcher_no_auto_focus: Default::default(),
|
||||||
|
window_matcher_initial_tile_state: Default::default(),
|
||||||
});
|
});
|
||||||
let init_msg = bincode_ops()
|
let init_msg = bincode_ops()
|
||||||
.serialize(&InitMessage::V1(V1InitMessage {}))
|
.serialize(&InitMessage::V1(V1InitMessage {}))
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ use {
|
||||||
TearingMode as ConfigTearingMode, TransferFunction as ConfigTransferFunction,
|
TearingMode as ConfigTearingMode, TransferFunction as ConfigTransferFunction,
|
||||||
Transform, VrrMode as ConfigVrrMode,
|
Transform, VrrMode as ConfigVrrMode,
|
||||||
},
|
},
|
||||||
window::{Window, WindowMatcher},
|
window::{TileState, Window, WindowMatcher},
|
||||||
xwayland::XScalingMode,
|
xwayland::XScalingMode,
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
|
|
@ -126,6 +126,13 @@ pub(super) struct ConfigProxyHandler {
|
||||||
pub window_matcher_std_kinds: Rc<TlmUpstreamNode>,
|
pub window_matcher_std_kinds: Rc<TlmUpstreamNode>,
|
||||||
pub window_matcher_no_auto_focus:
|
pub window_matcher_no_auto_focus:
|
||||||
CopyHashMap<WindowMatcher, Rc<CachedCriterion<WindowCriterionIpc, ToplevelData>>>,
|
CopyHashMap<WindowMatcher, Rc<CachedCriterion<WindowCriterionIpc, ToplevelData>>>,
|
||||||
|
pub window_matcher_initial_tile_state: CopyHashMap<
|
||||||
|
WindowMatcher,
|
||||||
|
(
|
||||||
|
Rc<CachedCriterion<WindowCriterionIpc, ToplevelData>>,
|
||||||
|
TileState,
|
||||||
|
),
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pollable {
|
pub struct Pollable {
|
||||||
|
|
@ -2030,6 +2037,7 @@ impl ConfigProxyHandler {
|
||||||
self.window_matchers.remove(&matcher);
|
self.window_matchers.remove(&matcher);
|
||||||
self.window_matcher_leafs.remove(&matcher);
|
self.window_matcher_leafs.remove(&matcher);
|
||||||
self.window_matcher_no_auto_focus.remove(&matcher);
|
self.window_matcher_no_auto_focus.remove(&matcher);
|
||||||
|
self.window_matcher_initial_tile_state.remove(&matcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_enable_window_matcher_events(
|
fn handle_enable_window_matcher_events(
|
||||||
|
|
@ -2073,6 +2081,17 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_set_window_matcher_initial_tile_state(
|
||||||
|
&self,
|
||||||
|
matcher: WindowMatcher,
|
||||||
|
tile_state: TileState,
|
||||||
|
) -> Result<(), CphError> {
|
||||||
|
let m = self.get_window_matcher(matcher)?;
|
||||||
|
self.window_matcher_initial_tile_state
|
||||||
|
.set(matcher, (m, tile_state));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn spaces_change(&self) {
|
fn spaces_change(&self) {
|
||||||
struct V;
|
struct V;
|
||||||
impl NodeVisitorBase for V {
|
impl NodeVisitorBase for V {
|
||||||
|
|
@ -2884,6 +2903,12 @@ impl ConfigProxyHandler {
|
||||||
} => self
|
} => self
|
||||||
.handle_set_window_matcher_auto_focus(matcher, auto_focus)
|
.handle_set_window_matcher_auto_focus(matcher, auto_focus)
|
||||||
.wrn("set_window_matcher_auto_focus")?,
|
.wrn("set_window_matcher_auto_focus")?,
|
||||||
|
ClientMessage::SetWindowMatcherInitialTileState {
|
||||||
|
matcher,
|
||||||
|
tile_state,
|
||||||
|
} => self
|
||||||
|
.handle_set_window_matcher_initial_tile_state(matcher, tile_state)
|
||||||
|
.wrn("set_window_matcher_initial_tile_state")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -2896,6 +2921,15 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initial_tile_state(&self, data: &ToplevelData) -> Option<TileState> {
|
||||||
|
for (matcher, state) in self.window_matcher_initial_tile_state.lock().values() {
|
||||||
|
if matcher.node.pull(data) {
|
||||||
|
return Some(*state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ use {
|
||||||
xwayland::XWaylandEvent,
|
xwayland::XWaylandEvent,
|
||||||
},
|
},
|
||||||
bstr::BString,
|
bstr::BString,
|
||||||
|
jay_config::window::TileState,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
ops::{Deref, Not},
|
ops::{Deref, Not},
|
||||||
|
|
@ -266,6 +267,14 @@ impl Xwindow {
|
||||||
pub fn map_status_changed(self: &Rc<Self>) {
|
pub fn map_status_changed(self: &Rc<Self>) {
|
||||||
let map_change = self.map_change();
|
let map_change = self.map_change();
|
||||||
let override_redirect = self.data.info.override_redirect.get();
|
let override_redirect = self.data.info.override_redirect.get();
|
||||||
|
let map_floating = match self
|
||||||
|
.toplevel_data
|
||||||
|
.state
|
||||||
|
.initial_tile_state(&self.toplevel_data)
|
||||||
|
{
|
||||||
|
None => self.data.info.wants_floating.get(),
|
||||||
|
Some(m) => m == TileState::Floating,
|
||||||
|
};
|
||||||
match map_change {
|
match map_change {
|
||||||
Change::None => return,
|
Change::None => return,
|
||||||
Change::Unmap => {
|
Change::Unmap => {
|
||||||
|
|
@ -282,7 +291,7 @@ impl Xwindow {
|
||||||
Some(self.data.state.root.stacked.add_last(self.clone()));
|
Some(self.data.state.root.stacked.add_last(self.clone()));
|
||||||
self.data.state.tree_changed();
|
self.data.state.tree_changed();
|
||||||
}
|
}
|
||||||
Change::Map if self.data.info.wants_floating.get() => {
|
Change::Map if map_floating => {
|
||||||
let ws = self.data.state.float_map_ws();
|
let ws = self.data.state.float_map_ws();
|
||||||
let ext = self.data.info.pending_extents.get();
|
let ext = self.data.info.pending_extents.get();
|
||||||
self.data
|
self.data
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ use {
|
||||||
wire::{XdgToplevelId, xdg_toplevel::*},
|
wire::{XdgToplevelId, xdg_toplevel::*},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
|
jay_config::window::TileState,
|
||||||
num_derive::FromPrimitive,
|
num_derive::FromPrimitive,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
@ -381,6 +382,31 @@ impl XdgToplevelRequestHandler for XdgToplevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgToplevel {
|
impl XdgToplevel {
|
||||||
|
fn map(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
parent: Option<&XdgToplevel>,
|
||||||
|
pos: Option<(&Rc<OutputNode>, i32, i32)>,
|
||||||
|
) {
|
||||||
|
if let Some(state) = self.state.initial_tile_state(&self.toplevel_data) {
|
||||||
|
match state {
|
||||||
|
TileState::Floating => {
|
||||||
|
let mut ws = None;
|
||||||
|
if let Some(parent) = parent {
|
||||||
|
ws = parent.xdg.workspace.get();
|
||||||
|
}
|
||||||
|
let ws = ws.unwrap_or_else(|| self.state.ensure_map_workspace(None));
|
||||||
|
self.map_floating(&ws, pos.map(|p| (p.1, p.2)));
|
||||||
|
}
|
||||||
|
_ => self.map_tiled(),
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match parent {
|
||||||
|
None => self.map_tiled(),
|
||||||
|
Some(p) => self.map_child(p, pos),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn map_floating(self: &Rc<Self>, workspace: &Rc<WorkspaceNode>, abs_pos: Option<(i32, i32)>) {
|
fn map_floating(self: &Rc<Self>, workspace: &Rc<WorkspaceNode>, abs_pos: Option<(i32, i32)>) {
|
||||||
let (width, height) = self.toplevel_data.float_size(workspace);
|
let (width, height) = self.toplevel_data.float_size(workspace);
|
||||||
self.state
|
self.state
|
||||||
|
|
@ -474,11 +500,7 @@ impl XdgToplevel {
|
||||||
}
|
}
|
||||||
self.state.tree_changed();
|
self.state.tree_changed();
|
||||||
} else {
|
} else {
|
||||||
if let Some(parent) = self.parent.get() {
|
self.map(self.parent.get().as_deref(), pos);
|
||||||
self.map_child(&parent, pos);
|
|
||||||
} else {
|
|
||||||
self.map_tiled();
|
|
||||||
}
|
|
||||||
self.extents_changed();
|
self.extents_changed();
|
||||||
if let Some(workspace) = self.xdg.workspace.get() {
|
if let Some(workspace) = self.xdg.workspace.get() {
|
||||||
let output = workspace.output.get();
|
let output = workspace.output.get();
|
||||||
|
|
|
||||||
26
src/state.rs
26
src/state.rs
|
|
@ -82,8 +82,8 @@ use {
|
||||||
time::Time,
|
time::Time,
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, LatchListener, Node,
|
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, LatchListener, Node,
|
||||||
NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelNode,
|
NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelData,
|
||||||
ToplevelNodeBase, VrrMode, WorkspaceNode, generic_node_visitor,
|
ToplevelNode, ToplevelNodeBase, VrrMode, WorkspaceNode, generic_node_visitor,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
||||||
|
|
@ -112,6 +112,7 @@ use {
|
||||||
jay_config::{
|
jay_config::{
|
||||||
PciId,
|
PciId,
|
||||||
video::{GfxApi, Transform},
|
video::{GfxApi, Transform},
|
||||||
|
window::TileState,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
@ -662,6 +663,16 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ensure_map_workspace(&self, seat: Option<&Rc<WlSeatGlobal>>) -> Rc<WorkspaceNode> {
|
||||||
|
seat.cloned()
|
||||||
|
.or_else(|| self.seat_queue.last().map(|s| s.deref().clone()))
|
||||||
|
.map(|s| s.get_output())
|
||||||
|
.or_else(|| self.root.outputs.lock().values().next().cloned())
|
||||||
|
.or_else(|| self.dummy_output.get())
|
||||||
|
.unwrap()
|
||||||
|
.ensure_workspace()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map_tiled(self: &Rc<Self>, node: Rc<dyn ToplevelNode>) {
|
pub fn map_tiled(self: &Rc<Self>, node: Rc<dyn ToplevelNode>) {
|
||||||
let seat = self.seat_queue.last();
|
let seat = self.seat_queue.last();
|
||||||
self.do_map_tiled(seat.as_deref(), node.clone());
|
self.do_map_tiled(seat.as_deref(), node.clone());
|
||||||
|
|
@ -669,12 +680,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_map_tiled(self: &Rc<Self>, seat: Option<&Rc<WlSeatGlobal>>, node: Rc<dyn ToplevelNode>) {
|
fn do_map_tiled(self: &Rc<Self>, seat: Option<&Rc<WlSeatGlobal>>, node: Rc<dyn ToplevelNode>) {
|
||||||
let output = seat
|
let ws = self.ensure_map_workspace(seat);
|
||||||
.map(|s| s.get_output())
|
|
||||||
.or_else(|| self.root.outputs.lock().values().next().cloned())
|
|
||||||
.or_else(|| self.dummy_output.get())
|
|
||||||
.unwrap();
|
|
||||||
let ws = output.ensure_workspace();
|
|
||||||
self.map_tiled_on(node, &ws);
|
self.map_tiled_on(node, &ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1384,6 +1390,10 @@ impl State {
|
||||||
};
|
};
|
||||||
ctx.supports_color_management()
|
ctx.supports_color_management()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initial_tile_state(&self, data: &ToplevelData) -> Option<TileState> {
|
||||||
|
self.config.get()?.initial_tile_state(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use {
|
||||||
status::MessageFormat,
|
status::MessageFormat,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
video::{ColorSpace, Format, GfxApi, TearingMode, TransferFunction, Transform, VrrMode},
|
video::{ColorSpace, Format, GfxApi, TearingMode, TransferFunction, Transform, VrrMode},
|
||||||
window::WindowType,
|
window::{TileState, WindowType},
|
||||||
xwayland::XScalingMode,
|
xwayland::XScalingMode,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -249,6 +249,7 @@ pub struct WindowRule {
|
||||||
pub action: Option<Action>,
|
pub action: Option<Action>,
|
||||||
pub latch: Option<Action>,
|
pub latch: Option<Action>,
|
||||||
pub auto_focus: Option<bool>,
|
pub auto_focus: Option<bool>,
|
||||||
|
pub initial_tile_state: Option<TileState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ pub mod shortcuts;
|
||||||
mod status;
|
mod status;
|
||||||
mod tearing;
|
mod tearing;
|
||||||
mod theme;
|
mod theme;
|
||||||
|
mod tile_state;
|
||||||
mod ui_drag;
|
mod ui_drag;
|
||||||
mod vrr;
|
mod vrr;
|
||||||
mod window_match;
|
mod window_match;
|
||||||
|
|
|
||||||
35
toml-config/src/config/parsers/tile_state.rs
Normal file
35
toml-config/src/config/parsers/tile_state.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
config::parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
|
toml::toml_span::{Span, SpannedExt},
|
||||||
|
},
|
||||||
|
jay_config::window::TileState,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TileStateParserError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Expected(#[from] UnexpectedDataType),
|
||||||
|
#[error("Unknown tile state `{}`", .0)]
|
||||||
|
UnknownTileState(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TileStateParser;
|
||||||
|
|
||||||
|
impl Parser for TileStateParser {
|
||||||
|
type Value = TileState;
|
||||||
|
type Error = TileStateParserError;
|
||||||
|
const EXPECTED: &'static [DataType] = &[DataType::String];
|
||||||
|
|
||||||
|
fn parse_string(&mut self, span: Span, string: &str) -> ParseResult<Self> {
|
||||||
|
let ty = match string {
|
||||||
|
"tiled" => TileState::Tiled,
|
||||||
|
"floating" => TileState::Floating,
|
||||||
|
_ => {
|
||||||
|
return Err(TileStateParserError::UnknownTileState(string.to_owned()).spanned(span));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ use {
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
parsers::{
|
parsers::{
|
||||||
action::{ActionParser, ActionParserError},
|
action::{ActionParser, ActionParserError},
|
||||||
|
tile_state::TileStateParser,
|
||||||
window_match::{WindowMatchParser, WindowMatchParserError},
|
window_match::{WindowMatchParser, WindowMatchParserError},
|
||||||
},
|
},
|
||||||
spanned::SpannedErrorExt,
|
spanned::SpannedErrorExt,
|
||||||
|
|
@ -47,13 +48,15 @@ impl Parser for WindowRuleParser<'_> {
|
||||||
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
||||||
) -> ParseResult<Self> {
|
) -> ParseResult<Self> {
|
||||||
let mut ext = Extractor::new(self.0, span, table);
|
let mut ext = Extractor::new(self.0, span, table);
|
||||||
let (name, match_val, action_val, latch_val, auto_focus) = ext.extract((
|
let (name, match_val, action_val, latch_val, auto_focus, initial_tile_state_val) = ext
|
||||||
opt(str("name")),
|
.extract((
|
||||||
opt(val("match")),
|
opt(str("name")),
|
||||||
opt(val("action")),
|
opt(val("match")),
|
||||||
opt(val("latch")),
|
opt(val("action")),
|
||||||
recover(opt(bol("auto-focus"))),
|
opt(val("latch")),
|
||||||
))?;
|
recover(opt(bol("auto-focus"))),
|
||||||
|
opt(val("initial-tile-state")),
|
||||||
|
))?;
|
||||||
let mut action = None;
|
let mut action = None;
|
||||||
if let Some(value) = action_val {
|
if let Some(value) = action_val {
|
||||||
action = Some(
|
action = Some(
|
||||||
|
|
@ -70,6 +73,18 @@ impl Parser for WindowRuleParser<'_> {
|
||||||
.map_spanned_err(WindowRuleParserError::Latch)?,
|
.map_spanned_err(WindowRuleParserError::Latch)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let mut initial_tile_state = None;
|
||||||
|
if let Some(value) = initial_tile_state_val {
|
||||||
|
match value.parse(&mut TileStateParser) {
|
||||||
|
Ok(v) => initial_tile_state = Some(v),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!(
|
||||||
|
"Could not parse the initial tile state: {}",
|
||||||
|
self.0.error(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let match_ = match match_val {
|
let match_ = match match_val {
|
||||||
None => WindowMatch::default(),
|
None => WindowMatch::default(),
|
||||||
Some(m) => m.parse_map(&mut WindowMatchParser(self.0))?,
|
Some(m) => m.parse_map(&mut WindowMatchParser(self.0))?,
|
||||||
|
|
@ -80,6 +95,7 @@ impl Parser for WindowRuleParser<'_> {
|
||||||
action,
|
action,
|
||||||
latch,
|
latch,
|
||||||
auto_focus: auto_focus.despan(),
|
auto_focus: auto_focus.despan(),
|
||||||
|
initial_tile_state,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -336,6 +336,9 @@ impl Rule for WindowRule {
|
||||||
if let Some(auto_focus) = self.auto_focus {
|
if let Some(auto_focus) = self.auto_focus {
|
||||||
matcher.set_auto_focus(auto_focus);
|
matcher.set_auto_focus(auto_focus);
|
||||||
}
|
}
|
||||||
|
if let Some(tile_state) = self.initial_tile_state {
|
||||||
|
matcher.set_initial_tile_state(tile_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_matcher(m: Self::Matcher) -> Self::Criterion<'static> {
|
fn gen_matcher(m: Self::Matcher) -> Self::Criterion<'static> {
|
||||||
|
|
|
||||||
|
|
@ -1664,6 +1664,14 @@
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
},
|
},
|
||||||
|
"TileState": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Whether a window is tiled or floating.",
|
||||||
|
"enum": [
|
||||||
|
"tiled",
|
||||||
|
"floating"
|
||||||
|
]
|
||||||
|
},
|
||||||
"TransferFunction": {
|
"TransferFunction": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The transfer function of an output.\n",
|
"description": "The transfer function of an output.\n",
|
||||||
|
|
@ -1908,6 +1916,10 @@
|
||||||
"auto-focus": {
|
"auto-focus": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether newly mapped windows that match this rule get the keyboard focus.\n\nIf a window matches any rule for which this is false, the window will not be\nautomatically focused.\n"
|
"description": "Whether newly mapped windows that match this rule get the keyboard focus.\n\nIf a window matches any rule for which this is false, the window will not be\nautomatically focused.\n"
|
||||||
|
},
|
||||||
|
"initial-tile-state": {
|
||||||
|
"description": "Specifies if the window is initially mapped tiled or floating.",
|
||||||
|
"$ref": "#/$defs/TileState"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|
|
||||||
|
|
@ -3710,6 +3710,25 @@ The table has the following fields:
|
||||||
The value of this field should be a string.
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
|
||||||
|
<a name="types-TileState"></a>
|
||||||
|
### `TileState`
|
||||||
|
|
||||||
|
Whether a window is tiled or floating.
|
||||||
|
|
||||||
|
Values of this type should be strings.
|
||||||
|
|
||||||
|
The string should have one of the following values:
|
||||||
|
|
||||||
|
- `tiled`:
|
||||||
|
|
||||||
|
The window is tiled.
|
||||||
|
|
||||||
|
- `floating`:
|
||||||
|
|
||||||
|
The window is floating.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="types-TransferFunction"></a>
|
<a name="types-TransferFunction"></a>
|
||||||
### `TransferFunction`
|
### `TransferFunction`
|
||||||
|
|
||||||
|
|
@ -4212,6 +4231,12 @@ The table has the following fields:
|
||||||
|
|
||||||
The value of this field should be a boolean.
|
The value of this field should be a boolean.
|
||||||
|
|
||||||
|
- `initial-tile-state` (optional):
|
||||||
|
|
||||||
|
Specifies if the window is initially mapped tiled or floating.
|
||||||
|
|
||||||
|
The value of this field should be a [TileState](#types-TileState).
|
||||||
|
|
||||||
|
|
||||||
<a name="types-WindowTypeMask"></a>
|
<a name="types-WindowTypeMask"></a>
|
||||||
### `WindowTypeMask`
|
### `WindowTypeMask`
|
||||||
|
|
|
||||||
|
|
@ -3376,6 +3376,10 @@ WindowRule:
|
||||||
|
|
||||||
If a window matches any rule for which this is false, the window will not be
|
If a window matches any rule for which this is false, the window will not be
|
||||||
automatically focused.
|
automatically focused.
|
||||||
|
initial-tile-state:
|
||||||
|
ref: TileState
|
||||||
|
required: false
|
||||||
|
description: Specifies if the window is initially mapped tiled or floating.
|
||||||
|
|
||||||
|
|
||||||
WindowMatch:
|
WindowMatch:
|
||||||
|
|
@ -3602,3 +3606,13 @@ WindowTypeMask:
|
||||||
description: An array of masks that are OR'd.
|
description: An array of masks that are OR'd.
|
||||||
items:
|
items:
|
||||||
ref: WindowTypeMask
|
ref: WindowTypeMask
|
||||||
|
|
||||||
|
|
||||||
|
TileState:
|
||||||
|
description: Whether a window is tiled or floating.
|
||||||
|
kind: string
|
||||||
|
values:
|
||||||
|
- value: tiled
|
||||||
|
description: The window is tiled.
|
||||||
|
- value: floating
|
||||||
|
description: The window is floating.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue