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",
"smart-default",
"structopt",
"strum 0.20.0",
"strum_macros 0.20.1",
"sysinfo",
"tokio",
"tokio-stream",
@ -1711,6 +1713,12 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
[[package]]
name = "strum"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c"
[[package]]
name = "strum_macros"
version = "0.18.0"
@ -1723,6 +1731,18 @@ dependencies = [
"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]]
name = "syn"
version = "0.11.11"
@ -1778,8 +1798,8 @@ checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
dependencies = [
"heck",
"pkg-config",
"strum",
"strum_macros",
"strum 0.18.0",
"strum_macros 0.18.0",
"thiserror",
"toml",
"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.
```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"/>
<widget>
<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.
This option is only valid on Wayland.
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>
<!-- 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-->
<reserve side="top" distance="4%" layer="top"/>
<widget>

View file

@ -307,7 +307,6 @@ fn initialize_window(
window_def: config::EwwWindowDefinition,
) -> Result<EwwWindow> {
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
if let Some(window) = display_backend::initialize_window(&window_def, monitor_geometry) {
window.set_title(&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);
#[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.
#[cfg(feature = "x11")]
@ -344,7 +343,6 @@ fn initialize_window(
} else {
Err(anyhow!("monitor {} is unavailable", window_def.screen_number.unwrap()))
}
}
/// 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 anyhow::*;
use derive_more::*;
use serde::{Deserialize, Serialize};
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.
/// **Use this** rather than `[RawEwwWindowDefinition]`.
#[derive(Debug, Clone)]
pub struct EwwWindowDefinition {
pub name: WindowName,
pub geometry: EwwWindowGeometry,
pub stacking: WindowStacking,
pub screen_number: Option<i32>,
pub widget: Box<dyn widget_node::WidgetNode>,
pub focusable: bool,
#[cfg(feature = "x11")]
pub window_type: EwwWindowType,
#[cfg(feature = "x11")]
pub struts: StrutDefinition,
#[cfg(feature = "wayland")]
pub exclusive: bool,
}
@ -35,6 +64,8 @@ impl EwwWindowDefinition {
widget: widget_node::generate_generic_widget_node(defs, &HashMap::new(), window.widget)?,
focusable: window.focusable,
#[cfg(feature = "x11")]
window_type: window.window_type,
#[cfg(feature = "x11")]
struts: window.struts,
#[cfg(feature = "wayland")]
exclusive: window.exclusive,
@ -52,6 +83,9 @@ pub struct RawEwwWindowDefinition {
pub widget: WidgetUse,
pub focusable: bool,
#[cfg(feature = "x11")]
pub window_type: EwwWindowType,
#[cfg(feature = "x11")]
pub struts: StrutDefinition,
@ -78,6 +112,14 @@ impl RawEwwWindowDefinition {
Ok(node) => EwwWindowGeometry::from_xml_element(node)?,
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()?)?,
stacking,
screen_number,

View file

@ -108,7 +108,7 @@ mod platform {
#[cfg(feature = "x11")]
mod platform {
use crate::config::{EwwWindowDefinition, Side, StrutDefinition, WindowStacking};
use crate::config::{EwwWindowDefinition, EwwWindowType, Side, WindowStacking};
use anyhow::*;
use gdkx11;
use gtk::{self, prelude::*};
@ -139,9 +139,9 @@ mod platform {
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()?;
backend.reserve_space_for(window, monitor, strut_def)?;
backend.set_xprops_for(window, monitor, window_def)?;
Ok(())
}
@ -159,11 +159,11 @@ mod platform {
Ok(X11Backend { conn, root_window: screen.root, atoms })
}
fn reserve_space_for(
fn set_xprops_for(
&self,
window: &gtk::Window,
monitor_rect: gdk::Rectangle,
strut_def: StrutDefinition,
window_def: &EwwWindowDefinition,
) -> Result<()> {
let win_id = window
.get_window()
@ -172,6 +172,7 @@ mod platform {
.ok()
.context("Failed to get x11 window for gtk window")?
.get_xid() as u32;
let strut_def = window_def.struts;
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;
@ -217,16 +218,33 @@ mod platform {
&strut_list,
)?
.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! {
pub AtomCollection: AtomCollectionCookie {
_NET_WM_WINDOW_TYPE,
_NET_WM_WINDOW_TYPE_NORMAL,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_TOOLBAR,
_NET_WM_STATE,
_NET_WM_STATE_STICKY,
_NET_WM_STATE_ABOVE,