Implement application properties

https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048
This commit is contained in:
Armin Friedl 2022-05-21 20:27:44 +02:00
parent bee554c057
commit 1729b8c2b1
8 changed files with 703 additions and 702 deletions

View file

@ -4,7 +4,7 @@ version = "0.1.0"
authors = [ "Armin Friedl <dev@friedl.net>" ] authors = [ "Armin Friedl <dev@friedl.net>" ]
description = "Rust implementation of xcb-wm - icccm and ewmh extensions for xcb" description = "Rust implementation of xcb-wm - icccm and ewmh extensions for xcb"
readme = "README.md" readme = "README.md"
keywords = ["icccm", "ewmh", "xcb-wm", "xcb", "window", "xlib", "x11"] keywords = ["icccm", "ewmh", "xcb", "window", "x11"]
license = "MIT" license = "MIT"
edition = "2018" edition = "2018"
repository = "https://git.friedl.net/incubator/xcb-wm" repository = "https://git.friedl.net/incubator/xcb-wm"

View file

@ -101,28 +101,28 @@ mod tests {
// println!("{:?}", reply); // println!("{:?}", reply);
// } // }
// //
// #[test] #[test]
// fn number_of_desktops() { fn number_of_desktops() {
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0; let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con); let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
//
// let request = crate::ewmh::proto::GetNumberOfDesktops::new(); let request = crate::ewmh::proto::GetNumberOfDesktops;
// let cookie = ewmh_con.send_request(request); let cookie = ewmh_con.send_request(&request);
// let reply = ewmh_con.wait_for_reply(cookie); let reply = ewmh_con.wait_for_reply(cookie);
// println!("{:?}", reply); println!("{:?}", reply);
// } }
//
// #[test] #[test]
// fn set_number_of_desktops() { fn set_number_of_desktops() {
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0; let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con); let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
//
// let request = crate::ewmh::proto::SetNumberOfDesktops::new(4); let request = crate::ewmh::proto::SetNumberOfDesktops::new(&ewmh_con, 4);
// let cookie = ewmh_con.send_request(request); let cookie = ewmh_con.send_request_checked(&request);
// let reply = xcb_con.check_request(cookie); let reply = xcb_con.check_request(cookie);
// println!("{:?}", reply); 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;

View file

@ -4,19 +4,15 @@
use xcb::{Xid, XidNew}; use xcb::{Xid, XidNew};
use crate::ewmh::connection::Connection; use crate::ewmh::proto::util::{strings_to_x_buffer, x_buffer_to_strings};
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData}; use crate::ewmh::traits::*;
use crate::ewmh::Connection;
// _NET_WM_NAME, UTF8_STRING // _NET_WM_NAME, UTF8_STRING
// {{{ // {{{
ewmh_get_window_request! { pub struct GetWmName(xcb::x::Window);
GetWmName, pub struct GetWmNameCookie(xcb::x::GetPropertyCookie);
_NET_WM_NAME, pub struct GetWmNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
UTF8_STRING,
GetWmNameCookie,
GetWmNameCookieUnchecked,
GetWmNameReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWmNameReply { pub struct GetWmNameReply {
@ -25,31 +21,52 @@ pub struct GetWmNameReply {
impl From<xcb::x::GetPropertyReply> for GetWmNameReply { impl From<xcb::x::GetPropertyReply> for GetWmNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmNameReply { GetWmNameReply {
name: String::from_utf8(buf).unwrap(), name: x_buffer_to_strings(reply.value::<u8>())[0].to_owned(),
} }
} }
} }
ewmh_get_property! {
request=GetWmName{
window: client_window,
property: _NET_WM_NAME,
xtype: UTF8_STRING
},
reply=GetWmNameReply,
cookie=GetWmNameCookie,
cookie_unchecked=GetWmNameCookieUnchecked
}
pub struct SetWmName {
window: xcb::x::Window,
data: Vec<u8>,
}
impl SetWmName {
pub fn new(connection: &Connection, window: xcb::x::Window, name: &str) -> SetWmName {
SetWmName {
window: window,
data: strings_to_x_buffer(vec![name]),
}
}
}
ewmh_set_property! {
request=SetWmName{
window: client_window,
property: _NET_WM_NAME,
xtype: UTF8_STRING
}
}
// }}} // }}}
// _NET_WM_VISIBLE_NAME, UTF8_STRING // _NET_WM_VISIBLE_NAME, UTF8_STRING
// {{{ // {{{
ewmh_get_window_request! { pub struct GetWmVisibleName(xcb::x::Window);
GetWmVisibleName, pub struct GetWmVisibleNameCookie(xcb::x::GetPropertyCookie);
_NET_WM_VISIBLE_NAME, pub struct GetWmVisibleNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
UTF8_STRING,
GetWmVisibleNameCooke,
GetWmVisibleNameCookieUnchecked,
GetWmVisibleNameReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWmVisibleNameReply { pub struct GetWmVisibleNameReply {
@ -58,31 +75,29 @@ pub struct GetWmVisibleNameReply {
impl From<xcb::x::GetPropertyReply> for GetWmVisibleNameReply { impl From<xcb::x::GetPropertyReply> for GetWmVisibleNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmVisibleNameReply { GetWmVisibleNameReply {
name: String::from_utf8(buf).unwrap(), name: x_buffer_to_strings(reply.value::<u8>())[0].to_owned(),
} }
} }
} }
ewmh_get_property! {
request=GetWmVisibleName{
window: root_window,
property: _NET_WM_VISIBLE_NAME,
xtype: UTF8_STRING
},
reply=GetWmVisibleNameReply,
cookie=GetWmVisibleNameCookie,
cookie_unchecked=GetWmVisibleNameCookieUnchecked
}
// }}} // }}}
// _NET_WM_ICON_NAME, UTF8_STRING // _NET_WM_ICON_NAME, UTF8_STRING
// {{{ // {{{
ewmh_get_window_request! { pub struct GetWmIconName;
GetWmIconName, pub struct GetWmIconNameCookie(xcb::x::GetPropertyCookie);
_NET_WM_ICON_NAME, pub struct GetWmIconNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
UTF8_STRING,
GetWmIconNameCooke,
GetWmIconNameCookieUnchecked,
GetWmIconNameReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWmIconNameReply { pub struct GetWmIconNameReply {
@ -91,31 +106,29 @@ pub struct GetWmIconNameReply {
impl From<xcb::x::GetPropertyReply> for GetWmIconNameReply { impl From<xcb::x::GetPropertyReply> for GetWmIconNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmIconNameReply { GetWmIconNameReply {
name: String::from_utf8(buf).unwrap(), name: x_buffer_to_strings(reply.value::<u8>())[0].to_owned(),
} }
} }
} }
ewmh_get_property! {
request=GetWmIconName{
window: root_window,
property: _NET_WM_ICON_NAME,
xtype: UTF8_STRING
},
reply=GetWmIconNameReply,
cookie=GetWmIconNameCookie,
cookie_unchecked=GetWmIconNameCookieUnchecked
}
// }}} // }}}
// _NET_WM_VISIBLE_ICON_NAME, UTF8_STRING // _NET_WM_VISIBLE_ICON_NAME, UTF8_STRING
// {{{ // {{{
ewmh_get_window_request! { pub struct GetWmVisibleIconName;
GetWmVisibleIconName, pub struct GetWmVisibleIconNameCookie(xcb::x::GetPropertyCookie);
_NET_WM_VISIBLE_ICON_NAME, pub struct GetWmVisibleIconNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
UTF8_STRING,
GetWmVisibleIconNameCooke,
GetWmVisibleIconNameCookieUnchecked,
GetWmVisibleIconNameReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWmVisibleIconNameReply { pub struct GetWmVisibleIconNameReply {
@ -124,31 +137,29 @@ pub struct GetWmVisibleIconNameReply {
impl From<xcb::x::GetPropertyReply> for GetWmVisibleIconNameReply { impl From<xcb::x::GetPropertyReply> for GetWmVisibleIconNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmVisibleIconNameReply { GetWmVisibleIconNameReply {
name: String::from_utf8(buf).unwrap(), name: x_buffer_to_strings(reply.value::<u8>())[0].to_owned(),
} }
} }
} }
ewmh_get_property! {
request=GetWmVisibleIconName{
window: root_window,
property: _NET_WM_VISIBLE_ICON_NAME,
xtype: UTF8_STRING
},
reply=GetWmVisibleIconNameReply,
cookie=GetWmVisibleIconNameCookie,
cookie_unchecked=GetWmVisibleIconNameCookieUnchecked
}
// }}} // }}}
// _NET_WM_DESKTOP, CARDINAL/32 // _NET_WM_DESKTOP, CARDINAL/32
// {{{ // {{{
ewmh_get_window_request! { pub struct GetWmDesktop;
GetWmDesktop, pub struct GetWmDesktopCookie(xcb::x::GetPropertyCookie);
_NET_WM_DESKTOP, pub struct GetWmDesktopCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
CARDINAL,
GetWmDesktopCooke,
GetWmDesktopCookieUnchecked,
GetWmDesktopReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWmDesktopReply { pub struct GetWmDesktopReply {
@ -162,11 +173,92 @@ impl From<xcb::x::GetPropertyReply> for GetWmDesktopReply {
} }
} }
} }
ewmh_get_property! {
request=GetWmDesktop{
window: root_window,
property: _NET_WM_DESKTOP,
xtype: ATOM_CARDINAL
},
reply=GetWmDesktopReply,
cookie=GetWmDesktopCookie,
cookie_unchecked=GetWmDesktopCookieUnchecked
}
pub struct SetWmDesktop {
window: xcb::x::Window,
data: Vec<u32>,
}
impl SetWmDesktop {
pub fn new(window: xcb::x::Window, desktop: u32) -> SetWmDesktop {
SetWmDesktop {
window: window,
data: vec![desktop],
}
}
}
ewmh_set_property! {
request=SetWmDesktop {
window: client_window,
property: _NET_WM_DESKTOP,
xtype: ATOM_CARDINAL
}
}
pub struct SendWmDesktop {
client_message: xcb::x::ClientMessageEvent,
}
impl SendWmDesktop {
pub fn new(connection: &Connection, desktop: u32, source_indication: u32) -> SendWmDesktop {
SendWmDesktop {
client_message: xcb::x::ClientMessageEvent::new(
connection.con.get_setup().roots().next().unwrap().root(),
connection.atoms._NET_WM_DESKTOP,
xcb::x::ClientMessageData::Data32([desktop, source_indication, 0x00, 0x00, 0x00]),
),
}
}
}
ewmh_client_message! {
request=SendWmDesktop{destination: root_window}
}
// }}} // }}}
// _NET_WM_WINDOW_TYPE, ATOM[]/32 // _NET_WM_WINDOW_TYPE, ATOM[]/32
// {{{ // {{{
pub struct GetWmWindowType;
pub struct GetWmWindowTypeCookie(xcb::x::GetPropertyCookie);
pub struct GetWmWindowTypeCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
#[derive(Debug)]
pub struct GetWmWindowTypeReply {
pub window_types: Vec<xcb::x::Atom>,
}
impl From<xcb::x::GetPropertyReply> for GetWmWindowTypeReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetWmWindowTypeReply {
window_types: reply.value::<xcb::x::Atom>().into(),
}
}
}
ewmh_get_property! {
request=GetWmWindowType{
window: root_window,
property: _NET_WM_WINDOW_TYPE,
xtype: ATOM_ATOM
},
reply=GetWmWindowTypeReply,
cookie=GetWmWindowTypeCookie,
cookie_unchecked=GetWmWindowTypeCookieUnchecked
}
pub struct SetWmWindowType { pub struct SetWmWindowType {
window: xcb::x::Window, window: xcb::x::Window,
data: Vec<xcb::x::Atom>, data: Vec<xcb::x::Atom>,
@ -181,31 +273,11 @@ impl SetWmWindowType {
} }
} }
ewmh_set_window_request! { ewmh_set_property! {
SetWmWindowType, request=SetWmWindowType{
_NET_WM_WINDOW_TYPE, window: client_window,
{ xcb::x::ATOM_ATOM } property: _NET_WM_WINDOW_TYPE,
} xtype: ATOM_ATOM
ewmh_get_window_request! {
GetWmWindowType,
_NET_WM_WINDOW_TYPE,
ATOM,
GetWmWindowTypeCooke,
GetWmWindowTypeCookieUnchecked,
GetWmWindowTypeReply
}
#[derive(Debug)]
pub struct GetWmWindowTypeReply {
pub types: Vec<xcb::x::Atom>,
}
impl From<xcb::x::GetPropertyReply> for GetWmWindowTypeReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetWmWindowTypeReply {
types: reply.value::<xcb::x::Atom>().into(),
}
} }
} }
@ -214,46 +286,65 @@ impl From<xcb::x::GetPropertyReply> for GetWmWindowTypeReply {
// _NET_WM_STATE, ATOM[]/32 // _NET_WM_STATE, ATOM[]/32
// {{{ // {{{
pub struct SetWmState { pub struct GetWmState(xcb::x::Window);
window: xcb::x::Window, pub struct GetWmStateCookie(xcb::x::GetPropertyCookie);
data: Vec<xcb::x::Atom>, pub struct GetWmStateCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
}
impl SetWmState {
pub fn new(window: xcb::x::Window, types: Vec<xcb::x::Atom>) -> SetWmState {
SetWmState {
window,
data: types,
}
}
}
ewmh_set_window_request! {
SetWmState,
_NET_WM_STATE,
{ xcb::x::ATOM_ATOM }
}
ewmh_get_window_request! {
GetWmState,
_NET_WM_STATE,
ATOM,
GetWmStateCooke,
GetWmStateCookieUnchecked,
GetWmStateReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWmStateReply { pub struct GetWmStateReply {
pub types: Vec<xcb::x::Atom>, pub states: Vec<xcb::x::Atom>,
} }
impl From<xcb::x::GetPropertyReply> for GetWmStateReply { impl From<xcb::x::GetPropertyReply> for GetWmStateReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetWmStateReply { GetWmStateReply {
types: reply.value::<xcb::x::Atom>().into(), states: reply.value::<xcb::x::Atom>().into(),
} }
} }
} }
ewmh_get_property! {
request=GetWmState{
window: client_window,
property: _NET_WM_STATE,
xtype: ATOM_ATOM
},
reply=GetWmStateReply,
cookie=GetWmStateCookie,
cookie_unchecked=GetWmStateCookieUnchecked
}
pub struct SetWmState {
client_message: xcb::x::ClientMessageEvent,
}
impl SetWmState {
pub fn new(
connection: &Connection,
window: xcb::x::Window,
action: xcb::x::PropMode,
states: [xcb::x::Atom; 2],
source_indication: u32,
) -> SetWmState {
let data = [
unsafe { std::mem::transmute::<_, u32>(action) },
states[0].resource_id(),
states[1].resource_id(),
source_indication,
0x00,
];
SetWmState {
client_message: xcb::x::ClientMessageEvent::new(
window,
connection.atoms._NET_WM_DESKTOP,
xcb::x::ClientMessageData::Data32(data),
),
}
}
}
ewmh_client_message! {
request=SetWmState{destination: root_window}
}
// }}} // }}}

View file

@ -49,11 +49,11 @@ macro_rules! _get_property_request {
} }
}; };
($window:ident, $property:ident, UTF8_STRING) => { (client_window, $property:ident, UTF8_STRING) => {
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty { fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
xcb::x::GetProperty { xcb::x::GetProperty {
delete: false, delete: false,
window: $window, window: self.0,
property: con.atoms.$property, property: con.atoms.$property,
r#type: con.atoms.UTF8_STRING, r#type: con.atoms.UTF8_STRING,
long_offset: 0, long_offset: 0,
@ -62,11 +62,11 @@ macro_rules! _get_property_request {
} }
}; };
($window:ident, $property:ident, $xtype:ident) => { (client_window, $property:ident, $xtype:ident) => {
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty { fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
xcb::x::GetProperty { xcb::x::GetProperty {
delete: false, delete: false,
window: $window, window: self.0,
property: con.atoms.$property, property: con.atoms.$property,
r#type: xcb::x::$xtype, r#type: xcb::x::$xtype,
long_offset: 0, long_offset: 0,
@ -126,7 +126,7 @@ macro_rules! _set_property_base {
}; };
(root_window, $property:ident, $xtype:ident) => { (root_window, $property:ident, $xtype:ident) => {
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u8> { fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
xcb::x::ChangeProperty { xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace, mode: xcb::x::PropMode::Replace,
window: con.con.get_setup().roots().next().unwrap().root(), window: con.con.get_setup().roots().next().unwrap().root(),
@ -137,11 +137,11 @@ macro_rules! _set_property_base {
} }
}; };
($window:ident, $property:ident, UTF8_STRING) => { (client_window, $property:ident, UTF8_STRING) => {
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u8> { fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u8> {
xcb::x::ChangeProperty { xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace, mode: xcb::x::PropMode::Replace,
window: $window, window: self.window,
property: con.atoms.$property, property: con.atoms.$property,
r#type: con.atoms.UTF8_STRING, r#type: con.atoms.UTF8_STRING,
data: &self.data, data: &self.data,
@ -149,13 +149,25 @@ macro_rules! _set_property_base {
} }
}; };
($window:ident, $property:ident, $xtype:ident) => { (client_window, $property:ident, ATOM_CARDINAL) => {
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u8> { fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
xcb::x::ChangeProperty { xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace, mode: xcb::x::PropMode::Replace,
window: $window, window: self.window,
property: con.atoms.$property, property: con.atoms.$property,
r#type: xcb::x::$xtype, r#type: xcb::x::ATOM_CARDINAL,
data: &self.data,
}
}
};
(client_window, $property:ident, ATOM_ATOM) => {
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, xcb::x::Atom> {
xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace,
window: self.window,
property: con.atoms.$property,
r#type: xcb::x::ATOM_ATOM,
data: &self.data, data: &self.data,
} }
} }
@ -166,14 +178,13 @@ macro_rules! ewmh_set_property {
(request=$request:ident{ (request=$request:ident{
window: $window:ident, window: $window:ident,
property: $property:ident, property: $property:ident,
xtype: $xtype: ident xtype: UTF8_STRING
}) => { }) => {
impl<'a> EwmhRequest<'a> for $request { impl<'a> EwmhRequest<'a> for $request {
// TODO fixing to u8 is probably not flexible enough
type XcbRequest = xcb::x::ChangeProperty<'a, u8>; type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
type EwmhCookie = xcb::VoidCookie; type EwmhCookie = xcb::VoidCookie;
_set_property_base! {$window, $property, $xtype} _set_property_base! {$window, $property, UTF8_STRING}
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie { fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
xcb_cookie xcb_cookie
@ -183,7 +194,53 @@ macro_rules! ewmh_set_property {
impl<'a> EwmhVoidRequestChecked<'a> for $request { impl<'a> EwmhVoidRequestChecked<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, u8>; type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
_set_property_base! {$window, $property, $xtype} _set_property_base! {$window, $property, UTF8_STRING}
}
};
(request=$request:ident{
window: $window:ident,
property: $property:ident,
xtype: ATOM_CARDINAL
}) => {
impl<'a> EwmhRequest<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, u32>;
type EwmhCookie = xcb::VoidCookie;
_set_property_base! {$window, $property, ATOM_CARDINAL}
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
xcb_cookie
}
}
impl<'a> EwmhVoidRequestChecked<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, u32>;
_set_property_base! {$window, $property, ATOM_CARDINAL}
}
};
(request=$request:ident{
window: $window:ident,
property: $property:ident,
xtype: ATOM_ATOM
}) => {
impl<'a> EwmhRequest<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, xcb::x::Atom>;
type EwmhCookie = xcb::VoidCookie;
_set_property_base! {$window, $property, ATOM_ATOM }
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
xcb_cookie
}
}
impl<'a> EwmhVoidRequestChecked<'a> for $request {
type XcbRequest = xcb::x::ChangeProperty<'a, xcb::x::Atom>;
_set_property_base! {$window, $property, ATOM_ATOM }
} }
}; };
} }

View file

@ -17,8 +17,10 @@
#[macro_use] #[macro_use]
mod macros; mod macros;
mod test_props; pub(crate) mod util;
pub use test_props::net_desktop_names::*; mod root_props;
pub use test_props::net_showing_desktop::*; pub use root_props::*;
pub use test_props::net_supported::*;
mod application_props;
pub use application_props::*;

View file

@ -4,19 +4,17 @@
use xcb::{Xid, XidNew}; use xcb::{Xid, XidNew};
use crate::ewmh::connection::Connection; use crate::ewmh::proto::util::{strings_to_x_buffer, x_buffer_to_strings};
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData}; use crate::ewmh::traits::*;
use crate::ewmh::Connection;
// _NET_SUPPORTED, ATOM[]/32 // _NET_SUPPORTED, ATOM[]/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetSupported;
GetSupported,
_NET_SUPPORTED, pub struct GetSupportedCookie(xcb::x::GetPropertyCookie);
ATOM_ATOM,
GetSupportedCookie, pub struct GetSupportedCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetSupportedCookieUnchecked,
GetSupportedReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetSupportedReply { pub struct GetSupportedReply {
@ -30,18 +28,26 @@ impl From<xcb::x::GetPropertyReply> for GetSupportedReply {
} }
} }
} }
ewmh_get_property! {
request=GetSupported{
window: root_window,
property: _NET_SUPPORTED,
xtype: ATOM_ATOM
},
reply=GetSupportedReply,
cookie=GetSupportedCookie,
cookie_unchecked=GetSupportedCookieUnchecked
}
// }}} // }}}
// _NET_CLIENT_LIST, WINDOW[]/32 // _NET_CLIENT_LIST, WINDOW[]/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetClientList;
GetClientList,
_NET_CLIENT_LIST, pub struct GetClientListCookie(xcb::x::GetPropertyCookie);
ATOM_WINDOW,
GetClientListCookie, pub struct GetClientListCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetClientListCookieUnchecked,
GetClientListReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetClientListReply { pub struct GetClientListReply {
@ -55,18 +61,26 @@ impl From<xcb::x::GetPropertyReply> for GetClientListReply {
} }
} }
} }
ewmh_get_property! {
request=GetClientList{
window: root_window,
property: _NET_CLIENT_LIST,
xtype: ATOM_WINDOW
},
reply=GetClientListReply,
cookie=GetClientListCookie,
cookie_unchecked=GetClientListCookieUnchecked
}
// }}} // }}}
// _NET_CLIENT_LIST_STACKING, WINDOW[]/32 // _NET_CLIENT_LIST_STACKING, WINDOW[]/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetClientListStacking;
GetClientListStacking,
_NET_CLIENT_LIST_STACKING, pub struct GetClientListStackingCookie(xcb::x::GetPropertyCookie);
ATOM_WINDOW,
GetClientListStackingCookie, pub struct GetClientListStackingCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetClientListStackingCookieUnchecked,
GetClientListStackingReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetClientListStackingReply { pub struct GetClientListStackingReply {
@ -80,18 +94,26 @@ impl From<xcb::x::GetPropertyReply> for GetClientListStackingReply {
} }
} }
} }
ewmh_get_property! {
request=GetClientListStacking{
window: root_window,
property: _NET_CLIENT_LIST_STACKING,
xtype: ATOM_WINDOW
},
reply=GetClientListStackingReply,
cookie=GetClientListStackingCookie,
cookie_unchecked=GetClientListStackingCookieUnchecked
}
// }}} // }}}
// _NET_NUMBER_OF_DESKTOPS, CARDINAL/32 // _NET_NUMBER_OF_DESKTOPS, CARDINAL/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetNumberOfDesktops;
GetNumberOfDesktops,
_NET_NUMBER_OF_DESKTOPS, pub struct GetNumberOfDesktopsCookie(xcb::x::GetPropertyCookie);
ATOM_CARDINAL,
GetNumberOfDesktopsCookie, pub struct GetNumberOfDesktopsCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetNumberOfDesktopsCookieUnchecked,
GetNumberOfDesktopsReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetNumberOfDesktopsReply { pub struct GetNumberOfDesktopsReply {
@ -106,34 +128,45 @@ impl From<xcb::x::GetPropertyReply> for GetNumberOfDesktopsReply {
} }
} }
ewmh_get_property! {
request=GetNumberOfDesktops{
window: root_window,
property: _NET_NUMBER_OF_DESKTOPS,
xtype: ATOM_CARDINAL
},
reply=GetNumberOfDesktopsReply,
cookie=GetNumberOfDesktopsCookie,
cookie_unchecked=GetNumberOfDesktopsCookieUnchecked
}
pub struct SetNumberOfDesktops { pub struct SetNumberOfDesktops {
data: [u32; 1], client_message: xcb::x::ClientMessageEvent,
} }
impl SetNumberOfDesktops { impl SetNumberOfDesktops {
pub fn new(desktops: u32) -> SetNumberOfDesktops { pub fn new(connection: &Connection, desktops: u32) -> SetNumberOfDesktops {
SetNumberOfDesktops { data: [desktops] } SetNumberOfDesktops {
client_message: xcb::x::ClientMessageEvent::new(
connection.con.get_setup().roots().next().unwrap().root(),
connection.atoms._NET_NUMBER_OF_DESKTOPS,
xcb::x::ClientMessageData::Data32([desktops, 0x00, 0x00, 0x00, 0x00]),
),
}
} }
} }
ewmh_set_root_request! { ewmh_client_message! {
SetNumberOfDesktops, request=SetNumberOfDesktops{destination: root_window}
_NET_NUMBER_OF_DESKTOPS,
ATOM_CARDINAL
} }
// }}} // }}}
// _NET_DESKTOP_GEOMETRY width, height, CARDINAL[2]/32 // _NET_DESKTOP_GEOMETRY width, height, CARDINAL[2]/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetDesktopGeometry;
GetDesktopGeometry,
_NET_DESKTOP_GEOMETRY, pub struct GetDesktopGeometryCookie(xcb::x::GetPropertyCookie);
ATOM_CARDINAL,
GetDesktopGeometryCookie, pub struct GetDesktopGeometryCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetDesktopGeometryCookieUnchecked,
GetDesktopGeometryReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetDesktopGeometryReply { pub struct GetDesktopGeometryReply {
@ -145,41 +178,51 @@ impl From<xcb::x::GetPropertyReply> for GetDesktopGeometryReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetDesktopGeometryReply { GetDesktopGeometryReply {
width: reply.value::<u32>()[0], width: reply.value::<u32>()[0],
height: reply.value::<u32>()[0], height: reply.value::<u32>()[1],
} }
} }
} }
ewmh_get_property! {
request=GetDesktopGeometry{
window: root_window,
property: _NET_DESKTOP_GEOMETRY,
xtype: ATOM_CARDINAL
},
reply=GetDesktopGeometryReply,
cookie=GetDesktopGeometryCookie,
cookie_unchecked=GetDesktopGeometryCookieUnchecked
}
pub struct SetDesktopGeometry { pub struct SetDesktopGeometry {
data: [u32; 2], client_message: xcb::x::ClientMessageEvent,
} }
impl SetDesktopGeometry { impl SetDesktopGeometry {
pub fn new(width: u32, height: u32) -> SetDesktopGeometry { pub fn new(connection: &Connection, width: u32, height: u32) -> SetDesktopGeometry {
SetDesktopGeometry { SetDesktopGeometry {
data: [width, height], client_message: xcb::x::ClientMessageEvent::new(
connection.con.get_setup().roots().next().unwrap().root(),
connection.atoms._NET_DESKTOP_GEOMETRY,
xcb::x::ClientMessageData::Data32([width, height, 0x00, 0x00, 0x00]),
),
} }
} }
} }
ewmh_set_root_request! { ewmh_client_message! {
SetDesktopGeometry, request=SetDesktopGeometry{destination: root_window}
_NET_DESKTOP_GEOMETRY,
ATOM_CARDINAL
} }
// }}} // }}}
// _NET_DESTKOP_VIEWPORT x, y, CARDINAL[][2]/32 // _NET_DESTKOP_VIEWPORT x, y, CARDINAL[][2]/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetDesktopViewport;
GetDesktopViewport,
_NET_DESKTOP_VIEWPORT, pub struct GetDesktopViewportCookie(xcb::x::GetPropertyCookie);
ATOM_CARDINAL,
GetDesktopViewportCookie, pub struct GetDesktopViewportCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetDesktopViewportCookieUnchecked,
GetDesktopViewportReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetDesktopViewportReply { pub struct GetDesktopViewportReply {
@ -196,34 +239,45 @@ impl From<xcb::x::GetPropertyReply> for GetDesktopViewportReply {
} }
} }
ewmh_get_property! {
request=GetDesktopViewport{
window: root_window,
property: _NET_DESKTOP_VIEWPORT,
xtype: ATOM_CARDINAL
},
reply=GetDesktopViewportReply,
cookie=GetDesktopViewportCookie,
cookie_unchecked=GetDesktopViewportCookieUnchecked
}
pub struct SetDesktopViewport { pub struct SetDesktopViewport {
data: [u32; 2], client_message: xcb::x::ClientMessageEvent,
} }
impl SetDesktopViewport { impl SetDesktopViewport {
pub fn new(x: u32, y: u32) -> SetDesktopViewport { pub fn new(connection: &Connection, x: u32, y: u32) -> SetDesktopViewport {
SetDesktopViewport { data: [x, y] } SetDesktopViewport {
client_message: xcb::x::ClientMessageEvent::new(
connection.con.get_setup().roots().next().unwrap().root(),
connection.atoms._NET_DESKTOP_VIEWPORT,
xcb::x::ClientMessageData::Data32([x, y, 0x00, 0x00, 0x00]),
),
}
} }
} }
ewmh_set_root_request! { ewmh_client_message! {
SetDesktopViewport, request=SetDesktopViewport{destination: root_window}
_NET_DESKTOP_VIEWPORT,
ATOM_CARDINAL
} }
// }}} // }}}
// _NET_CURRENT_DESKTOP desktop, CARDINAL/32 // _NET_CURRENT_DESKTOP desktop, CARDINAL/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetCurrentDesktop;
GetCurrentDesktop,
_NET_CURRENT_DESKTOP, pub struct GetCurrentDesktopCookie(xcb::x::GetPropertyCookie);
ATOM_CARDINAL,
GetCurrentDesktopCookie, pub struct GetCurrentDesktopCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetCurrentDesktopCookieUnchecked,
GetCurrentDesktopReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetCurrentDesktopReply { pub struct GetCurrentDesktopReply {
@ -238,115 +292,123 @@ impl From<xcb::x::GetPropertyReply> for GetCurrentDesktopReply {
} }
} }
ewmh_get_property! {
request=GetCurrentDesktop{
window: root_window,
property: _NET_CURRENT_DESKTOP,
xtype: ATOM_CARDINAL
},
reply=GetCurrentDesktopReply,
cookie=GetCurrentDesktopCookie,
cookie_unchecked=GetCurrentDesktopCookieUnchecked
}
pub struct SetCurrentDesktop { pub struct SetCurrentDesktop {
data: [u32; 2], client_message: xcb::x::ClientMessageEvent,
} }
impl SetCurrentDesktop { impl SetCurrentDesktop {
pub fn new(new_index: u32, timestamp: u32) -> SetCurrentDesktop { pub fn new(connection: &Connection, desktop: u32) -> SetCurrentDesktop {
SetCurrentDesktop { SetCurrentDesktop {
data: [new_index, timestamp], client_message: xcb::x::ClientMessageEvent::new(
connection.con.get_setup().roots().next().unwrap().root(),
connection.atoms._NET_CURRENT_DESKTOP,
xcb::x::ClientMessageData::Data32([desktop, 0x00, 0x00, 0x00, 0x00]),
),
} }
} }
} }
ewmh_set_root_request! { ewmh_client_message! {
SetCurrentDesktop, request=SetCurrentDesktop{destination: root_window}
_NET_CURRENT_DESKTOP,
ATOM_CARDINAL
} }
// }}} // }}}
// _NET_DESKTOP_NAMES desktop, UTF8_STRING[] // _NET_DESKTOP_NAMES desktop, UTF8_STRING[]
// {{{ // {{{
ewmh_get_root_request! { pub struct GetDesktopNames;
GetDesktopNames,
_NET_DESKTOP_NAMES, pub struct GetDesktopNamesCookie(xcb::x::GetPropertyCookie);
UTF8_STRING,
GetDesktopNamesCookie, pub struct GetDesktopNamesCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetDesktopNamesCookieUnchecked,
GetDesktopNamesReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetDesktopNamesReply { pub struct GetDesktopNamesReply {
pub desktop_names: Vec<String>, pub names: Vec<String>,
} }
impl From<xcb::x::GetPropertyReply> for GetDesktopNamesReply { impl From<xcb::x::GetPropertyReply> for GetDesktopNamesReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut vals = vec![];
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
} else if !buf.is_empty() {
vals.push(String::from_utf8(buf.clone()).unwrap());
buf.clear();
} else {
buf.clear();
}
}
GetDesktopNamesReply { GetDesktopNamesReply {
desktop_names: vals, names: x_buffer_to_strings(reply.value::<u8>()),
} }
} }
} }
ewmh_get_property! {
request=GetDesktopNames{
window: root_window,
property: _NET_DESKTOP_NAMES,
xtype: UTF8_STRING
},
reply=GetDesktopNamesReply,
cookie=GetDesktopNamesCookie,
cookie_unchecked=GetDesktopNamesCookieUnchecked
}
pub struct SetDesktopNames { pub struct SetDesktopNames {
data: Vec<u8>, data: Vec<u8>,
} }
impl SetDesktopNames { impl SetDesktopNames {
pub fn new(new_names: Vec<&str>) -> SetDesktopNames { pub fn new(names: Vec<&str>) -> SetDesktopNames {
let mut data: Vec<u8> = vec![]; SetDesktopNames {
data: strings_to_x_buffer(names),
// flatten `new_names` into a continuous array of bytes
for name in new_names {
let mut bname = name.as_bytes().to_owned();
bname.push(0b00);
data.extend(bname)
} }
SetDesktopNames { data }
} }
} }
ewmh_set_root_request! { ewmh_set_property! {
SetDesktopNames, request=SetDesktopNames{
_NET_DESKTOP_NAMES, window: root_window,
UTF8_STRING property: _NET_DESKTOP_NAMES,
xtype: UTF8_STRING
}
} }
// }}} // }}}
// _NET_ACTIVE_WINDOW, WINDOW/32 // _NET_ACTIVE_WINDOW, WINDOW/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetActiveWindow;
GetActiveWindow,
_NET_ACTIVE_WINDOW, pub struct GetActiveWindowCookie(xcb::x::GetPropertyCookie);
ATOM_WINDOW,
GetActiveWindowCookie, pub struct GetActiveWindowCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetActiveWindowCookieUnchecked,
GetActiveWindowReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetActiveWindowReply { pub struct GetActiveWindowReply {
pub value: xcb::x::Window, pub window: xcb::x::Window,
} }
impl From<xcb::x::GetPropertyReply> for GetActiveWindowReply { impl From<xcb::x::GetPropertyReply> for GetActiveWindowReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetActiveWindowReply { GetActiveWindowReply {
value: reply.value::<xcb::x::Window>()[0], window: unsafe { xcb::x::Window::new(reply.value::<u32>()[0]) },
} }
} }
} }
ewmh_get_property! {
request=GetActiveWindow{
window: root_window,
property: _NET_ACTIVE_WINDOW,
xtype: ATOM_WINDOW
},
reply=GetActiveWindowReply,
cookie=GetActiveWindowCookie,
cookie_unchecked=GetActiveWindowCookieUnchecked
}
pub struct SetActiveWindow { pub struct SetActiveWindow {
client_message: xcb::x::ClientMessageEvent, client_message: xcb::x::ClientMessageEvent,
} }
@ -359,67 +421,35 @@ impl SetActiveWindow {
timestamp: u32, timestamp: u32,
requestor_window: Option<xcb::x::Window>, requestor_window: Option<xcb::x::Window>,
) -> SetActiveWindow { ) -> SetActiveWindow {
let data = [ SetActiveWindow {
source_indication, client_message: xcb::x::ClientMessageEvent::new(
timestamp, window,
requestor_window.map_or(0, |w| w.resource_id()), connection.atoms._NET_ACTIVE_WINDOW,
0x00, xcb::x::ClientMessageData::Data32([
0x00, source_indication,
]; timestamp,
requestor_window.map_or(0, |w| w.resource_id()),
let client_message = xcb::x::ClientMessageEvent::new( 0x00,
window, 0x00,
connection.atoms._NET_ACTIVE_WINDOW, ]),
xcb::x::ClientMessageData::Data32(data),
);
SetActiveWindow { client_message }
}
}
impl<'a> EwmhRequest<'a> for SetActiveWindow {
type Cookie = xcb::VoidCookieChecked;
type CookieUnchecked = xcb::VoidCookie;
fn send_request(&self, con: &Connection) -> Self::Cookie {
con.con.send_request_checked(&self.get_request_data(con))
}
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
con.con.send_request(&self.get_request_data(con))
}
}
impl<'a> EwmhRequestData<'a> for SetActiveWindow {
type Request = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
fn get_request_data(
&'a self,
con: &Connection,
) -> xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent> {
xcb::x::SendEvent {
propagate: false,
destination: xcb::x::SendEventDest::Window(
con.con.get_setup().roots().next().unwrap().root(),
), ),
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
event: &self.client_message,
} }
} }
} }
ewmh_client_message! {
request=SetActiveWindow{destination: root_window}
}
// }}} // }}}
// _NET_WORKAREA, x, y, width, height, CARDINAL[][4]/32 // // _NET_WORKAREA, x, y, width, height, CARDINAL[][4]/32
// {{{ // {{{
ewmh_get_root_request! {
GetWorkarea, pub struct GetWorkarea;
_NET_WORKAREA,
ATOM_CARDINAL, pub struct GetWorkareaCookie(xcb::x::GetPropertyCookie);
GetWorkareaCookie,
GetWorkareaCookieUnchecked, pub struct GetWorkareaCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetWorkareaReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetWorkareaReply { pub struct GetWorkareaReply {
@ -439,18 +469,27 @@ impl From<xcb::x::GetPropertyReply> for GetWorkareaReply {
} }
} }
} }
ewmh_get_property! {
request=GetWorkarea{
window: root_window,
property: _NET_WORKAREA,
xtype: ATOM_CARDINAL
},
reply=GetWorkareaReply,
cookie=GetWorkareaCookie,
cookie_unchecked=GetWorkareaCookieUnchecked
}
// }}} // }}}
// _NET_SUPPORTING_WM_CHECK, WINDOW/32 // // _NET_SUPPORTING_WM_CHECK, WINDOW/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetSupportingWmCheck;
GetSupportingWmCheck,
_NET_SUPPORTING_WM_CHECK, pub struct GetSupportingWmCheckCookie(xcb::x::GetPropertyCookie);
ATOM_WINDOW,
GetSupportingWmCheckCookie, pub struct GetSupportingWmCheckCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetSupportingWmCheckCookieUnchecked,
GetSupportingWmCheckReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetSupportingWmCheckReply { pub struct GetSupportingWmCheckReply {
@ -468,14 +507,11 @@ impl From<xcb::x::GetPropertyReply> for GetSupportingWmCheckReply {
// _NET_VIRTUAL_ROOTS, WINDOW/32 // _NET_VIRTUAL_ROOTS, WINDOW/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetVirtualRoots;
GetVirtualRoots,
_NET_VIRTUAL_ROOTS, pub struct GetVirtualRootsCookie(xcb::x::GetPropertyCookie);
ATOM_WINDOW,
GetVirtualRootsCookie, pub struct GetVirtualRootsCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetVirtualRootsCookieUnchecked,
GetVirtualRootsReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetVirtualRootsReply { pub struct GetVirtualRootsReply {
@ -489,30 +525,38 @@ impl From<xcb::x::GetPropertyReply> for GetVirtualRootsReply {
} }
} }
} }
ewmh_get_property! {
request=GetVirtualRoots{
window: root_window,
property: _NET_VIRTUAL_ROOTS,
xtype: ATOM_WINDOW
},
reply=GetVirtualRootsReply,
cookie=GetVirtualRootsCookie,
cookie_unchecked=GetVirtualRootsCookieUnchecked
}
// }}} // }}}
// _NET_DESKTOP_LAYOUT, orientation, columns, rows, starting_corner, CARDINAL[4]/32 // _NET_DESKTOP_LAYOUT, orientation, columns, rows, starting_corner, CARDINAL[4]/32
// {{{ // {{{
ewmh_get_root_request! { pub struct DesktopLayout;
GetDesktopLayout,
_NET_DESKTOP_LAYOUT, pub struct DesktopLayoutCookie(xcb::x::GetPropertyCookie);
ATOM_CARDINAL,
GetDesktopLayoutCookie, pub struct DesktopLayoutCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetDesktopLayoutCookieUnchecked,
GetDesktopLayoutReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetDesktopLayoutReply { pub struct DesktopLayoutReply {
orientation: u32, pub orientation: u32,
columns: u32, pub columns: u32,
rows: u32, pub rows: u32,
starting_corner: u32, pub starting_corner: u32,
} }
impl From<xcb::x::GetPropertyReply> for GetDesktopLayoutReply { impl From<xcb::x::GetPropertyReply> for DesktopLayoutReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetDesktopLayoutReply { DesktopLayoutReply {
orientation: reply.value::<u32>()[0], orientation: reply.value::<u32>()[0],
columns: reply.value::<u32>()[1], columns: reply.value::<u32>()[1],
rows: reply.value::<u32>()[2], rows: reply.value::<u32>()[2],
@ -520,89 +564,76 @@ impl From<xcb::x::GetPropertyReply> for GetDesktopLayoutReply {
} }
} }
} }
ewmh_get_property! {
request=DesktopLayout{
window: root_window,
property: _NET_DESKTOP_LAYOUT,
xtype: ATOM_CARDINAL
},
reply=DesktopLayoutReply,
cookie=DesktopLayoutCookie,
cookie_unchecked=DesktopLayoutCookieUnchecked
}
// }}} // }}}
// _NET_SHOWING_DESKTOP desktop, CARDINAL/32 // _NET_SHOWING_DESKTOP desktop, CARDINAL/32
// {{{ // {{{
ewmh_get_root_request! { pub struct GetShowingDesktop;
GetShowingDesktop,
_NET_SHOWING_DESKTOP, pub struct GetShowingDesktopCookie(xcb::x::GetPropertyCookie);
ATOM_CARDINAL,
GetShowingDesktopCookie, pub struct GetShowingDesktopCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
GetShowingDesktopCookieUnchecked,
GetShowingDesktopReply
}
#[derive(Debug)] #[derive(Debug)]
pub struct GetShowingDesktopReply { pub struct GetShowingDesktopReply {
showing_desktop: bool, pub is_showing_desktop: bool,
} }
impl From<xcb::x::GetPropertyReply> for GetShowingDesktopReply { impl From<xcb::x::GetPropertyReply> for GetShowingDesktopReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self { fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetShowingDesktopReply { GetShowingDesktopReply {
showing_desktop: match reply.value::<u32>()[0] { is_showing_desktop: if reply.value::<u32>()[0] == 1 {
0 => false, true
1 => true, } else {
_ => unreachable!(), false
}, },
} }
} }
} }
ewmh_get_property! {
request=GetShowingDesktop{
window: root_window,
property: _NET_SHOWING_DESKTOP,
xtype: ATOM_CARDINAL
},
reply=GetShowingDesktopReply,
cookie=GetShowingDesktopCookie,
cookie_unchecked=GetShowingDesktopCookieUnchecked
}
pub struct SetShowingDesktop { pub struct SetShowingDesktop {
client_message: xcb::x::ClientMessageEvent, client_message: xcb::x::ClientMessageEvent,
} }
impl SetShowingDesktop { impl SetShowingDesktop {
pub fn new(connection: &Connection, show_desktop: bool) -> SetShowingDesktop { pub fn new(connection: &Connection, show_desktop: bool) -> SetShowingDesktop {
let data = match show_desktop { let data = if show_desktop { 1 } else { 0 };
false => 0 as u32,
true => 1 as u32,
};
let client_message = xcb::x::ClientMessageEvent::new( SetShowingDesktop {
connection.con.get_setup().roots().next().unwrap().root(), client_message: xcb::x::ClientMessageEvent::new(
connection.atoms._NET_SHOWING_DESKTOP, connection.con.get_setup().roots().next().unwrap().root(),
xcb::x::ClientMessageData::Data32([data, 0x00, 0x00, 0x00, 0x00]), connection.atoms._NET_SHOWING_DESKTOP,
); xcb::x::ClientMessageData::Data32([data, 0x00, 0x00, 0x00, 0x00]),
SetShowingDesktop { client_message }
}
}
impl<'a> EwmhRequest<'a> for SetShowingDesktop {
type Cookie = xcb::VoidCookieChecked;
type CookieUnchecked = xcb::VoidCookie;
fn send_request(&self, con: &Connection) -> Self::Cookie {
con.con.send_request_checked(&self.get_request_data(con))
}
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
con.con.send_request(&self.get_request_data(con))
}
}
impl<'a> EwmhRequestData<'a> for SetShowingDesktop {
type Request = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
fn get_request_data(
&'a self,
con: &Connection,
) -> xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent> {
xcb::x::SendEvent {
propagate: false,
destination: xcb::x::SendEventDest::Window(
con.con.get_setup().roots().next().unwrap().root(),
), ),
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
event: &self.client_message,
} }
} }
} }
ewmh_client_message! {
request=SetShowingDesktop{destination: root_window}
}
// }}} // }}}
// _NET_CLOSE_WINDOW // _NET_CLOSE_WINDOW
@ -618,72 +649,41 @@ impl CloseWindow {
source_indication: u32, source_indication: u32,
timestamp: u32, timestamp: u32,
) -> CloseWindow { ) -> CloseWindow {
let data = [timestamp, source_indication, 0x00, 0x00, 0x00]; CloseWindow {
client_message: xcb::x::ClientMessageEvent::new(
let client_message = xcb::x::ClientMessageEvent::new( window,
window, connection.atoms._NET_CLOSE_WINDOW,
connection.atoms._NET_CLOSE_WINDOW, xcb::x::ClientMessageData::Data32([timestamp, source_indication, 0x00, 0x00, 0x00]),
xcb::x::ClientMessageData::Data32(data),
);
CloseWindow { client_message }
}
}
impl<'a> EwmhRequest<'a> for CloseWindow {
type Cookie = xcb::VoidCookieChecked;
type CookieUnchecked = xcb::VoidCookie;
fn send_request(&self, con: &Connection) -> Self::Cookie {
con.con.send_request_checked(&self.get_request_data(con))
}
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
con.con.send_request(&self.get_request_data(con))
}
}
impl<'a> EwmhRequestData<'a> for CloseWindow {
type Request = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
fn get_request_data(
&'a self,
con: &Connection,
) -> xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent> {
xcb::x::SendEvent {
propagate: false,
destination: xcb::x::SendEventDest::Window(
con.con.get_setup().roots().next().unwrap().root(),
), ),
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
event: &self.client_message,
} }
} }
} }
// }}}
// _NET_MOVERESIZE_WINDOW ewmh_client_message! {
// {{{ request=CloseWindow{destination: root_window}
}
// TODO
// }}}
// _NET_WM_MOVERESIZE
// {{{
// TODO
// }}}
// _NET_RESTACK_WINDOW
// {{{
// TODO
// }}}
// // _NET_MOVERESIZE_WINDOW
// // {{{
//
// // TODO
//
// // }}}
//
// // _NET_WM_MOVERESIZE
// // {{{
//
// // TODO
//
// // }}}
//
// // _NET_RESTACK_WINDOW
// // {{{
//
// // TODO
//
// // }}}
//
// _NET_REQUEST_FRAME_EXTENTS // _NET_REQUEST_FRAME_EXTENTS
// {{{ // {{{
pub struct RequestFrameExtents { pub struct RequestFrameExtents {
@ -692,45 +692,17 @@ pub struct RequestFrameExtents {
impl RequestFrameExtents { impl RequestFrameExtents {
pub fn new(connection: &Connection, window: xcb::x::Window) -> RequestFrameExtents { pub fn new(connection: &Connection, window: xcb::x::Window) -> RequestFrameExtents {
let client_message = xcb::x::ClientMessageEvent::new( RequestFrameExtents {
window, client_message: xcb::x::ClientMessageEvent::new(
connection.atoms._NET_REQUEST_FRAME_EXTENTS, window,
xcb::x::ClientMessageData::Data32([0x0, 0x0, 0x0, 0x0, 0x0]), connection.atoms._NET_REQUEST_FRAME_EXTENTS,
); xcb::x::ClientMessageData::Data32([0x00, 0x00, 0x00, 0x00, 0x00]),
RequestFrameExtents { client_message }
}
}
impl<'a> EwmhRequest<'a> for RequestFrameExtents {
type Cookie = xcb::VoidCookieChecked;
type CookieUnchecked = xcb::VoidCookie;
fn send_request(&self, con: &Connection) -> Self::Cookie {
con.con.send_request_checked(&self.get_request_data(con))
}
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
con.con.send_request(&self.get_request_data(con))
}
}
impl<'a> EwmhRequestData<'a> for RequestFrameExtents {
type Request = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
fn get_request_data(
&'a self,
con: &Connection,
) -> xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent> {
xcb::x::SendEvent {
propagate: false,
destination: xcb::x::SendEventDest::Window(
con.con.get_setup().roots().next().unwrap().root(),
), ),
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
event: &self.client_message,
} }
} }
} }
ewmh_client_message! {
request=RequestFrameExtents{destination: root_window}
}
// }}} // }}}

View file

@ -1,151 +0,0 @@
fn x_buffer_to_strings(xbuf: &[u8]) -> Vec<String> {
let mut vals = vec![];
let mut buf = vec![];
for b in xbuf {
if *b != 0x00 {
buf.push(*b)
} else if !buf.is_empty() {
vals.push(String::from_utf8(buf.clone()).unwrap());
buf.clear();
} else {
buf.clear();
}
}
vals
}
fn strings_to_x_buffer(strings: Vec<&str>) -> Vec<u8> {
let mut data = vec![];
// flatten `strings` into a continuous, NULL separated, array of bytes
for s in strings {
let mut bs = s.as_bytes().to_owned();
bs.push(0b00);
data.extend(bs)
}
data
}
pub(crate) mod net_supported {
use crate::ewmh::traits::*;
use crate::ewmh::Connection;
pub struct GetSupported;
pub struct GetSupportedCookie(xcb::x::GetPropertyCookie);
pub struct GetSupportedCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
#[derive(Debug)]
pub struct GetSupportedReply {
pub atoms: Vec<xcb::x::Atom>,
}
impl From<xcb::x::GetPropertyReply> for GetSupportedReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetSupportedReply {
atoms: reply.value().into(),
}
}
}
ewmh_get_property! {
request=GetSupported{
window: root_window,
property: _NET_SUPPORTED,
xtype: ATOM_ATOM
},
reply=GetSupportedReply,
cookie=GetSupportedCookie,
cookie_unchecked=GetSupportedCookieUnchecked
}
}
pub(crate) mod net_desktop_names {
use crate::ewmh::proto::test_props::{strings_to_x_buffer, x_buffer_to_strings};
use crate::ewmh::traits::*;
use crate::ewmh::Connection;
pub struct GetDesktopNames;
pub struct GetDesktopNamesCookie(xcb::x::GetPropertyCookie);
pub struct GetDesktopNamesCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
#[derive(Debug)]
pub struct GetDesktopNamesReply {
pub desktop_names: Vec<String>,
}
impl From<xcb::x::GetPropertyReply> for GetDesktopNamesReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetDesktopNamesReply {
desktop_names: x_buffer_to_strings(reply.value::<u8>()),
}
}
}
ewmh_get_property! {
request=GetDesktopNames{
window: root_window,
property: _NET_DESKTOP_NAMES,
xtype: UTF8_STRING
},
reply=GetDesktopNamesReply,
cookie=GetDesktopNamesCookie,
cookie_unchecked=GetDesktopNamesCookieUnchecked
}
pub struct SetDesktopNames {
data: Vec<u8>,
}
impl SetDesktopNames {
pub fn new(names: Vec<&str>) -> SetDesktopNames {
SetDesktopNames {
data: strings_to_x_buffer(names),
}
}
}
ewmh_set_property! {
request=SetDesktopNames{
window: root_window,
property: _NET_DESKTOP_NAMES,
xtype: UTF8_STRING
}
}
}
pub(crate) mod net_showing_desktop {
use crate::ewmh::traits::*;
use crate::ewmh::Connection;
pub struct SetShowingDesktop {
client_message: xcb::x::ClientMessageEvent,
}
impl SetShowingDesktop {
pub fn new(connection: &Connection, show_desktop: bool) -> SetShowingDesktop {
let data = match show_desktop {
false => 0 as u32,
true => 1 as u32,
};
let client_message = xcb::x::ClientMessageEvent::new(
connection.con.get_setup().roots().next().unwrap().root(),
connection.atoms._NET_SHOWING_DESKTOP,
xcb::x::ClientMessageData::Data32([data, 0x00, 0x00, 0x00, 0x00]),
);
SetShowingDesktop { client_message }
}
}
ewmh_client_message! {
request=SetShowingDesktop{destination: root_window}
}
}

30
src/ewmh/proto/util.rs Normal file
View file

@ -0,0 +1,30 @@
pub(crate) fn x_buffer_to_strings(xbuf: &[u8]) -> Vec<String> {
let mut vals = vec![];
let mut buf = vec![];
for b in xbuf {
if *b != 0x00 {
buf.push(*b)
} else if !buf.is_empty() {
vals.push(String::from_utf8(buf.clone()).unwrap());
buf.clear();
} else {
buf.clear();
}
}
vals
}
pub(crate) fn strings_to_x_buffer(strings: Vec<&str>) -> Vec<u8> {
let mut data = vec![];
// flatten `strings` into a continuous, NULL separated, array of bytes
for s in strings {
let mut bs = s.as_bytes().to_owned();
bs.push(0b00);
data.extend(bs)
}
data
}