Implement application properties
https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048
This commit is contained in:
parent
bee554c057
commit
1729b8c2b1
8 changed files with 703 additions and 702 deletions
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
authors = [ "Armin Friedl <dev@friedl.net>" ]
|
||||
description = "Rust implementation of xcb-wm - icccm and ewmh extensions for xcb"
|
||||
readme = "README.md"
|
||||
keywords = ["icccm", "ewmh", "xcb-wm", "xcb", "window", "xlib", "x11"]
|
||||
keywords = ["icccm", "ewmh", "xcb", "window", "x11"]
|
||||
license = "MIT"
|
||||
edition = "2018"
|
||||
repository = "https://git.friedl.net/incubator/xcb-wm"
|
||||
|
|
|
@ -101,28 +101,28 @@ mod tests {
|
|||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn number_of_desktops() {
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let request = crate::ewmh::proto::GetNumberOfDesktops::new();
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn set_number_of_desktops() {
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let request = crate::ewmh::proto::SetNumberOfDesktops::new(4);
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
#[test]
|
||||
fn 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::GetNumberOfDesktops;
|
||||
let cookie = ewmh_con.send_request(&request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
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;
|
||||
|
|
|
@ -4,19 +4,15 @@
|
|||
|
||||
use xcb::{Xid, XidNew};
|
||||
|
||||
use crate::ewmh::connection::Connection;
|
||||
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData};
|
||||
use crate::ewmh::proto::util::{strings_to_x_buffer, x_buffer_to_strings};
|
||||
use crate::ewmh::traits::*;
|
||||
use crate::ewmh::Connection;
|
||||
|
||||
// _NET_WM_NAME, UTF8_STRING
|
||||
// {{{
|
||||
ewmh_get_window_request! {
|
||||
GetWmName,
|
||||
_NET_WM_NAME,
|
||||
UTF8_STRING,
|
||||
GetWmNameCookie,
|
||||
GetWmNameCookieUnchecked,
|
||||
GetWmNameReply
|
||||
}
|
||||
pub struct GetWmName(xcb::x::Window);
|
||||
pub struct GetWmNameCookie(xcb::x::GetPropertyCookie);
|
||||
pub struct GetWmNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetWmNameReply {
|
||||
|
@ -25,31 +21,52 @@ pub struct GetWmNameReply {
|
|||
|
||||
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(),
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_window_request! {
|
||||
GetWmVisibleName,
|
||||
_NET_WM_VISIBLE_NAME,
|
||||
UTF8_STRING,
|
||||
GetWmVisibleNameCooke,
|
||||
GetWmVisibleNameCookieUnchecked,
|
||||
GetWmVisibleNameReply
|
||||
}
|
||||
pub struct GetWmVisibleName(xcb::x::Window);
|
||||
pub struct GetWmVisibleNameCookie(xcb::x::GetPropertyCookie);
|
||||
pub struct GetWmVisibleNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetWmVisibleNameReply {
|
||||
|
@ -58,31 +75,29 @@ pub struct GetWmVisibleNameReply {
|
|||
|
||||
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(),
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_window_request! {
|
||||
GetWmIconName,
|
||||
_NET_WM_ICON_NAME,
|
||||
UTF8_STRING,
|
||||
GetWmIconNameCooke,
|
||||
GetWmIconNameCookieUnchecked,
|
||||
GetWmIconNameReply
|
||||
}
|
||||
pub struct GetWmIconName;
|
||||
pub struct GetWmIconNameCookie(xcb::x::GetPropertyCookie);
|
||||
pub struct GetWmIconNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetWmIconNameReply {
|
||||
|
@ -91,31 +106,29 @@ pub struct GetWmIconNameReply {
|
|||
|
||||
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(),
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_window_request! {
|
||||
GetWmVisibleIconName,
|
||||
_NET_WM_VISIBLE_ICON_NAME,
|
||||
UTF8_STRING,
|
||||
GetWmVisibleIconNameCooke,
|
||||
GetWmVisibleIconNameCookieUnchecked,
|
||||
GetWmVisibleIconNameReply
|
||||
}
|
||||
pub struct GetWmVisibleIconName;
|
||||
pub struct GetWmVisibleIconNameCookie(xcb::x::GetPropertyCookie);
|
||||
pub struct GetWmVisibleIconNameCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetWmVisibleIconNameReply {
|
||||
|
@ -124,31 +137,29 @@ pub struct GetWmVisibleIconNameReply {
|
|||
|
||||
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(),
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_window_request! {
|
||||
GetWmDesktop,
|
||||
_NET_WM_DESKTOP,
|
||||
CARDINAL,
|
||||
GetWmDesktopCooke,
|
||||
GetWmDesktopCookieUnchecked,
|
||||
GetWmDesktopReply
|
||||
}
|
||||
pub struct GetWmDesktop;
|
||||
pub struct GetWmDesktopCookie(xcb::x::GetPropertyCookie);
|
||||
pub struct GetWmDesktopCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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
|
||||
// {{{
|
||||
|
||||
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 {
|
||||
window: xcb::x::Window,
|
||||
data: Vec<xcb::x::Atom>,
|
||||
|
@ -181,31 +273,11 @@ impl SetWmWindowType {
|
|||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
ewmh_set_property! {
|
||||
request=SetWmWindowType{
|
||||
window: client_window,
|
||||
property: _NET_WM_WINDOW_TYPE,
|
||||
xtype: ATOM_ATOM
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,46 +286,65 @@ impl From<xcb::x::GetPropertyReply> for GetWmWindowTypeReply {
|
|||
// _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
|
||||
}
|
||||
pub struct GetWmState(xcb::x::Window);
|
||||
pub struct GetWmStateCookie(xcb::x::GetPropertyCookie);
|
||||
pub struct GetWmStateCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetWmStateReply {
|
||||
pub types: Vec<xcb::x::Atom>,
|
||||
pub states: 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(),
|
||||
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}
|
||||
}
|
||||
// }}}
|
||||
|
|
|
@ -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 {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: $window,
|
||||
window: self.0,
|
||||
property: con.atoms.$property,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
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 {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: $window,
|
||||
window: self.0,
|
||||
property: con.atoms.$property,
|
||||
r#type: xcb::x::$xtype,
|
||||
long_offset: 0,
|
||||
|
@ -126,7 +126,7 @@ macro_rules! _set_property_base {
|
|||
};
|
||||
|
||||
(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 {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
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> {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: $window,
|
||||
window: self.window,
|
||||
property: con.atoms.$property,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
data: &self.data,
|
||||
|
@ -149,13 +149,25 @@ macro_rules! _set_property_base {
|
|||
}
|
||||
};
|
||||
|
||||
($window:ident, $property:ident, $xtype:ident) => {
|
||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u8> {
|
||||
(client_window, $property:ident, ATOM_CARDINAL) => {
|
||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: $window,
|
||||
window: self.window,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -166,14 +178,13 @@ macro_rules! ewmh_set_property {
|
|||
(request=$request:ident{
|
||||
window: $window:ident,
|
||||
property: $property:ident,
|
||||
xtype: $xtype: ident
|
||||
xtype: UTF8_STRING
|
||||
}) => {
|
||||
impl<'a> EwmhRequest<'a> for $request {
|
||||
// TODO fixing to u8 is probably not flexible enough
|
||||
type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
|
||||
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 {
|
||||
xcb_cookie
|
||||
|
@ -183,7 +194,53 @@ macro_rules! ewmh_set_property {
|
|||
impl<'a> EwmhVoidRequestChecked<'a> for $request {
|
||||
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 }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod test_props;
|
||||
pub(crate) mod util;
|
||||
|
||||
pub use test_props::net_desktop_names::*;
|
||||
pub use test_props::net_showing_desktop::*;
|
||||
pub use test_props::net_supported::*;
|
||||
mod root_props;
|
||||
pub use root_props::*;
|
||||
|
||||
mod application_props;
|
||||
pub use application_props::*;
|
||||
|
|
|
@ -4,19 +4,17 @@
|
|||
|
||||
use xcb::{Xid, XidNew};
|
||||
|
||||
use crate::ewmh::connection::Connection;
|
||||
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData};
|
||||
use crate::ewmh::proto::util::{strings_to_x_buffer, x_buffer_to_strings};
|
||||
use crate::ewmh::traits::*;
|
||||
use crate::ewmh::Connection;
|
||||
|
||||
// _NET_SUPPORTED, ATOM[]/32
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetSupported,
|
||||
_NET_SUPPORTED,
|
||||
ATOM_ATOM,
|
||||
GetSupportedCookie,
|
||||
GetSupportedCookieUnchecked,
|
||||
GetSupportedReply
|
||||
}
|
||||
pub struct GetSupported;
|
||||
|
||||
pub struct GetSupportedCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetSupportedCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetClientList,
|
||||
_NET_CLIENT_LIST,
|
||||
ATOM_WINDOW,
|
||||
GetClientListCookie,
|
||||
GetClientListCookieUnchecked,
|
||||
GetClientListReply
|
||||
}
|
||||
pub struct GetClientList;
|
||||
|
||||
pub struct GetClientListCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetClientListCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetClientListStacking,
|
||||
_NET_CLIENT_LIST_STACKING,
|
||||
ATOM_WINDOW,
|
||||
GetClientListStackingCookie,
|
||||
GetClientListStackingCookieUnchecked,
|
||||
GetClientListStackingReply
|
||||
}
|
||||
pub struct GetClientListStacking;
|
||||
|
||||
pub struct GetClientListStackingCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetClientListStackingCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetNumberOfDesktops,
|
||||
_NET_NUMBER_OF_DESKTOPS,
|
||||
ATOM_CARDINAL,
|
||||
GetNumberOfDesktopsCookie,
|
||||
GetNumberOfDesktopsCookieUnchecked,
|
||||
GetNumberOfDesktopsReply
|
||||
}
|
||||
pub struct GetNumberOfDesktops;
|
||||
|
||||
pub struct GetNumberOfDesktopsCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetNumberOfDesktopsCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
data: [u32; 1],
|
||||
client_message: xcb::x::ClientMessageEvent,
|
||||
}
|
||||
|
||||
impl SetNumberOfDesktops {
|
||||
pub fn new(desktops: u32) -> SetNumberOfDesktops {
|
||||
SetNumberOfDesktops { data: [desktops] }
|
||||
pub fn new(connection: &Connection, desktops: u32) -> SetNumberOfDesktops {
|
||||
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! {
|
||||
SetNumberOfDesktops,
|
||||
_NET_NUMBER_OF_DESKTOPS,
|
||||
ATOM_CARDINAL
|
||||
ewmh_client_message! {
|
||||
request=SetNumberOfDesktops{destination: root_window}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_DESKTOP_GEOMETRY width, height, CARDINAL[2]/32
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetDesktopGeometry,
|
||||
_NET_DESKTOP_GEOMETRY,
|
||||
ATOM_CARDINAL,
|
||||
GetDesktopGeometryCookie,
|
||||
GetDesktopGeometryCookieUnchecked,
|
||||
GetDesktopGeometryReply
|
||||
}
|
||||
pub struct GetDesktopGeometry;
|
||||
|
||||
pub struct GetDesktopGeometryCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetDesktopGeometryCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetDesktopGeometryReply {
|
||||
|
@ -145,41 +178,51 @@ impl From<xcb::x::GetPropertyReply> for GetDesktopGeometryReply {
|
|||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||
GetDesktopGeometryReply {
|
||||
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 {
|
||||
data: [u32; 2],
|
||||
client_message: xcb::x::ClientMessageEvent,
|
||||
}
|
||||
|
||||
impl SetDesktopGeometry {
|
||||
pub fn new(width: u32, height: u32) -> SetDesktopGeometry {
|
||||
pub fn new(connection: &Connection, width: u32, height: u32) -> 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! {
|
||||
SetDesktopGeometry,
|
||||
_NET_DESKTOP_GEOMETRY,
|
||||
ATOM_CARDINAL
|
||||
ewmh_client_message! {
|
||||
request=SetDesktopGeometry{destination: root_window}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_DESTKOP_VIEWPORT x, y, CARDINAL[][2]/32
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetDesktopViewport,
|
||||
_NET_DESKTOP_VIEWPORT,
|
||||
ATOM_CARDINAL,
|
||||
GetDesktopViewportCookie,
|
||||
GetDesktopViewportCookieUnchecked,
|
||||
GetDesktopViewportReply
|
||||
}
|
||||
pub struct GetDesktopViewport;
|
||||
|
||||
pub struct GetDesktopViewportCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetDesktopViewportCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
data: [u32; 2],
|
||||
client_message: xcb::x::ClientMessageEvent,
|
||||
}
|
||||
|
||||
impl SetDesktopViewport {
|
||||
pub fn new(x: u32, y: u32) -> SetDesktopViewport {
|
||||
SetDesktopViewport { data: [x, y] }
|
||||
pub fn new(connection: &Connection, x: u32, y: u32) -> SetDesktopViewport {
|
||||
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! {
|
||||
SetDesktopViewport,
|
||||
_NET_DESKTOP_VIEWPORT,
|
||||
ATOM_CARDINAL
|
||||
ewmh_client_message! {
|
||||
request=SetDesktopViewport{destination: root_window}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_CURRENT_DESKTOP desktop, CARDINAL/32
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetCurrentDesktop,
|
||||
_NET_CURRENT_DESKTOP,
|
||||
ATOM_CARDINAL,
|
||||
GetCurrentDesktopCookie,
|
||||
GetCurrentDesktopCookieUnchecked,
|
||||
GetCurrentDesktopReply
|
||||
}
|
||||
pub struct GetCurrentDesktop;
|
||||
|
||||
pub struct GetCurrentDesktopCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetCurrentDesktopCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
data: [u32; 2],
|
||||
client_message: xcb::x::ClientMessageEvent,
|
||||
}
|
||||
|
||||
impl SetCurrentDesktop {
|
||||
pub fn new(new_index: u32, timestamp: u32) -> SetCurrentDesktop {
|
||||
pub fn new(connection: &Connection, desktop: u32) -> 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! {
|
||||
SetCurrentDesktop,
|
||||
_NET_CURRENT_DESKTOP,
|
||||
ATOM_CARDINAL
|
||||
ewmh_client_message! {
|
||||
request=SetCurrentDesktop{destination: root_window}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_DESKTOP_NAMES desktop, UTF8_STRING[]
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetDesktopNames,
|
||||
_NET_DESKTOP_NAMES,
|
||||
UTF8_STRING,
|
||||
GetDesktopNamesCookie,
|
||||
GetDesktopNamesCookieUnchecked,
|
||||
GetDesktopNamesReply
|
||||
}
|
||||
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>,
|
||||
pub names: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<xcb::x::GetPropertyReply> for GetDesktopNamesReply {
|
||||
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 {
|
||||
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 {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl SetDesktopNames {
|
||||
pub fn new(new_names: Vec<&str>) -> SetDesktopNames {
|
||||
let mut data: Vec<u8> = vec![];
|
||||
|
||||
// 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)
|
||||
pub fn new(names: Vec<&str>) -> SetDesktopNames {
|
||||
SetDesktopNames {
|
||||
data: strings_to_x_buffer(names),
|
||||
}
|
||||
|
||||
SetDesktopNames { data }
|
||||
}
|
||||
}
|
||||
|
||||
ewmh_set_root_request! {
|
||||
SetDesktopNames,
|
||||
_NET_DESKTOP_NAMES,
|
||||
UTF8_STRING
|
||||
ewmh_set_property! {
|
||||
request=SetDesktopNames{
|
||||
window: root_window,
|
||||
property: _NET_DESKTOP_NAMES,
|
||||
xtype: UTF8_STRING
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_ACTIVE_WINDOW, WINDOW/32
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetActiveWindow,
|
||||
_NET_ACTIVE_WINDOW,
|
||||
ATOM_WINDOW,
|
||||
GetActiveWindowCookie,
|
||||
GetActiveWindowCookieUnchecked,
|
||||
GetActiveWindowReply
|
||||
}
|
||||
pub struct GetActiveWindow;
|
||||
|
||||
pub struct GetActiveWindowCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetActiveWindowCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetActiveWindowReply {
|
||||
pub value: xcb::x::Window,
|
||||
pub window: xcb::x::Window,
|
||||
}
|
||||
|
||||
impl From<xcb::x::GetPropertyReply> for GetActiveWindowReply {
|
||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||
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 {
|
||||
client_message: xcb::x::ClientMessageEvent,
|
||||
}
|
||||
|
@ -359,67 +421,35 @@ impl SetActiveWindow {
|
|||
timestamp: u32,
|
||||
requestor_window: Option<xcb::x::Window>,
|
||||
) -> SetActiveWindow {
|
||||
let data = [
|
||||
SetActiveWindow {
|
||||
client_message: xcb::x::ClientMessageEvent::new(
|
||||
window,
|
||||
connection.atoms._NET_ACTIVE_WINDOW,
|
||||
xcb::x::ClientMessageData::Data32([
|
||||
source_indication,
|
||||
timestamp,
|
||||
requestor_window.map_or(0, |w| w.resource_id()),
|
||||
0x00,
|
||||
0x00,
|
||||
];
|
||||
|
||||
let client_message = xcb::x::ClientMessageEvent::new(
|
||||
window,
|
||||
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,
|
||||
_NET_WORKAREA,
|
||||
ATOM_CARDINAL,
|
||||
GetWorkareaCookie,
|
||||
GetWorkareaCookieUnchecked,
|
||||
GetWorkareaReply
|
||||
}
|
||||
|
||||
pub struct GetWorkarea;
|
||||
|
||||
pub struct GetWorkareaCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetWorkareaCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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! {
|
||||
GetSupportingWmCheck,
|
||||
_NET_SUPPORTING_WM_CHECK,
|
||||
ATOM_WINDOW,
|
||||
GetSupportingWmCheckCookie,
|
||||
GetSupportingWmCheckCookieUnchecked,
|
||||
GetSupportingWmCheckReply
|
||||
}
|
||||
pub struct GetSupportingWmCheck;
|
||||
|
||||
pub struct GetSupportingWmCheckCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetSupportingWmCheckCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetSupportingWmCheckReply {
|
||||
|
@ -468,14 +507,11 @@ impl From<xcb::x::GetPropertyReply> for GetSupportingWmCheckReply {
|
|||
|
||||
// _NET_VIRTUAL_ROOTS, WINDOW/32
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetVirtualRoots,
|
||||
_NET_VIRTUAL_ROOTS,
|
||||
ATOM_WINDOW,
|
||||
GetVirtualRootsCookie,
|
||||
GetVirtualRootsCookieUnchecked,
|
||||
GetVirtualRootsReply
|
||||
}
|
||||
pub struct GetVirtualRoots;
|
||||
|
||||
pub struct GetVirtualRootsCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetVirtualRootsCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetDesktopLayout,
|
||||
_NET_DESKTOP_LAYOUT,
|
||||
ATOM_CARDINAL,
|
||||
GetDesktopLayoutCookie,
|
||||
GetDesktopLayoutCookieUnchecked,
|
||||
GetDesktopLayoutReply
|
||||
}
|
||||
pub struct DesktopLayout;
|
||||
|
||||
pub struct DesktopLayoutCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct DesktopLayoutCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetDesktopLayoutReply {
|
||||
orientation: u32,
|
||||
columns: u32,
|
||||
rows: u32,
|
||||
starting_corner: u32,
|
||||
pub struct DesktopLayoutReply {
|
||||
pub orientation: u32,
|
||||
pub columns: u32,
|
||||
pub rows: 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 {
|
||||
GetDesktopLayoutReply {
|
||||
DesktopLayoutReply {
|
||||
orientation: reply.value::<u32>()[0],
|
||||
columns: reply.value::<u32>()[1],
|
||||
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
|
||||
// {{{
|
||||
ewmh_get_root_request! {
|
||||
GetShowingDesktop,
|
||||
_NET_SHOWING_DESKTOP,
|
||||
ATOM_CARDINAL,
|
||||
GetShowingDesktopCookie,
|
||||
GetShowingDesktopCookieUnchecked,
|
||||
GetShowingDesktopReply
|
||||
}
|
||||
pub struct GetShowingDesktop;
|
||||
|
||||
pub struct GetShowingDesktopCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetShowingDesktopCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetShowingDesktopReply {
|
||||
showing_desktop: bool,
|
||||
pub is_showing_desktop: bool,
|
||||
}
|
||||
|
||||
impl From<xcb::x::GetPropertyReply> for GetShowingDesktopReply {
|
||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||
GetShowingDesktopReply {
|
||||
showing_desktop: match reply.value::<u32>()[0] {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => unreachable!(),
|
||||
is_showing_desktop: if reply.value::<u32>()[0] == 1 {
|
||||
true
|
||||
} else {
|
||||
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 {
|
||||
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 data = if show_desktop { 1 } else { 0 };
|
||||
|
||||
let client_message = xcb::x::ClientMessageEvent::new(
|
||||
SetShowingDesktop {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -618,72 +649,41 @@ impl CloseWindow {
|
|||
source_indication: u32,
|
||||
timestamp: u32,
|
||||
) -> CloseWindow {
|
||||
let data = [timestamp, source_indication, 0x00, 0x00, 0x00];
|
||||
|
||||
let client_message = xcb::x::ClientMessageEvent::new(
|
||||
CloseWindow {
|
||||
client_message: xcb::x::ClientMessageEvent::new(
|
||||
window,
|
||||
connection.atoms._NET_CLOSE_WINDOW,
|
||||
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(),
|
||||
xcb::x::ClientMessageData::Data32([timestamp, source_indication, 0x00, 0x00, 0x00]),
|
||||
),
|
||||
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
||||
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
||||
event: &self.client_message,
|
||||
}
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
// _NET_MOVERESIZE_WINDOW
|
||||
// {{{
|
||||
|
||||
// TODO
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_WM_MOVERESIZE
|
||||
// {{{
|
||||
|
||||
// TODO
|
||||
|
||||
// }}}
|
||||
|
||||
// _NET_RESTACK_WINDOW
|
||||
// {{{
|
||||
|
||||
// TODO
|
||||
|
||||
// }}}
|
||||
ewmh_client_message! {
|
||||
request=CloseWindow{destination: root_window}
|
||||
}
|
||||
|
||||
// // _NET_MOVERESIZE_WINDOW
|
||||
// // {{{
|
||||
//
|
||||
// // TODO
|
||||
//
|
||||
// // }}}
|
||||
//
|
||||
// // _NET_WM_MOVERESIZE
|
||||
// // {{{
|
||||
//
|
||||
// // TODO
|
||||
//
|
||||
// // }}}
|
||||
//
|
||||
// // _NET_RESTACK_WINDOW
|
||||
// // {{{
|
||||
//
|
||||
// // TODO
|
||||
//
|
||||
// // }}}
|
||||
//
|
||||
// _NET_REQUEST_FRAME_EXTENTS
|
||||
// {{{
|
||||
pub struct RequestFrameExtents {
|
||||
|
@ -692,45 +692,17 @@ pub struct RequestFrameExtents {
|
|||
|
||||
impl RequestFrameExtents {
|
||||
pub fn new(connection: &Connection, window: xcb::x::Window) -> RequestFrameExtents {
|
||||
let client_message = xcb::x::ClientMessageEvent::new(
|
||||
RequestFrameExtents {
|
||||
client_message: xcb::x::ClientMessageEvent::new(
|
||||
window,
|
||||
connection.atoms._NET_REQUEST_FRAME_EXTENTS,
|
||||
xcb::x::ClientMessageData::Data32([0x0, 0x0, 0x0, 0x0, 0x0]),
|
||||
);
|
||||
|
||||
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(),
|
||||
xcb::x::ClientMessageData::Data32([0x00, 0x00, 0x00, 0x00, 0x00]),
|
||||
),
|
||||
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
||||
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
||||
event: &self.client_message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ewmh_client_message! {
|
||||
request=RequestFrameExtents{destination: root_window}
|
||||
}
|
||||
// }}}
|
||||
|
|
|
@ -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
30
src/ewmh/proto/util.rs
Normal 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
|
||||
}
|
Loading…
Reference in a new issue