Set _NET_WM_WINDOW_TYPE and related fields properly (#176)

* add windowtype attribute to window tag. set _NET_WM_WINDOW_TYPE property for x11

* up

* remove strum and strum_macros dependencies

* Update configuration.md

* Update window_definition.rs

* Update window_definition.rs

should work now

Co-authored-by: Midnight Exigent <6959267-midnightexigent@users.noreply.gitlab.com>
This commit is contained in:
Midnight Exigent 2021-07-15 13:37:50 +02:00 committed by GitHub
parent 1ed4925eb1
commit 31730bea32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 19 deletions

24
Cargo.lock generated
View file

@ -389,6 +389,8 @@ dependencies = [
"simple-signal", "simple-signal",
"smart-default", "smart-default",
"structopt", "structopt",
"strum 0.20.0",
"strum_macros 0.20.1",
"sysinfo", "sysinfo",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
@ -1711,6 +1713,12 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
[[package]]
name = "strum"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c"
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.18.0" version = "0.18.0"
@ -1723,6 +1731,18 @@ dependencies = [
"syn 1.0.72", "syn 1.0.72",
] ]
[[package]]
name = "strum_macros"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149"
dependencies = [
"heck",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.72",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.11.11" version = "0.11.11"
@ -1778,8 +1798,8 @@ checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
dependencies = [ dependencies = [
"heck", "heck",
"pkg-config", "pkg-config",
"strum", "strum 0.18.0",
"strum_macros", "strum_macros 0.18.0",
"thiserror", "thiserror",
"toml", "toml",
"version-compare", "version-compare",

View file

@ -220,7 +220,7 @@ For Wayland users the `<reserve/>` block is replaced by the exclusive field in `
The previous `<window>` block would look like this. The previous `<window>` block would look like this.
```xml ```xml
<window name="main_window" stacking="fg" focusable="false" screen="1" exclusive="true"> <window name="main_window" stacking="fg" focusable="false" screen="1" exclusive="true" windowtype="normal">
<geometry anchor="top left" x="300px" y="50%" width="25%" height="20px"/> <geometry anchor="top left" x="300px" y="50%" width="25%" height="20px"/>
<widget> <widget>
<main/> <main/>
@ -247,3 +247,10 @@ There are a couple things you can optionally configure on the window itself:
The details on how it is actually implemented are left to the compositor. The details on how it is actually implemented are left to the compositor.
This option is only valid on Wayland. This option is only valid on Wayland.
Possible values: `"true"`, `"false"`. Default: `"false"` Possible values: `"true"`, `"false"`. Default: `"false"`
- `windowtype`: (X11 only) Can be used in determining the decoration, stacking position and other behavior of the window.
Possible values:
- `"normal"`: indicates that this is a normal, top-level window
- `"dock"`: indicates a dock or panel feature
- `"toolbar"`: toolbars "torn off" from the main application
- `"dialog"`: indicates that this is a dialog window
- Default: `"dock"` if reserve is set, else `"normal"`

View file

@ -93,7 +93,7 @@ contain are defined. -->
<windows> <windows>
<!-- These are the windows --> <!-- These are the windows -->
<window name="bar" screen="0"> <window name="bar" screen="0" focusable="true" windowtype="dock">
<geometry x="0%" y="0%" width="100%" height="4%"/> <!--Specifies geometry--> <geometry x="0%" y="0%" width="100%" height="4%"/> <!--Specifies geometry-->
<reserve side="top" distance="4%" layer="top"/> <reserve side="top" distance="4%" layer="top"/>
<widget> <widget>

View file

@ -307,7 +307,6 @@ fn initialize_window(
window_def: config::EwwWindowDefinition, window_def: config::EwwWindowDefinition,
) -> Result<EwwWindow> { ) -> Result<EwwWindow> {
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry); let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
if let Some(window) = display_backend::initialize_window(&window_def, monitor_geometry) { if let Some(window) = display_backend::initialize_window(&window_def, monitor_geometry) {
window.set_title(&format!("Eww - {}", window_def.name)); window.set_title(&format!("Eww - {}", window_def.name));
let wm_class_name = format!("eww-{}", window_def.name); let wm_class_name = format!("eww-{}", window_def.name);
@ -329,7 +328,7 @@ fn initialize_window(
gdk_window.set_override_redirect(!window_def.focusable); gdk_window.set_override_redirect(!window_def.focusable);
#[cfg(feature = "x11")] #[cfg(feature = "x11")]
display_backend::reserve_space_for(&window, monitor_geometry, window_def.struts)?; display_backend::set_xprops(&window, monitor_geometry, &window_def)?;
// this should only be required on x11, as waylands layershell should manage the margins properly anways. // this should only be required on x11, as waylands layershell should manage the margins properly anways.
#[cfg(feature = "x11")] #[cfg(feature = "x11")]
@ -344,7 +343,6 @@ fn initialize_window(
} else { } else {
Err(anyhow!("monitor {} is unavailable", window_def.screen_number.unwrap())) Err(anyhow!("monitor {} is unavailable", window_def.screen_number.unwrap()))
} }
} }
/// Apply the provided window-positioning rules to the window. /// Apply the provided window-positioning rules to the window.

View file

@ -1,26 +1,55 @@
use super::*;
use crate::{ensure_xml_tag_is, value::NumWithUnit, widgets::widget_node}; use crate::{ensure_xml_tag_is, value::NumWithUnit, widgets::widget_node};
use anyhow::*;
use derive_more::*; use derive_more::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smart_default::SmartDefault; use smart_default::SmartDefault;
use std::collections::HashMap; use std::{collections::HashMap, str::FromStr};
use super::*; #[derive(Debug, Clone, PartialEq)]
pub enum EwwWindowType {
Dock,
Dialog,
Toolbar,
Normal,
}
impl FromStr for EwwWindowType {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"dock" => Ok(Self::Dock),
"toolbar" => Ok(Self::Toolbar),
"dialog" => Ok(Self::Dialog),
"normal" => Ok(Self::Normal),
x => Err(anyhow!("Unknown windowtype provided '{}'. Possible values are: dock, toolbar, dialog, normal", x)),
}
}
}
impl Default for EwwWindowType {
fn default() -> Self {
Self::Normal
}
}
/// Full window-definition containing the fully expanded widget tree. /// Full window-definition containing the fully expanded widget tree.
/// **Use this** rather than `[RawEwwWindowDefinition]`. /// **Use this** rather than `[RawEwwWindowDefinition]`.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EwwWindowDefinition { pub struct EwwWindowDefinition {
pub name: WindowName, pub name: WindowName,
pub geometry: EwwWindowGeometry, pub geometry: EwwWindowGeometry,
pub stacking: WindowStacking, pub stacking: WindowStacking,
pub screen_number: Option<i32>, pub screen_number: Option<i32>,
pub widget: Box<dyn widget_node::WidgetNode>, pub widget: Box<dyn widget_node::WidgetNode>,
pub focusable: bool, pub focusable: bool,
#[cfg(feature = "x11")]
pub window_type: EwwWindowType,
#[cfg(feature = "x11")] #[cfg(feature = "x11")]
pub struts: StrutDefinition, pub struts: StrutDefinition,
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
pub exclusive: bool, pub exclusive: bool,
} }
@ -35,6 +64,8 @@ impl EwwWindowDefinition {
widget: widget_node::generate_generic_widget_node(defs, &HashMap::new(), window.widget)?, widget: widget_node::generate_generic_widget_node(defs, &HashMap::new(), window.widget)?,
focusable: window.focusable, focusable: window.focusable,
#[cfg(feature = "x11")] #[cfg(feature = "x11")]
window_type: window.window_type,
#[cfg(feature = "x11")]
struts: window.struts, struts: window.struts,
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
exclusive: window.exclusive, exclusive: window.exclusive,
@ -52,6 +83,9 @@ pub struct RawEwwWindowDefinition {
pub widget: WidgetUse, pub widget: WidgetUse,
pub focusable: bool, pub focusable: bool,
#[cfg(feature = "x11")]
pub window_type: EwwWindowType,
#[cfg(feature = "x11")] #[cfg(feature = "x11")]
pub struts: StrutDefinition, pub struts: StrutDefinition,
@ -78,6 +112,14 @@ impl RawEwwWindowDefinition {
Ok(node) => EwwWindowGeometry::from_xml_element(node)?, Ok(node) => EwwWindowGeometry::from_xml_element(node)?,
Err(_) => EwwWindowGeometry::default(), Err(_) => EwwWindowGeometry::default(),
}, },
#[cfg(feature = "x11")]
window_type: match xml.attr("windowtype") {
Ok(v) => EwwWindowType::from_str(&v)?,
Err(_) => match struts {
Some(_) => EwwWindowType::Dock,
None => Default::default(),
},
},
widget: WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?, widget: WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?,
stacking, stacking,
screen_number, screen_number,

View file

@ -108,7 +108,7 @@ mod platform {
#[cfg(feature = "x11")] #[cfg(feature = "x11")]
mod platform { mod platform {
use crate::config::{EwwWindowDefinition, Side, StrutDefinition, WindowStacking}; use crate::config::{EwwWindowDefinition, EwwWindowType, Side, WindowStacking};
use anyhow::*; use anyhow::*;
use gdkx11; use gdkx11;
use gtk::{self, prelude::*}; use gtk::{self, prelude::*};
@ -139,9 +139,9 @@ mod platform {
Some(window) Some(window)
} }
pub fn reserve_space_for(window: &gtk::Window, monitor: gdk::Rectangle, strut_def: StrutDefinition) -> Result<()> { pub fn set_xprops(window: &gtk::Window, monitor: gdk::Rectangle, window_def: &EwwWindowDefinition) -> Result<()> {
let backend = X11Backend::new()?; let backend = X11Backend::new()?;
backend.reserve_space_for(window, monitor, strut_def)?; backend.set_xprops_for(window, monitor, window_def)?;
Ok(()) Ok(())
} }
@ -159,11 +159,11 @@ mod platform {
Ok(X11Backend { conn, root_window: screen.root, atoms }) Ok(X11Backend { conn, root_window: screen.root, atoms })
} }
fn reserve_space_for( fn set_xprops_for(
&self, &self,
window: &gtk::Window, window: &gtk::Window,
monitor_rect: gdk::Rectangle, monitor_rect: gdk::Rectangle,
strut_def: StrutDefinition, window_def: &EwwWindowDefinition,
) -> Result<()> { ) -> Result<()> {
let win_id = window let win_id = window
.get_window() .get_window()
@ -172,6 +172,7 @@ mod platform {
.ok() .ok()
.context("Failed to get x11 window for gtk window")? .context("Failed to get x11 window for gtk window")?
.get_xid() as u32; .get_xid() as u32;
let strut_def = window_def.struts;
let root_window_geometry = self.conn.get_geometry(self.root_window)?.reply()?; let root_window_geometry = self.conn.get_geometry(self.root_window)?.reply()?;
let mon_end_x = (monitor_rect.x + monitor_rect.width) as u32 - 1u32; let mon_end_x = (monitor_rect.x + monitor_rect.width) as u32 - 1u32;
@ -217,16 +218,33 @@ mod platform {
&strut_list, &strut_list,
)? )?
.check()?; .check()?;
self.conn.flush()?;
Ok(()) x11rb::wrapper::ConnectionExt::change_property32(
&self.conn,
PropMode::REPLACE,
win_id,
self.atoms._NET_WM_WINDOW_TYPE,
self.atoms.ATOM,
&[match window_def.window_type {
EwwWindowType::Dock => self.atoms._NET_WM_WINDOW_TYPE_DOCK,
EwwWindowType::Normal => self.atoms._NET_WM_WINDOW_TYPE_NORMAL,
EwwWindowType::Dialog => self.atoms._NET_WM_WINDOW_TYPE_DIALOG,
EwwWindowType::Toolbar => self.atoms._NET_WM_WINDOW_TYPE_TOOLBAR,
}],
)?
.check()?;
self.conn.flush().context("Failed to send requests to X server")
} }
} }
x11rb::atom_manager! { x11rb::atom_manager! {
pub AtomCollection: AtomCollectionCookie { pub AtomCollection: AtomCollectionCookie {
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE,
_NET_WM_WINDOW_TYPE_NORMAL,
_NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_TOOLBAR,
_NET_WM_STATE, _NET_WM_STATE,
_NET_WM_STATE_STICKY, _NET_WM_STATE_STICKY,
_NET_WM_STATE_ABOVE, _NET_WM_STATE_ABOVE,