Improve flexibility of monitor configuration (#1003)
* Allow named monitors on wayland * Allow list of monitor matchers
This commit is contained in:
parent
fff40ce1a7
commit
4f1f853b5f
6 changed files with 55 additions and 33 deletions
|
@ -20,6 +20,8 @@ All notable changes to eww will be listed here, starting at changes since versio
|
||||||
- Add trigonometric functions (`sin`, `cos`, `tan`, `cot`) and degree/radian conversions (`degtorad`, `radtodeg`) (By: end-4)
|
- Add trigonometric functions (`sin`, `cos`, `tan`, `cot`) and degree/radian conversions (`degtorad`, `radtodeg`) (By: end-4)
|
||||||
- Add `substring` function to simplexpr
|
- Add `substring` function to simplexpr
|
||||||
- Add `--duration` flag to `eww open`
|
- Add `--duration` flag to `eww open`
|
||||||
|
- Add support for referring to monitor with `<primary>`
|
||||||
|
- Add support for multiple matchers in `monitor` field
|
||||||
|
|
||||||
## [0.4.0] (04.09.2022)
|
## [0.4.0] (04.09.2022)
|
||||||
|
|
||||||
|
|
|
@ -560,9 +560,6 @@ fn get_monitor_geometry(identifier: Option<MonitorIdentifier>) -> Result<gdk::Re
|
||||||
let monitor = match identifier {
|
let monitor = match identifier {
|
||||||
Some(ident) => {
|
Some(ident) => {
|
||||||
let mon = get_monitor_from_display(&display, &ident);
|
let mon = get_monitor_from_display(&display, &ident);
|
||||||
|
|
||||||
#[cfg(feature = "x11")]
|
|
||||||
{
|
|
||||||
mon.with_context(|| {
|
mon.with_context(|| {
|
||||||
let head = format!("Failed to get monitor {}\nThe available monitors are:", ident);
|
let head = format!("Failed to get monitor {}\nThe available monitors are:", ident);
|
||||||
let mut body = String::new();
|
let mut body = String::new();
|
||||||
|
@ -574,18 +571,6 @@ fn get_monitor_geometry(identifier: Option<MonitorIdentifier>) -> Result<gdk::Re
|
||||||
format!("{}{}", head, body)
|
format!("{}{}", head, body)
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "x11"))]
|
|
||||||
{
|
|
||||||
mon.with_context(|| {
|
|
||||||
if ident.is_numeric() {
|
|
||||||
format!("Failed to get monitor {}", ident)
|
|
||||||
} else {
|
|
||||||
format!("Using ouput names (\"{}\" in the configuration) is not supported outside of x11 yet", ident)
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => display
|
None => display
|
||||||
.primary_monitor()
|
.primary_monitor()
|
||||||
.context("Failed to get primary monitor from GTK. Try explicitly specifying the monitor on your window.")?,
|
.context("Failed to get primary monitor from GTK. Try explicitly specifying the monitor on your window.")?,
|
||||||
|
@ -597,12 +582,16 @@ fn get_monitor_geometry(identifier: Option<MonitorIdentifier>) -> Result<gdk::Re
|
||||||
/// Outside of x11, only [MonitorIdentifier::Numeric] is supported
|
/// Outside of x11, only [MonitorIdentifier::Numeric] is supported
|
||||||
pub fn get_monitor_from_display(display: &gdk::Display, identifier: &MonitorIdentifier) -> Option<gdk::Monitor> {
|
pub fn get_monitor_from_display(display: &gdk::Display, identifier: &MonitorIdentifier) -> Option<gdk::Monitor> {
|
||||||
match identifier {
|
match identifier {
|
||||||
|
MonitorIdentifier::List(list) => {
|
||||||
|
for ident in list {
|
||||||
|
if let Some(monitor) = get_monitor_from_display(display, ident) {
|
||||||
|
return Some(monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
MonitorIdentifier::Primary => display.primary_monitor(),
|
||||||
MonitorIdentifier::Numeric(num) => display.monitor(*num),
|
MonitorIdentifier::Numeric(num) => display.monitor(*num),
|
||||||
|
|
||||||
#[cfg(not(feature = "x11"))]
|
|
||||||
MonitorIdentifier::Name(_) => return None,
|
|
||||||
|
|
||||||
#[cfg(feature = "x11")]
|
|
||||||
MonitorIdentifier::Name(name) => {
|
MonitorIdentifier::Name(name) => {
|
||||||
for m in 0..display.n_monitors() {
|
for m in 0..display.n_monitors() {
|
||||||
if let Some(model) = display.monitor(m).and_then(|x| x.model()) {
|
if let Some(model) = display.monitor(m).and_then(|x| x.model()) {
|
||||||
|
|
|
@ -5,8 +5,10 @@ use serde::{Deserialize, Serialize};
|
||||||
/// The type of the identifier used to select a monitor
|
/// The type of the identifier used to select a monitor
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum MonitorIdentifier {
|
pub enum MonitorIdentifier {
|
||||||
|
List(Vec<MonitorIdentifier>),
|
||||||
Numeric(i32),
|
Numeric(i32),
|
||||||
Name(String),
|
Name(String),
|
||||||
|
Primary,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonitorIdentifier {
|
impl MonitorIdentifier {
|
||||||
|
@ -18,8 +20,10 @@ impl MonitorIdentifier {
|
||||||
impl fmt::Display for MonitorIdentifier {
|
impl fmt::Display for MonitorIdentifier {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::List(l) => write!(f, "[{}]", l.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" ")),
|
||||||
Self::Numeric(n) => write!(f, "{}", n),
|
Self::Numeric(n) => write!(f, "{}", n),
|
||||||
Self::Name(n) => write!(f, "{}", n),
|
Self::Name(n) => write!(f, "{}", n),
|
||||||
|
Self::Primary => write!(f, "<primary>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +34,13 @@ impl str::FromStr for MonitorIdentifier {
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.parse::<i32>() {
|
match s.parse::<i32>() {
|
||||||
Ok(n) => Ok(Self::Numeric(n)),
|
Ok(n) => Ok(Self::Numeric(n)),
|
||||||
Err(_) => Ok(Self::Name(s.to_owned())),
|
Err(_) => {
|
||||||
|
if &s.to_lowercase() == "<primary>" {
|
||||||
|
Ok(Self::Primary)
|
||||||
|
} else {
|
||||||
|
Ok(Self::Name(s.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::fmt::Display;
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::monitor::MonitorIdentifier,
|
config::monitor::MonitorIdentifier,
|
||||||
|
@ -24,13 +24,22 @@ pub struct WindowDefinition {
|
||||||
pub backend_options: BackendWindowOptions,
|
pub backend_options: BackendWindowOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromAst for MonitorIdentifier {
|
||||||
|
fn from_ast(x: Ast) -> DiagResult<Self> {
|
||||||
|
match x {
|
||||||
|
Ast::Array(_, x) => Ok(Self::List(x.into_iter().map(MonitorIdentifier::from_ast).collect::<DiagResult<_>>()?)),
|
||||||
|
other => Ok(Self::from_str(&String::from_ast(other)?).unwrap()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromAstElementContent for WindowDefinition {
|
impl FromAstElementContent for WindowDefinition {
|
||||||
const ELEMENT_NAME: &'static str = "defwindow";
|
const ELEMENT_NAME: &'static str = "defwindow";
|
||||||
|
|
||||||
fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
|
fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
|
||||||
let (_, name) = iter.expect_symbol()?;
|
let (_, name) = iter.expect_symbol()?;
|
||||||
let mut attrs = iter.expect_key_values()?;
|
let mut attrs = iter.expect_key_values()?;
|
||||||
let monitor = attrs.primitive_optional("monitor")?;
|
let monitor = attrs.ast_optional::<MonitorIdentifier>("monitor")?;
|
||||||
let resizable = attrs.primitive_optional("resizable")?.unwrap_or(true);
|
let resizable = attrs.primitive_optional("resizable")?.unwrap_or(true);
|
||||||
let stacking = attrs.primitive_optional("stacking")?.unwrap_or(WindowStacking::Foreground);
|
let stacking = attrs.primitive_optional("stacking")?.unwrap_or(WindowStacking::Foreground);
|
||||||
let geometry = attrs.ast_optional("geometry")?;
|
let geometry = attrs.ast_optional("geometry")?;
|
||||||
|
|
|
@ -71,6 +71,8 @@ impl Ast {
|
||||||
|
|
||||||
as_func!(AstType::List, as_list as_list_ref<Vec<Ast>> = Ast::List(_, x) => x);
|
as_func!(AstType::List, as_list as_list_ref<Vec<Ast>> = Ast::List(_, x) => x);
|
||||||
|
|
||||||
|
as_func!(AstType::Array, as_array as_array_ref<Vec<Ast>> = Ast::Array(_, x) => x);
|
||||||
|
|
||||||
pub fn expr_type(&self) -> AstType {
|
pub fn expr_type(&self) -> AstType {
|
||||||
match self {
|
match self {
|
||||||
Ast::List(..) => AstType::List,
|
Ast::List(..) => AstType::List,
|
||||||
|
|
|
@ -50,10 +50,20 @@ You can now open your first window by running `eww open example`! Glorious!
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ---------: | ------------------------------------------------------------ |
|
| ---------: | ------------------------------------------------------------ |
|
||||||
| `monitor` | Which monitor this window should be displayed on. Can be either a number (X11 and Wayland) or an output name (X11 only). |
|
| `monitor` | Which monitor this window should be displayed on. See below for details.|
|
||||||
| `geometry` | Geometry of the window. |
|
| `geometry` | Geometry of the window. |
|
||||||
|
|
||||||
|
|
||||||
|
**`monitor`-property**
|
||||||
|
|
||||||
|
This field can be:
|
||||||
|
|
||||||
|
- the string `<primary>`, in which case eww tries to identify the primary display (which may fail, especially on wayland)
|
||||||
|
- an integer, declaring the monitor index
|
||||||
|
- the name of the monitor
|
||||||
|
- an array of monitor matchers, such as: `["<primary>" "HDMI-A-1" "PHL 345B1C" 0]`. Eww will try to find a match in order, allowing you to specify fallbacks.
|
||||||
|
|
||||||
|
|
||||||
**`geometry`-properties**
|
**`geometry`-properties**
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
|
|
Loading…
Add table
Reference in a new issue