Begin application properties implementation
This commit is contained in:
parent
eb7785a74a
commit
0980df1e2b
4 changed files with 535 additions and 2 deletions
124
src/ewmh/ewmh.rs
124
src/ewmh/ewmh.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
260
src/ewmh/proto/application_props.rs
Normal file
260
src/ewmh/proto/application_props.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
|
@ -1,4 +1,6 @@
|
|||
mod application_props;
|
||||
#[allow(unused)]
|
||||
mod root_props;
|
||||
|
||||
pub use application_props::*;
|
||||
pub use root_props::*;
|
||||
|
|
|
@ -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 {}
|
||||
|
|
Loading…
Reference in a new issue