From 0fca322bde886c18b75cebd1394d6dc8d461bb70 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Sun, 11 Oct 2020 19:01:12 +0200 Subject: [PATCH] Add stacking option to window definition --- src/app.rs | 29 ++++++++++++++++++++------ src/config/mod.rs | 52 ++++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 12 ++++++++++- src/util.rs | 25 +++++++++++++++++++++++ 4 files changed, 106 insertions(+), 12 deletions(-) diff --git a/src/app.rs b/src/app.rs index dc5ab74..b8f551b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,5 @@ use crate::*; +use config::WindowStacking; use debug_stub_derive::*; use script_var_handler::*; use std::collections::HashMap; @@ -27,7 +28,7 @@ impl App { pub fn handle_user_command(&mut self, opts: &Opt) -> Result<()> { match &opts.action { 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::KillServer => { log::info!("Received kill command, stopping server!"); @@ -68,14 +69,22 @@ impl App { Ok(()) } - fn open_window(&mut self, window_name: &config::WindowName) -> Result<()> { - let window_def = self + fn open_window( + &mut self, + window_name: &config::WindowName, + pos: Option, + size: Option, + ) -> Result<()> { + let mut window_def = self .eww_config .get_windows() .get(window_name) .context(format!("No window named '{}' defined", window_name))? .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); window.set_title("Eww"); window.set_wmclass("noswallow", "noswallow"); @@ -107,8 +116,14 @@ impl App { gdk_window.set_override_redirect(true); gdk_window.move_(window_def.position.0, window_def.position.1); 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); @@ -126,8 +141,10 @@ impl App { let windows = self.windows.clone(); for (window_name, window) in windows { + let old_pos = window.get_position(); + let old_size = window.get_size(); window.close(); - self.open_window(&window_name)?; + self.open_window(&window_name, Some(old_pos.into()), Some(old_size.into()))?; } Ok(()) } diff --git a/src/config/mod.rs b/src/config/mod.rs index c5c3042..4a2555f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,10 +2,12 @@ use crate::util; use crate::value::PrimitiveValue; use crate::value::VarName; use anyhow::*; +use derive_more; use element::*; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt; +use util::Coords; use xml_ext::*; pub mod element; @@ -163,8 +165,9 @@ impl fmt::Display for WindowName { #[derive(Debug, Clone, PartialEq)] pub struct EwwWindowDefinition { - pub position: (i32, i32), - pub size: (i32, i32), + pub position: Coords, + pub size: Coords, + pub stacking: WindowStacking, pub widget: WidgetUse, } @@ -173,11 +176,50 @@ impl EwwWindowDefinition { ensure_xml_tag_is!(xml, "window"); 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 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::()) + .transpose()? + .unwrap_or_else(WindowStacking::default); 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 { + 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 + )), + } } } diff --git a/src/main.rs b/src/main.rs index 5eab6aa..55732da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ #![feature(result_cloned)] #![feature(iterator_fold_self)] #![feature(try_blocks)] +#![feature(str_split_once)] + extern crate gio; extern crate gtk; @@ -70,7 +72,15 @@ pub enum OptAction { Update { fieldname: VarName, value: PrimitiveValue }, #[structopt(name = "open")] - OpenWindow { window_name: config::WindowName }, + OpenWindow { + window_name: config::WindowName, + + #[structopt(short, long)] + pos: Option, + + #[structopt(short, long)] + size: Option, + }, #[structopt(name = "close")] CloseWindow { window_name: config::WindowName }, diff --git a/src/util.rs b/src/util.rs index bf94020..c0081c4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,6 +2,8 @@ use anyhow::*; use extend::ext; use grass; use itertools::Itertools; +use serde::{Deserialize, Serialize}; +use std::fmt; use std::path::Path; pub fn parse_scss_from_file>(path: P) -> Result { @@ -37,3 +39,26 @@ pub fn parse_duration(s: &str) -> Result { 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 { + 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) + } +}