Add stacking option to window definition

This commit is contained in:
elkowar 2020-10-11 19:01:12 +02:00
parent 3d5509b570
commit 0fca322bde
4 changed files with 106 additions and 12 deletions

View file

@ -1,4 +1,5 @@
use crate::*; use crate::*;
use config::WindowStacking;
use debug_stub_derive::*; use debug_stub_derive::*;
use script_var_handler::*; use script_var_handler::*;
use std::collections::HashMap; use std::collections::HashMap;
@ -27,7 +28,7 @@ impl App {
pub fn handle_user_command(&mut self, opts: &Opt) -> Result<()> { pub fn handle_user_command(&mut self, opts: &Opt) -> Result<()> {
match &opts.action { match &opts.action {
OptAction::Update { fieldname, value } => self.update_state(fieldname.clone(), value.clone())?, OptAction::Update { fieldname, value } => self.update_state(fieldname.clone(), value.clone())?,
OptAction::OpenWindow { window_name } => self.open_window(&window_name)?, OptAction::OpenWindow { window_name, pos, size } => self.open_window(&window_name, *pos, *size)?,
OptAction::CloseWindow { window_name } => self.close_window(&window_name)?, OptAction::CloseWindow { window_name } => self.close_window(&window_name)?,
OptAction::KillServer => { OptAction::KillServer => {
log::info!("Received kill command, stopping server!"); log::info!("Received kill command, stopping server!");
@ -68,14 +69,22 @@ impl App {
Ok(()) Ok(())
} }
fn open_window(&mut self, window_name: &config::WindowName) -> Result<()> { fn open_window(
let window_def = self &mut self,
window_name: &config::WindowName,
pos: Option<util::Coords>,
size: Option<util::Coords>,
) -> Result<()> {
let mut window_def = self
.eww_config .eww_config
.get_windows() .get_windows()
.get(window_name) .get(window_name)
.context(format!("No window named '{}' defined", window_name))? .context(format!("No window named '{}' defined", window_name))?
.clone(); .clone();
window_def.position = pos.unwrap_or_else(|| window_def.position);
window_def.size = size.unwrap_or_else(|| window_def.size);
let window = gtk::Window::new(gtk::WindowType::Popup); let window = gtk::Window::new(gtk::WindowType::Popup);
window.set_title("Eww"); window.set_title("Eww");
window.set_wmclass("noswallow", "noswallow"); window.set_wmclass("noswallow", "noswallow");
@ -107,8 +116,14 @@ impl App {
gdk_window.set_override_redirect(true); gdk_window.set_override_redirect(true);
gdk_window.move_(window_def.position.0, window_def.position.1); gdk_window.move_(window_def.position.0, window_def.position.1);
gdk_window.show(); gdk_window.show();
gdk_window.raise();
window.set_keep_above(true); if window_def.stacking == WindowStacking::Foreground {
gdk_window.raise();
window.set_keep_above(true);
} else {
gdk_window.lower();
window.set_keep_below(true);
}
self.windows.insert(window_name.clone(), window); self.windows.insert(window_name.clone(), window);
@ -126,8 +141,10 @@ impl App {
let windows = self.windows.clone(); let windows = self.windows.clone();
for (window_name, window) in windows { for (window_name, window) in windows {
let old_pos = window.get_position();
let old_size = window.get_size();
window.close(); window.close();
self.open_window(&window_name)?; self.open_window(&window_name, Some(old_pos.into()), Some(old_size.into()))?;
} }
Ok(()) Ok(())
} }

View file

@ -2,10 +2,12 @@ use crate::util;
use crate::value::PrimitiveValue; use crate::value::PrimitiveValue;
use crate::value::VarName; use crate::value::VarName;
use anyhow::*; use anyhow::*;
use derive_more;
use element::*; use element::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use util::Coords;
use xml_ext::*; use xml_ext::*;
pub mod element; pub mod element;
@ -163,8 +165,9 @@ impl fmt::Display for WindowName {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct EwwWindowDefinition { pub struct EwwWindowDefinition {
pub position: (i32, i32), pub position: Coords,
pub size: (i32, i32), pub size: Coords,
pub stacking: WindowStacking,
pub widget: WidgetUse, pub widget: WidgetUse,
} }
@ -173,11 +176,50 @@ impl EwwWindowDefinition {
ensure_xml_tag_is!(xml, "window"); ensure_xml_tag_is!(xml, "window");
let size_node = xml.child("size")?; let size_node = xml.child("size")?;
let size = (size_node.attr("x")?.parse()?, size_node.attr("y")?.parse()?); let size = Coords(size_node.attr("x")?.parse()?, size_node.attr("y")?.parse()?);
let pos_node = xml.child("pos")?; let pos_node = xml.child("pos")?;
let position = (pos_node.attr("x")?.parse()?, pos_node.attr("y")?.parse()?); let position = Coords(pos_node.attr("x")?.parse()?, pos_node.attr("y")?.parse()?);
let stacking = xml
.attr("stacking")
.ok()
.map(|stacking| stacking.parse::<WindowStacking>())
.transpose()?
.unwrap_or_else(WindowStacking::default);
let widget = WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?; let widget = WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?;
Ok(EwwWindowDefinition { position, size, widget }) Ok(EwwWindowDefinition {
position,
size,
widget,
stacking,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display)]
pub enum WindowStacking {
Foreground,
Background,
}
impl Default for WindowStacking {
fn default() -> Self {
WindowStacking::Foreground
}
}
impl std::str::FromStr for WindowStacking {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let s = s.to_lowercase();
match s.as_str() {
"foreground" | "fg" | "f" => Ok(WindowStacking::Foreground),
"background" | "bg" | "b" => Ok(WindowStacking::Background),
_ => Err(anyhow!(
"Couldn't parse '{}' as window stacking, must be either foreground, fg, background or bg",
s
)),
}
} }
} }

View file

@ -2,6 +2,8 @@
#![feature(result_cloned)] #![feature(result_cloned)]
#![feature(iterator_fold_self)] #![feature(iterator_fold_self)]
#![feature(try_blocks)] #![feature(try_blocks)]
#![feature(str_split_once)]
extern crate gio; extern crate gio;
extern crate gtk; extern crate gtk;
@ -70,7 +72,15 @@ pub enum OptAction {
Update { fieldname: VarName, value: PrimitiveValue }, Update { fieldname: VarName, value: PrimitiveValue },
#[structopt(name = "open")] #[structopt(name = "open")]
OpenWindow { window_name: config::WindowName }, OpenWindow {
window_name: config::WindowName,
#[structopt(short, long)]
pos: Option<util::Coords>,
#[structopt(short, long)]
size: Option<util::Coords>,
},
#[structopt(name = "close")] #[structopt(name = "close")]
CloseWindow { window_name: config::WindowName }, CloseWindow { window_name: config::WindowName },

View file

@ -2,6 +2,8 @@ use anyhow::*;
use extend::ext; use extend::ext;
use grass; use grass;
use itertools::Itertools; use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::path::Path; use std::path::Path;
pub fn parse_scss_from_file<P: AsRef<Path>>(path: P) -> Result<String> { pub fn parse_scss_from_file<P: AsRef<Path>>(path: P) -> Result<String> {
@ -37,3 +39,26 @@ pub fn parse_duration(s: &str) -> Result<std::time::Duration> {
Err(anyhow!("unrecognized time format: {}", s)) Err(anyhow!("unrecognized time format: {}", s))
} }
} }
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
pub struct Coords(pub i32, pub i32);
impl fmt::Display for Coords {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}x{}", self.0, self.1)
}
}
impl std::str::FromStr for Coords {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let (x, y) = s.split_once('x').ok_or_else(|| anyhow!("must be formatted like 200x500"))?;
Ok(Coords(x.parse()?, y.parse()?))
}
}
impl From<(i32, i32)> for Coords {
fn from((x, y): (i32, i32)) -> Self {
Coords(x, y)
}
}