WIP
This commit is contained in:
parent
5e90576c49
commit
72100921e6
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -1,5 +1,7 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.14"
|
version = "0.7.14"
|
||||||
@ -15,6 +17,12 @@ version = "1.0.33"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixscreen"
|
name = "fixscreen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -22,6 +30,23 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"regex",
|
"regex",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"xrandr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -30,12 +55,24 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.139"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.3.4"
|
version = "2.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
@ -85,18 +122,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.21"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42"
|
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.21"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab"
|
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -117,3 +154,24 @@ name = "unicode-xid"
|
|||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x11"
|
||||||
|
version = "2.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xrandr"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9faecbb5f354fe09959775758b6f7b6524ee80103a6c5c66a57112a2f707862"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"thiserror",
|
||||||
|
"x11",
|
||||||
|
]
|
||||||
|
|||||||
@ -10,3 +10,4 @@ edition = "2018"
|
|||||||
thiserror = "1.0.21"
|
thiserror = "1.0.21"
|
||||||
anyhow = "1.0.33"
|
anyhow = "1.0.33"
|
||||||
regex = "1.4.2"
|
regex = "1.4.2"
|
||||||
|
xrandr = "0.1.1"
|
||||||
|
|||||||
88
src/lib.rs
88
src/lib.rs
@ -9,6 +9,59 @@ use std::{
|
|||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use xrandr::{XHandle, XrandrError};
|
||||||
|
|
||||||
|
pub fn swap_workspaces(cfg: &Config) -> Result<Vec<Result<Output, CommandError>>, CommandError> {
|
||||||
|
let monitors = XHandle::open()?.monitors()?;
|
||||||
|
|
||||||
|
// TODO(wathiede): if I ever get two monitors with the same resolution, use EDID to find a
|
||||||
|
// better key.
|
||||||
|
let map: HashMap<_, _> = monitors
|
||||||
|
.iter()
|
||||||
|
.map(|m| ((m.width_px as usize, m.height_px as usize), m.name.clone()))
|
||||||
|
.collect();
|
||||||
|
// TODO(wathiede):
|
||||||
|
// i3-msg commands to move them.
|
||||||
|
// Example:
|
||||||
|
// i3-msg '[workspace="trustee"]' move workspace to output DP-0
|
||||||
|
Ok(cfg
|
||||||
|
.screens
|
||||||
|
.iter()
|
||||||
|
.map(|s| {
|
||||||
|
let key = match s.orientation {
|
||||||
|
Orientation::None | Orientation::Invert => {
|
||||||
|
(s.resolution.width, s.resolution.height)
|
||||||
|
}
|
||||||
|
Orientation::Left | Orientation::Right => (s.resolution.height, s.resolution.width),
|
||||||
|
};
|
||||||
|
if let Some(m) = map.get(&key) {
|
||||||
|
println!("Moving {:?} to {}", s.workspaces, m);
|
||||||
|
run_move_workspace_cmd(&s.workspaces, m)
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
fn run_move_workspace_cmd(
|
||||||
|
workspaces: &[String],
|
||||||
|
monitor: &str,
|
||||||
|
) -> Vec<Result<Output, CommandError>> {
|
||||||
|
workspaces
|
||||||
|
.iter()
|
||||||
|
.map(|workspace| {
|
||||||
|
let s = format!(r#"'[workspace="{monitor}"]'"#);
|
||||||
|
let args = vec!["i3-msg", &s, "move", "workspace", "to", workspace];
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
Command::new("echo").args(args).output()
|
||||||
|
} else {
|
||||||
|
Command::new(&args[0]).args(&args[1..]).output()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|r| r.map_err(CommandError::from))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
@ -16,6 +69,8 @@ pub enum ParseError {
|
|||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
#[error("invalid data: {0}")]
|
#[error("invalid data: {0}")]
|
||||||
Parse(String),
|
Parse(String),
|
||||||
|
#[error("xrandr: {0}")]
|
||||||
|
XrandrError(#[from] XrandrError),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map monitor name to DFP connection.
|
// Map monitor name to DFP connection.
|
||||||
@ -43,20 +98,23 @@ pub enum CommandError {
|
|||||||
MissingMonitor(String),
|
MissingMonitor(String),
|
||||||
#[error("error executing command")]
|
#[error("error executing command")]
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
|
#[error("xrandr error: {0}")]
|
||||||
|
XrandrError(#[from] XrandrError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Resolution {
|
pub struct Resolution {
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Offset {
|
pub struct Offset {
|
||||||
pub x: isize,
|
pub x: isize,
|
||||||
pub y: isize,
|
pub y: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Orientation {
|
pub enum Orientation {
|
||||||
None,
|
None,
|
||||||
Right,
|
Right,
|
||||||
@ -80,12 +138,14 @@ impl fmt::Debug for Orientation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Screen {
|
pub struct Screen {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub resolution: Resolution,
|
pub resolution: Resolution,
|
||||||
pub offset: Offset,
|
pub offset: Offset,
|
||||||
pub orientation: Orientation,
|
pub orientation: Orientation,
|
||||||
|
pub primary: bool,
|
||||||
|
pub workspaces: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Screen {
|
impl Screen {
|
||||||
@ -119,16 +179,16 @@ impl Screen {
|
|||||||
))
|
))
|
||||||
/*
|
/*
|
||||||
Ok(format!("{connection}: {w}x{h} @{in_w}x{in_h} {x:+}{y:+} {{ForceCompositionPipeline=On, ViewPortIn={in_w}x{in_h}, ViewPortOut={w}x{h}+0+0, Rotation={rotation}}}",
|
Ok(format!("{connection}: {w}x{h} @{in_w}x{in_h} {x:+}{y:+} {{ForceCompositionPipeline=On, ViewPortIn={in_w}x{in_h}, ViewPortOut={w}x{h}+0+0, Rotation={rotation}}}",
|
||||||
connection=connection,
|
connection=connection,
|
||||||
w=width,
|
w=width,
|
||||||
h=height,
|
h=height,
|
||||||
in_w=in_w,
|
in_w=in_w,
|
||||||
in_h=in_h,
|
in_h=in_h,
|
||||||
x=x,
|
x=x,
|
||||||
y=y,
|
y=y,
|
||||||
rotation=rotation,
|
rotation=rotation,
|
||||||
))
|
))
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +197,7 @@ pub struct Config {
|
|||||||
pub screens: Vec<Screen>,
|
pub screens: Vec<Screen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_cmd(screen_mapping: &ScreenMapping, cfg: Config) -> Result<Output, CommandError> {
|
pub fn run_cmd(screen_mapping: &ScreenMapping, cfg: &Config) -> Result<Output, CommandError> {
|
||||||
let args = build_cmd_args(screen_mapping, cfg)?;
|
let args = build_cmd_args(screen_mapping, cfg)?;
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
Ok(Command::new("echo").args(args).output()?)
|
Ok(Command::new("echo").args(args).output()?)
|
||||||
@ -148,7 +208,7 @@ pub fn run_cmd(screen_mapping: &ScreenMapping, cfg: Config) -> Result<Output, Co
|
|||||||
|
|
||||||
fn build_cmd_args(
|
fn build_cmd_args(
|
||||||
screen_mapping: &ScreenMapping,
|
screen_mapping: &ScreenMapping,
|
||||||
cfg: Config,
|
cfg: &Config,
|
||||||
) -> Result<Vec<String>, CommandError> {
|
) -> Result<Vec<String>, CommandError> {
|
||||||
let metamode = cfg
|
let metamode = cfg
|
||||||
.screens
|
.screens
|
||||||
|
|||||||
15
src/main.rs
15
src/main.rs
@ -13,6 +13,7 @@ fn main() -> Result<()> {
|
|||||||
y: 1440 * 2 - 1920,
|
y: 1440 * 2 - 1920,
|
||||||
},
|
},
|
||||||
orientation: Orientation::Left,
|
orientation: Orientation::Left,
|
||||||
|
workspaces: vec!["distortion".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let lg = Screen {
|
let lg = Screen {
|
||||||
@ -29,6 +30,7 @@ fn main() -> Result<()> {
|
|||||||
x: 1 + dell.resolution.height as isize,
|
x: 1 + dell.resolution.height as isize,
|
||||||
y: 0,
|
y: 0,
|
||||||
},
|
},
|
||||||
|
workspaces: vec!["virtue".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let lenovo = Screen {
|
let lenovo = Screen {
|
||||||
@ -41,15 +43,24 @@ fn main() -> Result<()> {
|
|||||||
x: (dell.resolution.height + (lg.resolution.width - 2560) / 2) as isize,
|
x: (dell.resolution.height + (lg.resolution.width - 2560) / 2) as isize,
|
||||||
y: (lg.resolution.height) as isize,
|
y: (lg.resolution.height) as isize,
|
||||||
},
|
},
|
||||||
|
primary: true,
|
||||||
|
workspaces: vec!["fraud".to_string(), "twilight".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
let screens = vec![dell, lg, lenovo];
|
||||||
let cfg = Config {
|
let cfg = Config {
|
||||||
screens: vec![dell, lg, lenovo],
|
screens: screens.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let map = screen_mapping_from_xorg_log("/var/log/X.0.log")?;
|
let map = screen_mapping_from_xorg_log("/var/log/X.0.log")?;
|
||||||
let cmd = run_cmd(&map, cfg)?;
|
let cmd = run_cmd(&map, &cfg)?;
|
||||||
println!("cmd {:#?}", cmd);
|
println!("cmd {:#?}", cmd);
|
||||||
|
// TODO(wathiede): run xrandr --output $DPY --primary
|
||||||
|
// TODO(wathiede): i3-msg to move workspaces to proper places.
|
||||||
|
let res = swap_workspaces(&cfg)?;
|
||||||
|
for r in res {
|
||||||
|
println!("r = {:?}", r);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user