Add stacking option to window definition
This commit is contained in:
parent
3d5509b570
commit
0fca322bde
4 changed files with 106 additions and 12 deletions
29
src/app.rs
29
src/app.rs
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -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 },
|
||||||
|
|
25
src/util.rs
25
src/util.rs
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue