Implement struts
This commit is contained in:
parent
ab26c1ea81
commit
9238688774
10 changed files with 362 additions and 53 deletions
96
Cargo.lock
generated
96
Cargo.lock
generated
|
@ -263,6 +263,7 @@ dependencies = [
|
|||
"futures-util",
|
||||
"gdk",
|
||||
"gdk-pixbuf",
|
||||
"gdkx11",
|
||||
"gio",
|
||||
"glib",
|
||||
"grass",
|
||||
|
@ -273,7 +274,7 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"maplit",
|
||||
"nix",
|
||||
"nix 0.19.1",
|
||||
"num",
|
||||
"pretty_assertions",
|
||||
"pretty_env_logger",
|
||||
|
@ -287,6 +288,7 @@ dependencies = [
|
|||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"unescape",
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -461,6 +463,55 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdkx11"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b89606baa221f9b8d8aa81924fd448c6b107d20de949f0fbf9a4ec203bb54b63"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gdk",
|
||||
"gdk-pixbuf",
|
||||
"gdk-pixbuf-sys",
|
||||
"gdk-sys",
|
||||
"gdkx11-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango",
|
||||
"x11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdkx11-sys"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6710388d530f3178ccbeb65cbafdf497a5772c4409eaf574ee9fa461af0a3d09"
|
||||
dependencies = [
|
||||
"gdk-pixbuf-sys",
|
||||
"gdk-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"system-deps",
|
||||
"x11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e692e296bfac1d2533ef168d0b60ff5897b8b70a4009276834014dd8924cc028"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -804,6 +855,18 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.19.1"
|
||||
|
@ -1627,12 +1690,43 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-wsapoll"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "x11"
|
||||
version = "2.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ecd092546cb16f25783a5451538e73afc8d32e242648d54f4ae5459ba1e773"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "232bc353846d5350d7a815c249209f9545f1d5c725dca846a5ae383a70f30fa5"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"nix 0.18.0",
|
||||
"winapi",
|
||||
"winapi-wsapoll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xmlparser"
|
||||
version = "0.13.3"
|
||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -9,6 +9,12 @@ repository = "https://github.com/elkowar/eww"
|
|||
homepage = "https://github.com/elkowar/eww"
|
||||
|
||||
|
||||
[features]
|
||||
default = ["x11"]
|
||||
x11 = ["gdkx11", "x11rb"]
|
||||
no-x11 = []
|
||||
|
||||
|
||||
[dependencies]
|
||||
gtk = { version = "0.9", features = [ "v3_16" ] }
|
||||
gdk = { version = "", features = ["v3_16"] }
|
||||
|
@ -17,6 +23,9 @@ glib = { version = "", features = ["v2_44"] }
|
|||
|
||||
gdk-pixbuf = "0.9"
|
||||
|
||||
gdkx11 = { version = "0.9", optional = true }
|
||||
x11rb = { version = "0.7", features = ["randr"], optional = true }
|
||||
|
||||
regex = "1"
|
||||
bincode = "1.3"
|
||||
anyhow = "1.0"
|
||||
|
@ -47,5 +56,10 @@ futures-util = "0.3"
|
|||
inotify = "0.9"
|
||||
tokio-util = "0.6"
|
||||
|
||||
|
||||
[target.'cfg(target_os="linux")'.dependencies]
|
||||
inotify = "0.9"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.6.1"
|
||||
|
|
|
@ -22,15 +22,15 @@ contain are defined. -->
|
|||
|
||||
<def name="workspaces">
|
||||
<box orientation="h" class="workspaces" space-evenly="true" halign="start"> <!-- Your workspaces.-->
|
||||
<button onclick="wmctrl -s 0">1</button>
|
||||
<button onclick="wmctrl -s 1">2</button>
|
||||
<button onclick="wmctrl -s 0">1</button>
|
||||
<button onclick="wmctrl -s 1">2</button>
|
||||
<button onclick="wmctrl -s 2">3</button>
|
||||
<button onclick="wmctrl -s 3">4</button>
|
||||
<button onclick="wmctrl -s 4">5</button>
|
||||
<button onclick="wmctrl -s 5">6</button>
|
||||
<button onclick="wmctrl -s 6">7</button>
|
||||
<button onclick="wmctrl -s 7">8</button>
|
||||
<button onclick="wmctrl -s 8">9</button>
|
||||
<button onclick="wmctrl -s 3">4</button>
|
||||
<button onclick="wmctrl -s 4">5</button>
|
||||
<button onclick="wmctrl -s 5">6</button>
|
||||
<button onclick="wmctrl -s 6">7</button>
|
||||
<button onclick="wmctrl -s 7">8</button>
|
||||
<button onclick="wmctrl -s 8">9</button>
|
||||
</box>
|
||||
</def>
|
||||
<def name="music">
|
||||
|
@ -45,7 +45,7 @@ contain are defined. -->
|
|||
<!--A basic volume slider-->
|
||||
<box orientation="h" class="slider-vol" space-evenly="false">
|
||||
<box class="label-vol"></box>
|
||||
<scale min="0" max="101" value="{{volume}}" onchange="amixer -D pulse sset Master {}%"/>
|
||||
<scale min="0" max="101" value="{{volume}}" onchange="amixer -D pulse sset Master {}%"/>
|
||||
</box>
|
||||
</def>
|
||||
<def name="slider-ram">
|
||||
|
@ -66,11 +66,11 @@ contain are defined. -->
|
|||
<!-- Music vars -->
|
||||
<!-- These are your variables. Like they say, they run a script, and then output that to the variable. In
|
||||
the following var, we get music info from playerctl. -->
|
||||
|
||||
|
||||
<script-var name="music" interval="5s">playerctl metadata --format '{{ artist }} - {{ title }}'</script-var>
|
||||
|
||||
|
||||
<!--Volume var-->
|
||||
<!--Volume var-->
|
||||
<!-- If your vars get too complex to write down here, you can use an external script and paste it's path here as well, as shown below.
|
||||
-->
|
||||
|
||||
|
@ -93,8 +93,9 @@ contain are defined. -->
|
|||
|
||||
<windows>
|
||||
<!-- These are the windows -->
|
||||
<window name="bar">
|
||||
<window name="bar" screen="0">
|
||||
<geometry x="0%" y="0%" width="100%" height="4%"/> <!--Specifies geometry-->
|
||||
<reserve side="top" distance="4%"/>
|
||||
<widget>
|
||||
<bar/> <!--This is the def we created earlier-->
|
||||
</widget>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
config,
|
||||
config::{window_definition::WindowName, AnchorPoint, WindowStacking},
|
||||
eww_state,
|
||||
display_backend, eww_state,
|
||||
script_var_handler::*,
|
||||
value::{AttrValue, Coords, NumWithUnit, PrimitiveValue, VarName},
|
||||
widgets,
|
||||
|
@ -379,6 +379,8 @@ fn initialize_window(
|
|||
window.set_keep_below(true);
|
||||
}
|
||||
|
||||
display_backend::reserve_space_for(&window, monitor_geometry, window_def.struts)?;
|
||||
|
||||
Ok(EwwWindow {
|
||||
name: window_def.name.clone(),
|
||||
definition: window_def,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ensure_xml_tag_is;
|
||||
use crate::{ensure_xml_tag_is, value::NumWithUnit};
|
||||
use anyhow::*;
|
||||
use derive_more::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -6,6 +6,21 @@ use smart_default::SmartDefault;
|
|||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault)]
|
||||
pub enum Side {
|
||||
#[default]
|
||||
Top,
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct StrutDefinition {
|
||||
pub side: Side,
|
||||
pub dist: NumWithUnit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct EwwWindowDefinition {
|
||||
pub name: WindowName,
|
||||
|
@ -13,7 +28,7 @@ pub struct EwwWindowDefinition {
|
|||
pub stacking: WindowStacking,
|
||||
pub screen_number: Option<i32>,
|
||||
pub widget: WidgetUse,
|
||||
pub struts: Struts,
|
||||
pub struts: StrutDefinition,
|
||||
pub focusable: bool,
|
||||
}
|
||||
|
||||
|
@ -21,10 +36,17 @@ impl EwwWindowDefinition {
|
|||
pub fn from_xml_element(xml: &XmlElement) -> Result<Self> {
|
||||
ensure_xml_tag_is!(xml, "window");
|
||||
let stacking: WindowStacking = xml.parse_optional_attr("stacking")?.unwrap_or_default();
|
||||
let screen_number = xml.parse_optional_attr("screen")?;
|
||||
let focusable = xml.parse_optional_attr("focusable")?;
|
||||
|
||||
let struts = xml.child("struts").ok().map(Struts::from_xml_element).transpose()?;
|
||||
// TODO maybe rename this to monitor?
|
||||
let focusable = xml.parse_optional_attr("focusable")?;
|
||||
let screen_number = xml.parse_optional_attr("screen")?;
|
||||
|
||||
let struts: Option<StrutDefinition> = xml
|
||||
.child("reserve")
|
||||
.ok()
|
||||
.map(parse_strut_definition)
|
||||
.transpose()
|
||||
.context("Failed to parse <reserve>")?;
|
||||
|
||||
Ok(EwwWindowDefinition {
|
||||
name: WindowName(xml.attr("name")?.to_owned()),
|
||||
|
@ -46,23 +68,23 @@ impl EwwWindowDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Struts {
|
||||
left: i32,
|
||||
right: i32,
|
||||
top: i32,
|
||||
bottom: i32,
|
||||
fn parse_strut_definition(xml: XmlElement) -> Result<StrutDefinition> {
|
||||
Ok(StrutDefinition {
|
||||
side: parse_side(xml.attr("side")?)?,
|
||||
dist: xml.attr("distance")?.parse()?,
|
||||
})
|
||||
}
|
||||
|
||||
impl Struts {
|
||||
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
|
||||
ensure_xml_tag_is!(xml, "struts");
|
||||
Ok(Struts {
|
||||
left: xml.attr("left")?.parse()?,
|
||||
right: xml.attr("right")?.parse()?,
|
||||
top: xml.attr("top")?.parse()?,
|
||||
bottom: xml.attr("bottom")?.parse()?,
|
||||
})
|
||||
fn parse_side(s: &str) -> Result<Side> {
|
||||
match s {
|
||||
"l" | "left" => Ok(Side::Left),
|
||||
"r" | "right" => Ok(Side::Right),
|
||||
"t" | "top" => Ok(Side::Top),
|
||||
"b" | "bottom" => Ok(Side::Bottom),
|
||||
_ => Err(anyhow!(
|
||||
"Failed to parse {} as valid side. Must be one of \"left\", \"right\", \"top\", \"bottom\"",
|
||||
s
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
131
src/display_backend.rs
Normal file
131
src/display_backend.rs
Normal file
|
@ -0,0 +1,131 @@
|
|||
pub use platform::*;
|
||||
|
||||
#[cfg(feature = "no-x11")]
|
||||
mod platform {
|
||||
pub fn reserve_space_for(window: >k::Window, monitor: gdk::Rectangle, strut_def: StrutDefinition) -> Result<()> {
|
||||
Err(anyhow!("Cannot reserve space on non-X11 backends"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "x11")]
|
||||
mod platform {
|
||||
use crate::config::{Side, StrutDefinition};
|
||||
use anyhow::*;
|
||||
use gdkx11;
|
||||
use gtk::{self, prelude::*};
|
||||
use x11rb::protocol::xproto::ConnectionExt;
|
||||
|
||||
use x11rb::{
|
||||
self,
|
||||
connection::Connection,
|
||||
protocol::xproto::*,
|
||||
rust_connection::{DefaultStream, RustConnection},
|
||||
};
|
||||
|
||||
pub fn reserve_space_for(window: >k::Window, monitor: gdk::Rectangle, strut_def: StrutDefinition) -> Result<()> {
|
||||
let backend = X11Backend::new()?;
|
||||
backend.reserve_space_for(window, monitor, strut_def)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct X11Backend {
|
||||
conn: RustConnection<DefaultStream>,
|
||||
root_window: u32,
|
||||
atoms: AtomCollection,
|
||||
}
|
||||
|
||||
impl X11Backend {
|
||||
fn new() -> Result<Self> {
|
||||
let (conn, screen_num) = RustConnection::connect(None)?;
|
||||
let screen = conn.setup().roots[screen_num].clone();
|
||||
let atoms = AtomCollection::new(&conn)?.reply()?;
|
||||
Ok(X11Backend {
|
||||
conn,
|
||||
root_window: screen.root,
|
||||
atoms,
|
||||
})
|
||||
}
|
||||
|
||||
fn reserve_space_for(
|
||||
&self,
|
||||
window: >k::Window,
|
||||
monitor_rect: gdk::Rectangle,
|
||||
strut_def: StrutDefinition,
|
||||
) -> Result<()> {
|
||||
let win_id = window
|
||||
.get_window()
|
||||
.context("Couldn't get gdk window from gtk window")?
|
||||
.downcast::<gdkx11::X11Window>()
|
||||
.ok()
|
||||
.context("Failed to get x11 window for gtk window")?
|
||||
.get_xid() as u32;
|
||||
let root_window_geometry = self.conn.get_geometry(self.root_window)?.reply()?;
|
||||
|
||||
let mon_end_x = (monitor_rect.x + monitor_rect.width) as u32 - 1u32;
|
||||
let mon_end_y = (monitor_rect.y + monitor_rect.height) as u32 - 1u32;
|
||||
|
||||
let dist = match strut_def.side {
|
||||
Side::Left | Side::Right => strut_def.dist.relative_to(monitor_rect.width) as u32,
|
||||
Side::Top | Side::Bottom => strut_def.dist.relative_to(monitor_rect.height) as u32,
|
||||
};
|
||||
|
||||
// don't question it,.....
|
||||
// it's how the X gods want it to be.
|
||||
// left, right, top, bottom, left_start_y, left_end_y, right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, bottom_end_x
|
||||
#[rustfmt::skip]
|
||||
let strut_list: Vec<u8> = match strut_def.side {
|
||||
Side::Left => vec![dist + monitor_rect.x as u32, 0, 0, 0, monitor_rect.y as u32, mon_end_y, 0, 0, 0, 0, 0, 0],
|
||||
Side::Right => vec![0, root_window_geometry.width as u32 - mon_end_x + dist, 0, 0, 0, 0, monitor_rect.y as u32, mon_end_y, 0, 0, 0, 0],
|
||||
Side::Top => vec![0, 0, dist + monitor_rect.y as u32, 0, 0, 0, 0, 0, monitor_rect.x as u32, mon_end_x, 0, 0],
|
||||
Side::Bottom => vec![0, 0, 0, root_window_geometry.height as u32 - mon_end_y + dist, 0, 0, 0, 0, 0, 0, monitor_rect.x as u32, mon_end_x]
|
||||
}.iter().flat_map(|x| x.to_le_bytes().to_vec()).collect();
|
||||
|
||||
self.conn
|
||||
.change_property(
|
||||
PropMode::Replace,
|
||||
win_id,
|
||||
self.atoms._NET_WM_STRUT,
|
||||
self.atoms.CARDINAL,
|
||||
32,
|
||||
4,
|
||||
&strut_list[0..16],
|
||||
)?
|
||||
.check()?;
|
||||
self.conn
|
||||
.change_property(
|
||||
PropMode::Replace,
|
||||
win_id,
|
||||
self.atoms._NET_WM_STRUT_PARTIAL,
|
||||
self.atoms.CARDINAL,
|
||||
32,
|
||||
12,
|
||||
&strut_list,
|
||||
)?
|
||||
.check()?;
|
||||
self.conn.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
x11rb::atom_manager! {
|
||||
pub AtomCollection: AtomCollectionCookie {
|
||||
_NET_WM_WINDOW_TYPE,
|
||||
_NET_WM_WINDOW_TYPE_DOCK,
|
||||
_NET_WM_WINDOW_TYPE_DIALOG,
|
||||
_NET_WM_STATE,
|
||||
_NET_WM_STATE_STICKY,
|
||||
_NET_WM_STATE_ABOVE,
|
||||
_NET_WM_STATE_BELOW,
|
||||
_NET_WM_NAME,
|
||||
_NET_WM_STRUT,
|
||||
_NET_WM_STRUT_PARTIAL,
|
||||
WM_NAME,
|
||||
UTF8_STRING,
|
||||
COMPOUND_TEXT,
|
||||
CARDINAL,
|
||||
ATOM,
|
||||
WM_CLASS,
|
||||
STRING,
|
||||
}
|
||||
}
|
||||
}
|
36
src/geometry.rs
Normal file
36
src/geometry.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use derive_more::*;
|
||||
pub trait Rectangular {
|
||||
fn get_rect(&self) -> Rect;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Display)]
|
||||
#[display(fmt = ".x*.y:.width*.height")]
|
||||
pub struct Rect {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn of(x: i32, y: i32, width: i32, height: i32) -> Self {
|
||||
Rect { x, y, width, height }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rectangular for Rect {
|
||||
fn get_rect(&self) -> Rect {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Rectangular for gdk::Rectangle {
|
||||
fn get_rect(&self) -> Rect {
|
||||
Rect {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,8 @@ pub mod server;
|
|||
pub mod util;
|
||||
pub mod value;
|
||||
pub mod widgets;
|
||||
pub mod geometry;
|
||||
pub mod display_backend;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref IPC_SOCKET_PATH: std::path::PathBuf = std::env::var("XDG_RUNTIME_DIR")
|
||||
|
|
14
src/opts.rs
14
src/opts.rs
|
@ -28,7 +28,7 @@ struct RawOpt {
|
|||
#[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Action {
|
||||
/// Start the Eww daemon.
|
||||
#[structopt(name = "daemon")]
|
||||
#[structopt(name = "daemon", alias = "d")]
|
||||
Daemon {
|
||||
/// Custom Config Path
|
||||
#[structopt(short, long)]
|
||||
|
@ -56,7 +56,7 @@ pub enum ActionWithServer {
|
|||
Ping,
|
||||
|
||||
/// Update the value of a variable, in a running eww instance
|
||||
#[structopt(name = "update")]
|
||||
#[structopt(name = "update", alias = "u")]
|
||||
Update {
|
||||
/// variable_name="new_value"-pairs that will be updated
|
||||
#[structopt(parse(try_from_str = parse_var_update_arg))]
|
||||
|
@ -64,7 +64,7 @@ pub enum ActionWithServer {
|
|||
},
|
||||
|
||||
/// open a window
|
||||
#[structopt(name = "open")]
|
||||
#[structopt(name = "open", alias = "o")]
|
||||
OpenWindow {
|
||||
/// Name of the window you want to open.
|
||||
window_name: WindowName,
|
||||
|
@ -88,19 +88,19 @@ pub enum ActionWithServer {
|
|||
OpenMany { windows: Vec<WindowName> },
|
||||
|
||||
/// Close the window with the given name
|
||||
#[structopt(name = "close")]
|
||||
#[structopt(name = "close", alias = "c")]
|
||||
CloseWindow { window_name: WindowName },
|
||||
|
||||
/// Reload the configuration
|
||||
#[structopt(name = "reload")]
|
||||
#[structopt(name = "reload", alias = "r")]
|
||||
Reload,
|
||||
|
||||
/// kill the eww daemon
|
||||
#[structopt(name = "kill")]
|
||||
#[structopt(name = "kill", alias = "k")]
|
||||
KillServer,
|
||||
|
||||
/// Close all windows, without killing the daemon
|
||||
#[structopt(name = "close-all")]
|
||||
#[structopt(name = "close-all", alias = "ca")]
|
||||
CloseAll,
|
||||
|
||||
/// Print the current eww-state
|
||||
|
|
|
@ -15,6 +15,15 @@ pub enum NumWithUnit {
|
|||
Pixels(i32),
|
||||
}
|
||||
|
||||
impl NumWithUnit {
|
||||
pub fn relative_to(&self, max: i32) -> i32 {
|
||||
match *self {
|
||||
NumWithUnit::Percent(n) => ((max as f64 / 100.0) * n as f64) as i32,
|
||||
NumWithUnit::Pixels(n) => n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for NumWithUnit {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
|
@ -35,7 +44,7 @@ impl FromStr for NumWithUnit {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Display, Default)]
|
||||
#[display(fmt = "{}X{}", x, y)]
|
||||
#[display(fmt = "{}*{}", x, y)]
|
||||
pub struct Coords {
|
||||
pub x: NumWithUnit,
|
||||
pub y: NumWithUnit,
|
||||
|
@ -46,7 +55,7 @@ impl FromStr for Coords {
|
|||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (x, y) = s
|
||||
.split_once(|x: char| x.to_ascii_lowercase() == 'x')
|
||||
.split_once(|x: char| x.to_ascii_lowercase() == 'x' || x.to_ascii_lowercase() == '*')
|
||||
.ok_or_else(|| anyhow!("must be formatted like 200x500"))?;
|
||||
Coords::from_strs(x, y)
|
||||
}
|
||||
|
@ -59,6 +68,13 @@ impl fmt::Debug for Coords {
|
|||
}
|
||||
|
||||
impl Coords {
|
||||
pub fn from_pixels(x: i32, y: i32) -> Self {
|
||||
Coords {
|
||||
x: NumWithUnit::Pixels(x),
|
||||
y: NumWithUnit::Pixels(y),
|
||||
}
|
||||
}
|
||||
|
||||
/// parse a string for x and a string for y into a [`Coords`] object.
|
||||
pub fn from_strs(x: &str, y: &str) -> Result<Coords> {
|
||||
Ok(Coords {
|
||||
|
@ -69,16 +85,7 @@ impl Coords {
|
|||
|
||||
/// resolve the possibly relative coordinates relative to a given containers size
|
||||
pub fn relative_to(&self, width: i32, height: i32) -> (i32, i32) {
|
||||
(
|
||||
match self.x {
|
||||
NumWithUnit::Percent(n) => ((width as f64 / 100.0) * n as f64) as i32,
|
||||
NumWithUnit::Pixels(n) => n,
|
||||
},
|
||||
match self.y {
|
||||
NumWithUnit::Percent(n) => ((height as f64 / 100.0) * n as f64) as i32,
|
||||
NumWithUnit::Pixels(n) => n,
|
||||
},
|
||||
)
|
||||
(self.x.relative_to(width), self.y.relative_to(height))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue