Begin application properties implementation

This commit is contained in:
Armin Friedl 2022-05-14 21:08:27 +02:00
parent eb7785a74a
commit 0980df1e2b
4 changed files with 535 additions and 2 deletions

View file

@ -304,4 +304,128 @@ mod tests {
let reply = xcb_con.check_request(cookie);
println!("{:?}", reply);
}
#[test]
fn wm_name() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(77594744) };
let request = crate::ewmh::proto::GetWmName::new(window);
let cookie = ewmh_con.send_request(request);
let reply = ewmh_con.wait_for_reply(cookie);
println!("{:?}", reply);
}
#[test]
fn wm_visible_name() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(20983603) };
let request = crate::ewmh::proto::GetWmVisibleName::new(window);
let cookie = ewmh_con.send_request(request);
let reply = ewmh_con.wait_for_reply(cookie);
println!("{:?}", reply);
}
#[test]
fn wm_desktop() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(20983603) };
let request = crate::ewmh::proto::GetWmDesktop::new(window);
let cookie = ewmh_con.send_request(request);
let reply = ewmh_con.wait_for_reply(cookie);
println!("{:?}", reply);
}
#[test]
fn set_wm_type() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(20995834) };
let request = crate::ewmh::proto::SetWmWindowType::new(
window,
vec![
ewmh_con.atoms._NET_WM_WINDOW_TYPE_UTILITY,
ewmh_con.atoms._NET_WM_WINDOW_TYPE_SPLASH,
],
);
let cookie = ewmh_con.send_request(request);
let reply = xcb_con.check_request(cookie);
println!("{:?}", reply);
}
#[test]
fn get_wm_type() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(20995834) };
let request = crate::ewmh::proto::GetWmWindowType::new(window);
let cookie = ewmh_con.send_request(request);
let reply = ewmh_con.wait_for_reply(cookie);
println!("{:?}", reply);
}
#[test]
fn set_wm_state() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(21002424) };
let request = crate::ewmh::proto::SetWmState::new(
window,
vec![
ewmh_con.atoms._NET_WM_STATE_STICKY,
ewmh_con.atoms._NET_WM_STATE_DEMANDS_ATTENTION,
],
);
let cookie = ewmh_con.send_request(request);
let reply = xcb_con.check_request(cookie);
println!("{:?}", reply);
}
#[test]
fn get_wm_state() {
use xcb::XidNew;
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
let window = unsafe { xcb::x::Window::new(21002424) };
let request = crate::ewmh::proto::GetWmWindowType::new(window);
let cookie = ewmh_con.send_request(request);
let reply = ewmh_con.wait_for_reply(cookie);
println!("{:?}", reply);
}
}

View file

@ -0,0 +1,260 @@
//! Application Window Properties
//!
//! see: https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048
use xcb::{Xid, XidNew};
use crate::ewmh::ewmh::Connection;
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData};
// _NET_WM_NAME, UTF8_STRING
// {{{
ewmh_get_window_request! {
GetWmName,
_NET_WM_NAME,
UTF8_STRING,
GetWmNameCookie,
GetWmNameCookieUnchecked,
GetWmNameReply
}
#[derive(Debug)]
pub struct GetWmNameReply {
pub name: String,
}
impl From<xcb::x::GetPropertyReply> for GetWmNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmNameReply {
name: String::from_utf8(buf).unwrap(),
}
}
}
// }}}
// _NET_WM_VISIBLE_NAME, UTF8_STRING
// {{{
ewmh_get_window_request! {
GetWmVisibleName,
_NET_WM_VISIBLE_NAME,
UTF8_STRING,
GetWmVisibleNameCooke,
GetWmVisibleNameCookieUnchecked,
GetWmVisibleNameReply
}
#[derive(Debug)]
pub struct GetWmVisibleNameReply {
pub name: String,
}
impl From<xcb::x::GetPropertyReply> for GetWmVisibleNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmVisibleNameReply {
name: String::from_utf8(buf).unwrap(),
}
}
}
// }}}
// _NET_WM_ICON_NAME, UTF8_STRING
// {{{
ewmh_get_window_request! {
GetWmIconName,
_NET_WM_ICON_NAME,
UTF8_STRING,
GetWmIconNameCooke,
GetWmIconNameCookieUnchecked,
GetWmIconNameReply
}
#[derive(Debug)]
pub struct GetWmIconNameReply {
pub name: String,
}
impl From<xcb::x::GetPropertyReply> for GetWmIconNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmIconNameReply {
name: String::from_utf8(buf).unwrap(),
}
}
}
// }}}
// _NET_WM_VISIBLE_ICON_NAME, UTF8_STRING
// {{{
ewmh_get_window_request! {
GetWmVisibleIconName,
_NET_WM_VISIBLE_ICON_NAME,
UTF8_STRING,
GetWmVisibleIconNameCooke,
GetWmVisibleIconNameCookieUnchecked,
GetWmVisibleIconNameReply
}
#[derive(Debug)]
pub struct GetWmVisibleIconNameReply {
pub name: String,
}
impl From<xcb::x::GetPropertyReply> for GetWmVisibleIconNameReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
let mut buf = vec![];
for b in reply.value::<u8>() {
if *b != 0x00 {
buf.push(*b)
}
}
GetWmVisibleIconNameReply {
name: String::from_utf8(buf).unwrap(),
}
}
}
// }}}
// _NET_WM_DESKTOP, CARDINAL/32
// {{{
ewmh_get_window_request! {
GetWmDesktop,
_NET_WM_DESKTOP,
CARDINAL,
GetWmDesktopCooke,
GetWmDesktopCookieUnchecked,
GetWmDesktopReply
}
#[derive(Debug)]
pub struct GetWmDesktopReply {
pub desktop: u32,
}
impl From<xcb::x::GetPropertyReply> for GetWmDesktopReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetWmDesktopReply {
desktop: reply.value::<u32>()[0],
}
}
}
// }}}
// _NET_WM_WINDOW_TYPE, ATOM[]/32
// {{{
pub struct SetWmWindowType {
window: xcb::x::Window,
data: Vec<xcb::x::Atom>,
}
impl SetWmWindowType {
pub fn new(window: xcb::x::Window, types: Vec<xcb::x::Atom>) -> SetWmWindowType {
SetWmWindowType {
window,
data: types,
}
}
}
ewmh_set_window_request! {
SetWmWindowType,
_NET_WM_WINDOW_TYPE,
{ xcb::x::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()
}
}
}
// }}}
// _NET_WM_STATE, ATOM[]/32
// {{{
pub struct SetWmState {
window: xcb::x::Window,
data: Vec<xcb::x::Atom>,
}
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)]
pub struct GetWmStateReply {
pub types: Vec<xcb::x::Atom>,
}
impl From<xcb::x::GetPropertyReply> for GetWmStateReply {
fn from(reply: xcb::x::GetPropertyReply) -> Self {
GetWmStateReply {
types: reply.value::<xcb::x::Atom>().into()
}
}
}
// }}}

View file

@ -1,4 +1,6 @@
mod application_props;
#[allow(unused)]
mod root_props;
pub use application_props::*;
pub use root_props::*;

View file

@ -1,5 +1,3 @@
#![macro_use]
use crate::ewmh::ewmh::Connection;
pub(crate) trait EwmhRequest<'a>: EwmhRequestData<'a> {
@ -25,6 +23,155 @@ pub(crate) trait EwmhCookieUnchecked {
fn reply(self, con: &Connection) -> Option<Self::Reply>;
}
macro_rules! ewmh_get_window_request_private {
($req: ident, $prop: ident, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
pub struct $req {
window: xcb::x::Window,
}
pub struct $cookie {
cookie: xcb::x::GetPropertyCookie,
}
pub struct $cookie_unchecked {
cookie: xcb::x::GetPropertyCookieUnchecked,
}
impl $req {
pub fn new(window: xcb::x::Window) -> $req {
$req { window }
}
}
impl<'a> EwmhRequest<'a> for $req {
type Cookie = $cookie;
type CookieUnchecked = $cookie_unchecked;
fn send_request(&self, con: &Connection) -> Self::Cookie {
$cookie {
cookie: con.con.send_request(&self.get_request_data(con)),
}
}
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
$cookie_unchecked {
cookie: con.con.send_request_unchecked(&self.get_request_data(con)),
}
}
}
impl EwmhCookie for $cookie {
type Reply = $reply;
fn reply(self, con: &Connection) -> Self::Reply {
let reply = con.con.wait_for_reply(self.cookie).unwrap();
reply.into()
}
}
impl EwmhCookieUnchecked for $cookie_unchecked {
type Reply = $reply;
fn reply(self, con: &Connection) -> Option<Self::Reply> {
con.con
.wait_for_reply_unchecked(self.cookie)
.unwrap()
.map(|reply| reply.into())
}
}
};
}
macro_rules! ewmh_get_window_request {
($req: ident, $prop: ident, UTF8_STRING, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
ewmh_get_window_request_private! {$req, $prop, $cookie, $cookie_unchecked, $reply}
impl<'a> EwmhRequestData<'a> for $req {
type Request = xcb::x::GetProperty;
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
xcb::x::GetProperty {
delete: false,
window: self.window,
property: con.atoms.$prop,
r#type: con.atoms.UTF8_STRING,
long_offset: 0,
long_length: u32::MAX,
}
}
}
};
($req: ident, $prop: ident, CARDINAL, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
ewmh_get_window_request_private! {$req, $prop, $cookie, $cookie_unchecked, $reply}
impl<'a> EwmhRequestData<'a> for $req {
type Request = xcb::x::GetProperty;
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
xcb::x::GetProperty {
delete: false,
window: self.window,
property: con.atoms.$prop,
r#type: xcb::x::ATOM_CARDINAL,
long_offset: 0,
long_length: u32::MAX,
}
}
}
};
($req: ident, $prop: ident, ATOM, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
ewmh_get_window_request_private! {$req, $prop, $cookie, $cookie_unchecked, $reply}
impl<'a> EwmhRequestData<'a> for $req {
type Request = xcb::x::GetProperty;
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
xcb::x::GetProperty {
delete: false,
window: self.window,
property: con.atoms.$prop,
r#type: xcb::x::ATOM_ATOM,
long_offset: 0,
long_length: u32::MAX,
}
}
}
};
}
macro_rules! ewmh_set_window_request {
($req: ident, $prop: ident, $type: tt) => {
impl<'a> EwmhRequest<'a> for $req {
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 $req {
type Request = xcb::x::ChangeProperty<'a, xcb::x::Atom>;
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
xcb::x::ChangeProperty {
mode: xcb::x::PropMode::Replace,
window: self.window,
property: con.atoms.$prop,
r#type: $type,
data: &self.data,
}
}
}
};
}
macro_rules! ewmh_get_request {
($req: ident, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
pub struct $req {}