Add ICCCM WM_NORMAL_HINTS
This commit is contained in:
parent
692e55c246
commit
bb00bad0e4
5 changed files with 281 additions and 12 deletions
|
@ -13,6 +13,7 @@ homepage = "https://git.friedl.net/incubator/xcb-wm"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
xcb = "1"
|
xcb = "1"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
bitflags = "1.3.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
icccm = []
|
icccm = []
|
||||||
|
|
|
@ -112,17 +112,6 @@ mod tests {
|
||||||
println!("{:?}", reply);
|
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]
|
// #[test]
|
||||||
// fn number_of_desktops2() {
|
// fn number_of_desktops2() {
|
||||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
|
|
@ -76,7 +76,7 @@ impl<'a> Connection<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::icccm::proto::SetWmName;
|
use crate::icccm::proto::{GetWmNormalHints, SetWmName, SetWmNormalHints, WmSizeHints};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn number_of_desktops() {
|
fn number_of_desktops() {
|
||||||
|
@ -108,4 +108,19 @@ mod tests {
|
||||||
let reply = xcb_con.check_request(cookie);
|
let reply = xcb_con.check_request(cookie);
|
||||||
println!("{:?}", reply);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use std::convert::TryInto;
|
||||||
use xcb::{Xid, XidNew};
|
use xcb::{Xid, XidNew};
|
||||||
|
|
||||||
use crate::icccm::traits::*;
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue