Add ICCCM WM_NORMAL_HINTS

This commit is contained in:
Armin Friedl 2022-06-03 06:59:43 +02:00
parent 692e55c246
commit bb00bad0e4
5 changed files with 281 additions and 12 deletions

View file

@ -13,6 +13,7 @@ homepage = "https://git.friedl.net/incubator/xcb-wm"
[dependencies]
xcb = "1"
paste = "1"
bitflags = "1.3.2"
[features]
icccm = []

View file

@ -112,17 +112,6 @@ mod tests {
println!("{:?}", reply);
}
#[test]
fn set_number_of_desktops() {
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
let request = crate::ewmh::proto::SetNumberOfDesktops::new(&ewmh_con, 4);
let cookie = ewmh_con.send_request_checked(&request);
let reply = xcb_con.check_request(cookie);
println!("{:?}", reply);
}
// #[test]
// fn number_of_desktops2() {
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;

View file

@ -76,7 +76,7 @@ impl<'a> Connection<'a> {
#[cfg(test)]
mod tests {
use crate::icccm::proto::SetWmName;
use crate::icccm::proto::{GetWmNormalHints, SetWmName, SetWmNormalHints, WmSizeHints};
#[test]
fn number_of_desktops() {
@ -108,4 +108,19 @@ mod tests {
let reply = xcb_con.check_request(cookie);
println!("{:?}", reply);
}
#[test]
fn get_wm_normal_hints() {
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let icccm_con = crate::icccm::Connection::connect(&xcb_con);
use xcb::XidNew;
let window = unsafe { xcb::x::Window::new(0x440013e) };
let request = GetWmNormalHints::new(window);
let cookie = icccm_con.send_request(&request);
let reply = icccm_con.wait_for_reply(cookie);
println!("{:?}", reply);
}
}

View file

@ -4,6 +4,8 @@
#![allow(dead_code)]
use bitflags::bitflags;
use std::convert::TryInto;
use xcb::{Xid, XidNew};
use crate::icccm::traits::*;
@ -257,3 +259,225 @@ icccm_set_property! {
}
}
// }}}
// WM_NORMAL_HINTS,
// {{{
bitflags! {
struct WmSizeHintsFlags: u32 {
const Empty = 0b0000_0000_0000;
const USPosition = 0b0000_0000_0001;
const USSize = 0b0000_0000_0010;
const PPosition = 0b0000_0000_0100;
const PSize = 0b0000_0000_1000;
const PMinSize = 0b0000_0001_0000;
const PMaxSize = 0b0000_0010_0000;
const PResizeInc = 0b0000_0100_0000;
const PAspect = 0b0000_1000_0000;
const PBaseSize = 0b0001_0000_0000;
const PWinGravity = 0b0010_0000_0000;
}
}
#[derive(Debug)]
pub struct WmSizeHints {
flags: WmSizeHintsFlags,
x: u32,
y: u32,
width: u32,
height: u32,
min_width: u32,
min_height: u32,
max_width: u32,
max_height: u32,
width_inc: u32,
height_inc: u32,
min_aspect: (u32, u32),
max_aspect: (u32, u32),
base_width: u32,
base_height: u32,
win_gravity: xcb::x::Gravity,
}
impl Default for WmSizeHints {
fn default() -> Self {
WmSizeHints {
flags: WmSizeHintsFlags::Empty,
x: 0,
y: 0,
width: 0,
height: 0,
min_width: 0,
min_height: 0,
max_width: 0,
max_height: 0,
width_inc: 0,
height_inc: 0,
min_aspect: (0, 0),
max_aspect: (0, 0),
base_width: 0,
base_height: 0,
win_gravity: xcb::x::Gravity::NorthWest,
}
}
}
impl WmSizeHints {
pub fn as_data(&mut self) -> Vec<u32> {
vec![
self.flags.bits,
self.x,
self.y,
self.width,
self.height,
self.min_width,
self.min_height,
self.max_width,
self.max_height,
self.width_inc,
self.height_inc,
self.min_aspect.0,
self.min_aspect.1,
self.max_aspect.0,
self.max_aspect.1,
self.base_width,
self.base_height,
self.win_gravity as u32,
]
}
pub fn from_reply(reply: xcb::x::GetPropertyReply) -> WmSizeHints {
let packed_vals = reply.value::<u32>();
WmSizeHints {
flags: WmSizeHintsFlags::from_bits_truncate(packed_vals[0]),
x: packed_vals[1],
y: packed_vals[2],
width: packed_vals[3],
height: packed_vals[4],
min_width: packed_vals[5],
min_height: packed_vals[6],
max_width: packed_vals[7],
max_height: packed_vals[8],
width_inc: packed_vals[9],
height_inc: packed_vals[10],
min_aspect: (packed_vals[11], packed_vals[12]),
max_aspect: (packed_vals[13], packed_vals[14]),
base_width: packed_vals[15],
base_height: packed_vals[16],
win_gravity: unsafe { std::mem::transmute(packed_vals[17]) },
}
}
pub fn position(&mut self, user_specified: bool, x: u32, y: u32) {
// reset
self.flags &= !(WmSizeHintsFlags::USPosition | WmSizeHintsFlags::PPosition);
if user_specified {
self.flags |= WmSizeHintsFlags::USPosition
} else {
self.flags |= WmSizeHintsFlags::PPosition
}
self.x = x;
self.y = y;
}
pub fn size(&mut self, user_specified: bool, width: u32, height: u32) {
// reset
self.flags &= !(WmSizeHintsFlags::USSize | WmSizeHintsFlags::PSize);
if user_specified {
self.flags |= WmSizeHintsFlags::USSize
} else {
self.flags |= WmSizeHintsFlags::PSize
}
self.width = width;
self.height = height;
}
pub fn min_size(&mut self, min_width: u32, min_height: u32) {
self.flags |= WmSizeHintsFlags::PMinSize;
self.min_width = min_width;
self.min_height = min_height;
}
pub fn max_size(&mut self, max_width: u32, max_height: u32) {
self.flags |= WmSizeHintsFlags::PMaxSize;
self.max_width = max_width;
self.max_height = max_height;
}
pub fn resize_inc(&mut self, width_inc: u32, height_inc: u32) {
self.flags |= WmSizeHintsFlags::PResizeInc;
self.width_inc = width_inc;
self.height_inc = height_inc;
}
pub fn aspect(&mut self, min_aspect: (u32, u32), max_aspect: (u32, u32)) {
self.flags |= WmSizeHintsFlags::PAspect;
self.min_aspect = min_aspect;
self.max_aspect = max_aspect;
}
pub fn base_size(&mut self, base_width: u32, base_height: u32) {
self.flags |= WmSizeHintsFlags::PBaseSize;
self.base_width = base_width;
self.base_height = base_height;
}
pub fn win_gravity(&mut self, win_gravity: xcb::x::Gravity) {
self.flags |= WmSizeHintsFlags::PWinGravity;
self.win_gravity = win_gravity;
}
}
#[derive(Debug)]
pub struct GetWmNormalHintsReply {
pub size_hints: WmSizeHints,
}
impl From<xcb::x::GetPropertyReply> for GetWmNormalHintsReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetWmNormalHintsReply {
size_hints: WmSizeHints::from_reply(reply),
}
}
}
icccm_get_property! {
request=GetWmNormalHints{
window: client,
property: ATOM_WM_NORMAL_HINTS,
xtype: ATOM_WM_SIZE_HINTS
},
reply=GetWmNormalHintsReply
}
pub struct SetWmNormalHints {
window: xcb::x::Window,
data: Vec<u32>,
}
impl SetWmNormalHints {
pub fn new(window: xcb::x::Window, size_hints: &mut WmSizeHints) -> SetWmNormalHints {
SetWmNormalHints {
window: window,
data: size_hints.as_data(),
}
}
}
icccm_set_hint_property! {
request=SetWmNormalHints{
property: ATOM_WM_NORMAL_HINTS,
xtype: ATOM_WM_SIZE_HINTS
}
}
// }}}

View file

@ -126,3 +126,43 @@ macro_rules! icccm_set_property {
}
};
}
macro_rules! icccm_set_hint_property {
(request=$request:ident{
property: $property:ident,
xtype: $type:ident
}) => {
impl<'a> IcccmRequest<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, u32>;
type IcccmCookie = xcb::VoidCookie;
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace,
window: self.window,
property: xcb::x::$property,
r#type: xcb::x::$type,
data: &self.data,
}
}
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::IcccmCookie {
xcb_cookie
}
}
impl<'a> IcccmVoidRequestChecked<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, u32>;
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace,
window: self.window,
property: xcb::x::$property,
r#type: xcb::x::$type,
data: &self.data,
}
}
}
};
}