Compare commits
No commits in common. "main" and "xcb-base" have entirely different histories.
22 changed files with 403 additions and 1814 deletions
|
@ -1,19 +1,18 @@
|
||||||
[package]
|
[package]
|
||||||
name = "xcb-wm"
|
name = "xcb-wm"
|
||||||
version = "0.3.0"
|
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", "window", "x11"]
|
keywords = ["icccm", "ewmh", "xcb", "window", "x11"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/arminfriedl/xcb-wm"
|
repository = "https://git.friedl.net/incubator/xcb-wm"
|
||||||
homepage = "https://github.com/arminfriedl/xcb-wm"
|
homepage = "https://git.friedl.net/incubator/xcb-wm"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
xcb = "1"
|
xcb = "1"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
bitflags = "1.3.2"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
icccm = []
|
icccm = []
|
||||||
|
|
72
README.md
72
README.md
|
@ -1,71 +1,3 @@
|
||||||
# xcb-wm
|
# rust-xcb-wm
|
||||||
|
|
||||||
The long lost Rust implementation of the
|
Rust implementation of xcb-wm - icccm and ewmh extensions for xcb
|
||||||
[icccm](https://tronche.com/gui/x/icccm/) and
|
|
||||||
[ewmh](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html)
|
|
||||||
extensions for the X Window System protocol.
|
|
||||||
|
|
||||||
xcb-wm provides type safe and Rust-native abstractions. It simplifies the usage
|
|
||||||
of window manager extensions to X11.
|
|
||||||
|
|
||||||
xcb-wm sits on top of [rust-xcb](https://github.com/rust-x-bindings/rust-xcb)
|
|
||||||
similar to how [libxcb-wm](https://gitlab.freedesktop.org/xorg/lib/libxcb-wm)
|
|
||||||
sits on top of [libxcb](https://gitlab.freedesktop.org/xorg/lib/libxcb). If you
|
|
||||||
are already using rust-xcb you are also familiar with xcb-wm. The public APIs
|
|
||||||
and general usage are intentionally close.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
Add this to your Cargo.toml:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
xcb-wm = "0.3.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Each request is either a `Get*`, a `Set*` or a `Send*` struct. `Get*` structs
|
|
||||||
can be used to get ewmh or iccm properties. `Set*` structs can be used to set
|
|
||||||
properties. `Send*` structs can be used to send client messages. You can read up
|
|
||||||
on the protocol definitions for more details but in general every property has a
|
|
||||||
corresponding `Get*` request. `Set*` requests are mostly useful _before_ a
|
|
||||||
window is mapped. `Send*` requests for everything else.
|
|
||||||
|
|
||||||
Each request can be sent either checked or unchecked. This is typesafe by
|
|
||||||
special cookies for each of them. You get the request cookie by calling
|
|
||||||
`send_request`/`send_request_unchecked`.
|
|
||||||
|
|
||||||
You can retrieve a reply and wrap it into a high level and meaningful Rust
|
|
||||||
struct by calling `wait_for_reply`/`wait_for_reply_unchecked` on the cookie. For
|
|
||||||
requests that don't have a reply (i.e. `Set*` and `Send*` requests) you can use
|
|
||||||
`check_request` to check for errors.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Get the names of available desktops:
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
use xcb;
|
|
||||||
use xcb_wm::ewmh;
|
|
||||||
|
|
||||||
// Create a `rust-xcb` connection
|
|
||||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
|
||||||
|
|
||||||
// Wrap the connection in an `xcb-wm::ewmh` connection for ewmh extensions.
|
|
||||||
//
|
|
||||||
// Note that this does not take ownership of the `rust-xcb` connection
|
|
||||||
// so you can continue to use other xcb functionality with the same
|
|
||||||
// connection.
|
|
||||||
let ewmh_con = ewmh::Connection::connect(&xcb_con);
|
|
||||||
|
|
||||||
// Create a request for the _NET_DESKTOP_NAMES property
|
|
||||||
let request = ewmh::proto::GetDesktopNames;
|
|
||||||
let cookie = ewmh_con.send_request(&request);
|
|
||||||
|
|
||||||
// Get a `GetDesktopNamesReply` reply
|
|
||||||
//
|
|
||||||
// Replies are automatically de-serialized into meaningful Rust structs. You
|
|
||||||
// take full ownership of the reply struct.
|
|
||||||
let reply = ewmh_con.wait_for_reply(cookie);
|
|
||||||
|
|
||||||
// All replies implement `Debug` so you can also print them
|
|
||||||
println!("{:?}", reply);
|
|
||||||
```
|
|
|
@ -33,28 +33,28 @@ impl<'a> Connection<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_request<'b, R>(&self, request: &'b R) -> R::EwmhCookie
|
fn send_request<'b, R>(&self, request: &'b R) -> R::EwmhCookie
|
||||||
where
|
where
|
||||||
R: EwmhRequest<'b>,
|
R: EwmhRequest<'b>,
|
||||||
{
|
{
|
||||||
request.send(self)
|
request.send(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_request_checked<'b, R>(&self, request: &'b R) -> xcb::VoidCookieChecked
|
fn send_request_checked<'b, R>(&self, request: &'b R) -> xcb::VoidCookieChecked
|
||||||
where
|
where
|
||||||
R: EwmhVoidRequestChecked<'b>,
|
R: EwmhVoidRequestChecked<'b>,
|
||||||
{
|
{
|
||||||
request.send(self)
|
request.send(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_request_unchecked<R>(&self, request: &R) -> R::EwmhCookie
|
fn send_request_unchecked<R>(&self, request: &R) -> R::EwmhCookie
|
||||||
where
|
where
|
||||||
R: EwmhPropertyRequestUnchecked,
|
R: EwmhPropertyRequestUnchecked,
|
||||||
{
|
{
|
||||||
request.send(self)
|
request.send(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_for_reply<C>(&self, cookie: C) -> C::Reply
|
fn wait_for_reply<C>(&self, cookie: C) -> C::Reply
|
||||||
where
|
where
|
||||||
C: EwmhPropertyCookieChecked,
|
C: EwmhPropertyCookieChecked,
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ impl<'a> Connection<'a> {
|
||||||
xcb_reply.unwrap().into()
|
xcb_reply.unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_for_reply_unchecked<C>(&self, cookie: C) -> C::Reply
|
fn wait_for_reply_unchecked<C>(&self, cookie: C) -> C::Reply
|
||||||
where
|
where
|
||||||
C: EwmhPropertyCookieUnchecked,
|
C: EwmhPropertyCookieUnchecked,
|
||||||
{
|
{
|
||||||
|
@ -112,6 +112,17 @@ mod tests {
|
||||||
println!("{:?}", reply);
|
println!("{:?}", reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_number_of_desktops() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::SetNumberOfDesktops::new(&ewmh_con, 4);
|
||||||
|
let cookie = ewmh_con.send_request_checked(&request);
|
||||||
|
let reply = xcb_con.check_request(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn number_of_desktops2() {
|
// fn number_of_desktops2() {
|
||||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
//! see: <https://specifications.freedesktop.org/wm-spec/1.5/ar01s03.html#idm45539547193552>
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! see: <https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048>
|
//! see: <https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048>
|
||||||
|
|
||||||
#![allow(dead_code)]
|
use xcb::{Xid, XidNew};
|
||||||
|
|
||||||
use xcb::Xid;
|
|
||||||
|
|
||||||
use crate::ewmh::proto::util::{strings_to_x_buffer, x_buffer_to_strings};
|
use crate::ewmh::proto::util::{strings_to_x_buffer, x_buffer_to_strings};
|
||||||
use crate::ewmh::traits::*;
|
use crate::ewmh::traits::*;
|
||||||
|
@ -42,7 +40,7 @@ pub struct SetWmName {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SetWmName {
|
impl SetWmName {
|
||||||
pub fn new(window: xcb::x::Window, name: &str) -> SetWmName {
|
pub fn new(connection: &Connection, window: xcb::x::Window, name: &str) -> SetWmName {
|
||||||
SetWmName {
|
SetWmName {
|
||||||
window: window,
|
window: window,
|
||||||
data: strings_to_x_buffer(vec![name]),
|
data: strings_to_x_buffer(vec![name]),
|
||||||
|
@ -52,7 +50,7 @@ impl SetWmName {
|
||||||
|
|
||||||
ewmh_set_property! {
|
ewmh_set_property! {
|
||||||
request=SetWmName{
|
request=SetWmName{
|
||||||
window: client,
|
window: client_window,
|
||||||
property: _NET_WM_NAME,
|
property: _NET_WM_NAME,
|
||||||
xtype: UTF8_STRING
|
xtype: UTF8_STRING
|
||||||
}
|
}
|
||||||
|
@ -175,7 +173,7 @@ impl SetWmDesktop {
|
||||||
|
|
||||||
ewmh_set_property! {
|
ewmh_set_property! {
|
||||||
request=SetWmDesktop {
|
request=SetWmDesktop {
|
||||||
window: client,
|
window: client_window,
|
||||||
property: _NET_WM_DESKTOP,
|
property: _NET_WM_DESKTOP,
|
||||||
xtype: ATOM_CARDINAL
|
xtype: ATOM_CARDINAL
|
||||||
}
|
}
|
||||||
|
@ -198,7 +196,7 @@ impl SendWmDesktop {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendWmDesktop{destination: root}
|
request=SendWmDesktop{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -242,7 +240,7 @@ impl SetWmWindowType {
|
||||||
|
|
||||||
ewmh_set_property! {
|
ewmh_set_property! {
|
||||||
request=SetWmWindowType{
|
request=SetWmWindowType{
|
||||||
window: client,
|
window: client_window,
|
||||||
property: _NET_WM_WINDOW_TYPE,
|
property: _NET_WM_WINDOW_TYPE,
|
||||||
xtype: ATOM_ATOM
|
xtype: ATOM_ATOM
|
||||||
}
|
}
|
||||||
|
@ -274,18 +272,18 @@ ewmh_get_property! {
|
||||||
reply=GetWmStateReply
|
reply=GetWmStateReply
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendWmState {
|
pub struct SetWmState {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendWmState {
|
impl SetWmState {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
connection: &Connection,
|
connection: &Connection,
|
||||||
window: xcb::x::Window,
|
window: xcb::x::Window,
|
||||||
action: xcb::x::PropMode,
|
action: xcb::x::PropMode,
|
||||||
states: [xcb::x::Atom; 2],
|
states: [xcb::x::Atom; 2],
|
||||||
source_indication: u32,
|
source_indication: u32,
|
||||||
) -> SendWmState {
|
) -> SetWmState {
|
||||||
let data = [
|
let data = [
|
||||||
unsafe { std::mem::transmute::<_, u32>(action) },
|
unsafe { std::mem::transmute::<_, u32>(action) },
|
||||||
states[0].resource_id(),
|
states[0].resource_id(),
|
||||||
|
@ -294,7 +292,7 @@ impl SendWmState {
|
||||||
0x00,
|
0x00,
|
||||||
];
|
];
|
||||||
|
|
||||||
SendWmState {
|
SetWmState {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
window,
|
window,
|
||||||
connection.atoms._NET_WM_DESKTOP,
|
connection.atoms._NET_WM_DESKTOP,
|
||||||
|
@ -305,6 +303,6 @@ impl SendWmState {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendWmState{destination: root}
|
request=SetWmState{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
320
src/ewmh/proto/macros.rs
Normal file
320
src/ewmh/proto/macros.rs
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
macro_rules! _set_property_base {
|
||||||
|
(root_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: con.con.get_setup().roots().next().unwrap().root(),
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: con.atoms.UTF8_STRING,
|
||||||
|
data: &self.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(root_window, $property:ident, $xtype:ident) => {
|
||||||
|
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(),
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: xcb::x::$xtype,
|
||||||
|
data: &self.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(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: self.window,
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: con.atoms.UTF8_STRING,
|
||||||
|
data: &self.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(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: self.window,
|
||||||
|
property: con.atoms.$property,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ewmh_set_property {
|
||||||
|
(request=$request:ident{
|
||||||
|
window: $window:ident,
|
||||||
|
property: $property:ident,
|
||||||
|
xtype: UTF8_STRING
|
||||||
|
}) => {
|
||||||
|
impl<'a> EwmhRequest<'a> for $request {
|
||||||
|
type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
|
||||||
|
type EwmhCookie = xcb::VoidCookie;
|
||||||
|
|
||||||
|
_set_property_base! {$window, $property, UTF8_STRING}
|
||||||
|
|
||||||
|
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, u8>;
|
||||||
|
|
||||||
|
_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 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! _client_message_base {
|
||||||
|
(root_window) => {
|
||||||
|
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($destination: ident) => {
|
||||||
|
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
||||||
|
xcb::x::SendEvent {
|
||||||
|
propagate: false,
|
||||||
|
destination: xcb::x::SendEventDest::Window($destination),
|
||||||
|
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
||||||
|
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
||||||
|
event: &self.client_message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ewmh_client_message {
|
||||||
|
(request=$request:ident{destination: $destination:ident}) => {
|
||||||
|
impl<'a> EwmhRequest<'a> for $request {
|
||||||
|
type XcbRequest = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
|
||||||
|
type EwmhCookie = xcb::VoidCookie;
|
||||||
|
|
||||||
|
_client_message_base! {$destination}
|
||||||
|
|
||||||
|
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
|
||||||
|
xcb_cookie
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> EwmhVoidRequestChecked<'a> for $request {
|
||||||
|
type XcbRequest = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
|
||||||
|
_client_message_base! {$destination}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! _get_property_cookies {
|
||||||
|
(@private $request:ident, $reply:ident) => {
|
||||||
|
paste! {
|
||||||
|
impl EwmhCookie for [<$request Cookie>] {
|
||||||
|
type XcbCookie = xcb::x::GetPropertyCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhPropertyCookieChecked for [<$request Cookie>] {
|
||||||
|
type Reply = $reply;
|
||||||
|
|
||||||
|
fn inner(self) -> xcb::x::GetPropertyCookie {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhPropertyCookieUnchecked for [<$request CookieUnchecked>] {
|
||||||
|
type Reply = $reply;
|
||||||
|
|
||||||
|
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! _get_property_request {
|
||||||
|
(@private root, $property:ident, UTF8_STRING) => {
|
||||||
|
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||||
|
xcb::x::GetProperty {
|
||||||
|
delete: false,
|
||||||
|
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: con.atoms.UTF8_STRING,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(@private root, $property:ident, $xtype:ident) => {
|
||||||
|
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||||
|
xcb::x::GetProperty {
|
||||||
|
delete: false,
|
||||||
|
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: xcb::x::$xtype,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(@private client, $property:ident, UTF8_STRING) => {
|
||||||
|
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||||
|
xcb::x::GetProperty {
|
||||||
|
delete: false,
|
||||||
|
window: self.0,
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: con.atoms.UTF8_STRING,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(@private client, $property:ident, $xtype:ident) => {
|
||||||
|
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||||
|
xcb::x::GetProperty {
|
||||||
|
delete: false,
|
||||||
|
window: self.0,
|
||||||
|
property: con.atoms.$property,
|
||||||
|
r#type: xcb::x::$xtype,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! _get_property_structs {
|
||||||
|
(@private $request:ident, root) => {
|
||||||
|
paste! {
|
||||||
|
pub struct $request;
|
||||||
|
pub struct [<$request Cookie>](xcb::x::GetPropertyCookie);
|
||||||
|
pub struct [<$request CookieUnchecked>](xcb::x::GetPropertyCookieUnchecked);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@private $request:ident, client) => {
|
||||||
|
paste! {
|
||||||
|
pub struct $request(xcb::x::Window);
|
||||||
|
pub struct [<$request Cookie>](xcb::x::GetPropertyCookie);
|
||||||
|
pub struct [<$request CookieUnchecked>](xcb::x::GetPropertyCookieUnchecked);
|
||||||
|
|
||||||
|
impl $request {
|
||||||
|
fn new(window: xcb::x::Window) -> $request {
|
||||||
|
$request(window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ewmh_get_property {
|
||||||
|
(request=$request:ident{
|
||||||
|
window: $window:ident,
|
||||||
|
property: $property:ident,
|
||||||
|
xtype: $xtype: ident
|
||||||
|
},
|
||||||
|
reply=$reply:ident) => {
|
||||||
|
paste!{
|
||||||
|
_get_property_structs! {@private $request, $window}
|
||||||
|
|
||||||
|
impl<'a> EwmhRequest<'a> for $request {
|
||||||
|
type XcbRequest = xcb::x::GetProperty;
|
||||||
|
type EwmhCookie = [<$request Cookie>];
|
||||||
|
|
||||||
|
_get_property_request! {@private $window, $property, $xtype}
|
||||||
|
|
||||||
|
fn convert_cookie(&'a self, xcb_cookie: xcb::x::GetPropertyCookie) -> Self::EwmhCookie {
|
||||||
|
[<$request Cookie>](xcb_cookie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhPropertyRequestUnchecked for $request {
|
||||||
|
paste!{type EwmhCookie = [<$request CookieUnchecked>];}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn convert_cookie(&self, xcb_cookie: xcb::x::GetPropertyCookieUnchecked) -> Self::EwmhCookie {
|
||||||
|
[<$request CookieUnchecked>](xcb_cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_property_request! {@private $window, $property, $xtype}
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_property_cookies! {@private $request, $reply}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,47 +0,0 @@
|
||||||
macro_rules! _client_message_base {
|
|
||||||
(root) => {
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
($destination: ident) => {
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
|
||||||
xcb::x::SendEvent {
|
|
||||||
propagate: false,
|
|
||||||
destination: xcb::x::SendEventDest::Window($destination),
|
|
||||||
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
|
||||||
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
|
||||||
event: &self.client_message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! ewmh_client_message {
|
|
||||||
(request=$request:ident{destination: $destination:ident}) => {
|
|
||||||
impl<'a> EwmhRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
|
|
||||||
type EwmhCookie = xcb::VoidCookie;
|
|
||||||
|
|
||||||
_client_message_base! {$destination}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
|
|
||||||
xcb_cookie
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> EwmhVoidRequestChecked<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
|
|
||||||
_client_message_base! {$destination}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
macro_rules! _get_property_cookies {
|
|
||||||
(@ewmh_priv $request:ident, $reply:ident) => {
|
|
||||||
paste! {
|
|
||||||
impl EwmhCookie for [<$request Cookie>] {
|
|
||||||
type XcbCookie = xcb::x::GetPropertyCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EwmhPropertyCookieChecked for [<$request Cookie>] {
|
|
||||||
type Reply = $reply;
|
|
||||||
|
|
||||||
fn inner(self) -> xcb::x::GetPropertyCookie {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EwmhPropertyCookieUnchecked for [<$request CookieUnchecked>] {
|
|
||||||
type Reply = $reply;
|
|
||||||
|
|
||||||
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! _get_property_request {
|
|
||||||
(@ewmh_priv root, $property:ident, UTF8_STRING) => {
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
|
||||||
xcb::x::GetProperty {
|
|
||||||
delete: false,
|
|
||||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: con.atoms.UTF8_STRING,
|
|
||||||
long_offset: 0,
|
|
||||||
long_length: u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(@ewmh_priv root, $property:ident, $xtype:ident) => {
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
|
||||||
xcb::x::GetProperty {
|
|
||||||
delete: false,
|
|
||||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: xcb::x::$xtype,
|
|
||||||
long_offset: 0,
|
|
||||||
long_length: u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(@ewmh_priv client, $property:ident, UTF8_STRING) => {
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
|
||||||
xcb::x::GetProperty {
|
|
||||||
delete: false,
|
|
||||||
window: self.0,
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: con.atoms.UTF8_STRING,
|
|
||||||
long_offset: 0,
|
|
||||||
long_length: u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(@ewmh_priv client, $property:ident, $xtype:ident) => {
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
|
||||||
xcb::x::GetProperty {
|
|
||||||
delete: false,
|
|
||||||
window: self.0,
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: xcb::x::$xtype,
|
|
||||||
long_offset: 0,
|
|
||||||
long_length: u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! _get_property_structs {
|
|
||||||
(@ewmh_priv $request:ident, root) => {
|
|
||||||
paste! {
|
|
||||||
pub struct $request;
|
|
||||||
pub struct [<$request Cookie>](xcb::x::GetPropertyCookie);
|
|
||||||
pub struct [<$request CookieUnchecked>](xcb::x::GetPropertyCookieUnchecked);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(@ewmh_priv $request:ident, client) => {
|
|
||||||
paste! {
|
|
||||||
pub struct $request(xcb::x::Window);
|
|
||||||
pub struct [<$request Cookie>](xcb::x::GetPropertyCookie);
|
|
||||||
pub struct [<$request CookieUnchecked>](xcb::x::GetPropertyCookieUnchecked);
|
|
||||||
|
|
||||||
impl $request {
|
|
||||||
fn new(window: xcb::x::Window) -> $request {
|
|
||||||
$request(window)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! ewmh_get_property {
|
|
||||||
(request=$request:ident{
|
|
||||||
window: $window:ident,
|
|
||||||
property: $property:ident,
|
|
||||||
xtype: $xtype: ident
|
|
||||||
},
|
|
||||||
reply=$reply:ident) => {
|
|
||||||
paste!{
|
|
||||||
_get_property_structs! {@ewmh_priv $request, $window}
|
|
||||||
|
|
||||||
impl<'a> EwmhRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::GetProperty;
|
|
||||||
type EwmhCookie = [<$request Cookie>];
|
|
||||||
|
|
||||||
_get_property_request! {@ewmh_priv $window, $property, $xtype}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::x::GetPropertyCookie) -> Self::EwmhCookie {
|
|
||||||
[<$request Cookie>](xcb_cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EwmhPropertyRequestUnchecked for $request {
|
|
||||||
paste!{type EwmhCookie = [<$request CookieUnchecked>];}
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn convert_cookie(&self, xcb_cookie: xcb::x::GetPropertyCookieUnchecked) -> Self::EwmhCookie {
|
|
||||||
[<$request CookieUnchecked>](xcb_cookie)
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_property_request! {@ewmh_priv $window, $property, $xtype}
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_property_cookies! {@ewmh_priv $request, $reply}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
mod get_property;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod set_property;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod client_message;
|
|
|
@ -1,132 +0,0 @@
|
||||||
macro_rules! _set_property_base {
|
|
||||||
(root, $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: con.con.get_setup().roots().next().unwrap().root(),
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: con.atoms.UTF8_STRING,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(root, $property:ident, $xtype:ident) => {
|
|
||||||
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(),
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: xcb::x::$xtype,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(client, $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: self.window,
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: con.atoms.UTF8_STRING,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(client, $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: self.window,
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: xcb::x::ATOM_CARDINAL,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(client, $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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! ewmh_set_property {
|
|
||||||
(request=$request:ident{
|
|
||||||
window: $window:ident,
|
|
||||||
property: $property:ident,
|
|
||||||
xtype: UTF8_STRING
|
|
||||||
}) => {
|
|
||||||
impl<'a> EwmhRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
|
|
||||||
type EwmhCookie = xcb::VoidCookie;
|
|
||||||
|
|
||||||
_set_property_base! {$window, $property, UTF8_STRING}
|
|
||||||
|
|
||||||
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, u8>;
|
|
||||||
|
|
||||||
_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 }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -81,7 +81,7 @@ ewmh_get_property! {
|
||||||
property: _NET_CLIENT_LIST_STACKING,
|
property: _NET_CLIENT_LIST_STACKING,
|
||||||
xtype: ATOM_WINDOW
|
xtype: ATOM_WINDOW
|
||||||
},
|
},
|
||||||
reply=GetClientListStackingReply
|
reply=GetClientListStackingReply,
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -109,13 +109,13 @@ ewmh_get_property! {
|
||||||
reply=GetNumberOfDesktopsReply
|
reply=GetNumberOfDesktopsReply
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendNumberOfDesktops {
|
pub struct SetNumberOfDesktops {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendNumberOfDesktops {
|
impl SetNumberOfDesktops {
|
||||||
pub fn new(connection: &Connection, desktops: u32) -> SendNumberOfDesktops {
|
pub fn new(connection: &Connection, desktops: u32) -> SetNumberOfDesktops {
|
||||||
SendNumberOfDesktops {
|
SetNumberOfDesktops {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
connection.con.get_setup().roots().next().unwrap().root(),
|
connection.con.get_setup().roots().next().unwrap().root(),
|
||||||
connection.atoms._NET_NUMBER_OF_DESKTOPS,
|
connection.atoms._NET_NUMBER_OF_DESKTOPS,
|
||||||
|
@ -126,7 +126,7 @@ impl SendNumberOfDesktops {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendNumberOfDesktops{destination: root}
|
request=SetNumberOfDesktops{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -156,13 +156,13 @@ ewmh_get_property! {
|
||||||
reply=GetDesktopGeometryReply
|
reply=GetDesktopGeometryReply
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendDesktopGeometry {
|
pub struct SetDesktopGeometry {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendDesktopGeometry {
|
impl SetDesktopGeometry {
|
||||||
pub fn new(connection: &Connection, width: u32, height: u32) -> SendDesktopGeometry {
|
pub fn new(connection: &Connection, width: u32, height: u32) -> SetDesktopGeometry {
|
||||||
SendDesktopGeometry {
|
SetDesktopGeometry {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
connection.con.get_setup().roots().next().unwrap().root(),
|
connection.con.get_setup().roots().next().unwrap().root(),
|
||||||
connection.atoms._NET_DESKTOP_GEOMETRY,
|
connection.atoms._NET_DESKTOP_GEOMETRY,
|
||||||
|
@ -173,8 +173,9 @@ impl SendDesktopGeometry {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendDesktopGeometry{destination: root}
|
request=SetDesktopGeometry{destination: root_window}
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// _NET_DESTKOP_VIEWPORT x, y, CARDINAL[][2]/32
|
// _NET_DESTKOP_VIEWPORT x, y, CARDINAL[][2]/32
|
||||||
|
@ -203,13 +204,13 @@ ewmh_get_property! {
|
||||||
reply=GetDesktopViewportReply
|
reply=GetDesktopViewportReply
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendDesktopViewport {
|
pub struct SetDesktopViewport {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendDesktopViewport {
|
impl SetDesktopViewport {
|
||||||
pub fn new(connection: &Connection, x: u32, y: u32) -> SendDesktopViewport {
|
pub fn new(connection: &Connection, x: u32, y: u32) -> SetDesktopViewport {
|
||||||
SendDesktopViewport {
|
SetDesktopViewport {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
connection.con.get_setup().roots().next().unwrap().root(),
|
connection.con.get_setup().roots().next().unwrap().root(),
|
||||||
connection.atoms._NET_DESKTOP_VIEWPORT,
|
connection.atoms._NET_DESKTOP_VIEWPORT,
|
||||||
|
@ -220,7 +221,7 @@ impl SendDesktopViewport {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendDesktopViewport{destination: root}
|
request=SetDesktopViewport{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -248,13 +249,13 @@ ewmh_get_property! {
|
||||||
reply=GetCurrentDesktopReply
|
reply=GetCurrentDesktopReply
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendCurrentDesktop {
|
pub struct SetCurrentDesktop {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendCurrentDesktop {
|
impl SetCurrentDesktop {
|
||||||
pub fn new(connection: &Connection, desktop: u32) -> SendCurrentDesktop {
|
pub fn new(connection: &Connection, desktop: u32) -> SetCurrentDesktop {
|
||||||
SendCurrentDesktop {
|
SetCurrentDesktop {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
connection.con.get_setup().roots().next().unwrap().root(),
|
connection.con.get_setup().roots().next().unwrap().root(),
|
||||||
connection.atoms._NET_CURRENT_DESKTOP,
|
connection.atoms._NET_CURRENT_DESKTOP,
|
||||||
|
@ -265,7 +266,7 @@ impl SendCurrentDesktop {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendCurrentDesktop{destination: root}
|
request=SetCurrentDesktop{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ impl SetDesktopNames {
|
||||||
|
|
||||||
ewmh_set_property! {
|
ewmh_set_property! {
|
||||||
request=SetDesktopNames{
|
request=SetDesktopNames{
|
||||||
window: root,
|
window: root_window,
|
||||||
property: _NET_DESKTOP_NAMES,
|
property: _NET_DESKTOP_NAMES,
|
||||||
xtype: UTF8_STRING
|
xtype: UTF8_STRING
|
||||||
}
|
}
|
||||||
|
@ -338,19 +339,19 @@ ewmh_get_property! {
|
||||||
reply=GetActiveWindowReply
|
reply=GetActiveWindowReply
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendActiveWindow {
|
pub struct SetActiveWindow {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendActiveWindow {
|
impl SetActiveWindow {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
connection: &Connection,
|
connection: &Connection,
|
||||||
window: xcb::x::Window,
|
window: xcb::x::Window,
|
||||||
source_indication: u32,
|
source_indication: u32,
|
||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
requestor_window: Option<xcb::x::Window>,
|
requestor_window: Option<xcb::x::Window>,
|
||||||
) -> SendActiveWindow {
|
) -> SetActiveWindow {
|
||||||
SendActiveWindow {
|
SetActiveWindow {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
window,
|
window,
|
||||||
connection.atoms._NET_ACTIVE_WINDOW,
|
connection.atoms._NET_ACTIVE_WINDOW,
|
||||||
|
@ -367,7 +368,7 @@ impl SendActiveWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendActiveWindow{destination: root}
|
request=SetActiveWindow{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
@ -493,7 +494,11 @@ pub struct GetShowingDesktopReply {
|
||||||
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 {
|
||||||
is_showing_desktop: { reply.value::<u32>()[0] == 1 },
|
is_showing_desktop: if reply.value::<u32>()[0] == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,24 +531,24 @@ impl SetShowingDesktop {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SetShowingDesktop{destination: root}
|
request=SetShowingDesktop{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// _NET_CLOSE_WINDOW
|
// _NET_CLOSE_WINDOW
|
||||||
// {{{
|
// {{{
|
||||||
pub struct SendCloseWindow {
|
pub struct CloseWindow {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendCloseWindow {
|
impl CloseWindow {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
connection: &Connection,
|
connection: &Connection,
|
||||||
window: xcb::x::Window,
|
window: xcb::x::Window,
|
||||||
source_indication: u32,
|
source_indication: u32,
|
||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
) -> SendCloseWindow {
|
) -> CloseWindow {
|
||||||
SendCloseWindow {
|
CloseWindow {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
window,
|
window,
|
||||||
connection.atoms._NET_CLOSE_WINDOW,
|
connection.atoms._NET_CLOSE_WINDOW,
|
||||||
|
@ -554,7 +559,7 @@ impl SendCloseWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendCloseWindow{destination: root}
|
request=CloseWindow{destination: root_window}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // _NET_MOVERESIZE_WINDOW
|
// // _NET_MOVERESIZE_WINDOW
|
||||||
|
@ -580,13 +585,13 @@ ewmh_client_message! {
|
||||||
//
|
//
|
||||||
// _NET_REQUEST_FRAME_EXTENTS
|
// _NET_REQUEST_FRAME_EXTENTS
|
||||||
// {{{
|
// {{{
|
||||||
pub struct SendRequestFrameExtents {
|
pub struct RequestFrameExtents {
|
||||||
client_message: xcb::x::ClientMessageEvent,
|
client_message: xcb::x::ClientMessageEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendRequestFrameExtents {
|
impl RequestFrameExtents {
|
||||||
pub fn new(connection: &Connection, window: xcb::x::Window) -> SendRequestFrameExtents {
|
pub fn new(connection: &Connection, window: xcb::x::Window) -> RequestFrameExtents {
|
||||||
SendRequestFrameExtents {
|
RequestFrameExtents {
|
||||||
client_message: xcb::x::ClientMessageEvent::new(
|
client_message: xcb::x::ClientMessageEvent::new(
|
||||||
window,
|
window,
|
||||||
connection.atoms._NET_REQUEST_FRAME_EXTENTS,
|
connection.atoms._NET_REQUEST_FRAME_EXTENTS,
|
||||||
|
@ -597,6 +602,6 @@ impl SendRequestFrameExtents {
|
||||||
}
|
}
|
||||||
|
|
||||||
ewmh_client_message! {
|
ewmh_client_message! {
|
||||||
request=SendRequestFrameExtents{destination: root}
|
request=RequestFrameExtents{destination: root_window}
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::ewmh::connection::Connection;
|
||||||
///
|
///
|
||||||
/// This is a bit mind-bending and makes these traits hard to grasp. This was however done to align
|
/// This is a bit mind-bending and makes these traits hard to grasp. This was however done to align
|
||||||
/// with how the parent [`xcb`] crate works.
|
/// with how the parent [`xcb`] crate works.
|
||||||
pub trait EwmhRequest<'a> {
|
pub(crate) trait EwmhRequest<'a> {
|
||||||
/// The underlying [`xcb::Request`] used to do the actual heavy lifting
|
/// The underlying [`xcb::Request`] used to do the actual heavy lifting
|
||||||
type XcbRequest: xcb::Request;
|
type XcbRequest: xcb::Request;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ pub trait EwmhRequest<'a> {
|
||||||
/// > errors using Connection::check_request.
|
/// > errors using Connection::check_request.
|
||||||
///
|
///
|
||||||
/// For [`xcb-wm`] this means either `SetProperty` or `ClientMessage` requests.
|
/// For [`xcb-wm`] this means either `SetProperty` or `ClientMessage` requests.
|
||||||
pub trait EwmhVoidRequestChecked<'a> {
|
pub(crate) trait EwmhVoidRequestChecked<'a> {
|
||||||
type XcbRequest: xcb::RequestWithoutReply;
|
type XcbRequest: xcb::RequestWithoutReply;
|
||||||
|
|
||||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
/// Construct the [`xcb::Request`]. This is implementation specific.
|
||||||
|
@ -69,7 +69,7 @@ pub trait EwmhVoidRequestChecked<'a> {
|
||||||
/// > be sent to the event loop
|
/// > be sent to the event loop
|
||||||
///
|
///
|
||||||
/// For [`xcb-wm`] this means a `GetProperty` requests.
|
/// For [`xcb-wm`] this means a `GetProperty` requests.
|
||||||
pub trait EwmhPropertyRequestUnchecked {
|
pub(crate) trait EwmhPropertyRequestUnchecked {
|
||||||
type EwmhCookie: EwmhPropertyCookieUnchecked;
|
type EwmhCookie: EwmhPropertyCookieUnchecked;
|
||||||
|
|
||||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
/// Construct the [`xcb::Request`]. This is implementation specific.
|
||||||
|
@ -99,7 +99,7 @@ pub trait EwmhPropertyRequestUnchecked {
|
||||||
///
|
///
|
||||||
/// At the same time it may have a _response_ for reply requests or it
|
/// At the same time it may have a _response_ for reply requests or it
|
||||||
/// may have no _response_ for void requests.
|
/// may have no _response_ for void requests.
|
||||||
pub trait EwmhCookie {
|
pub(crate) trait EwmhCookie {
|
||||||
/// The wrapped [`xcb::Cookie`]
|
/// The wrapped [`xcb::Cookie`]
|
||||||
type XcbCookie: xcb::Cookie;
|
type XcbCookie: xcb::Cookie;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ impl EwmhCookie for xcb::VoidCookie {
|
||||||
/// This is needed for 2 purposes:
|
/// This is needed for 2 purposes:
|
||||||
/// - Carry the reply type from the request to the retrieval of the response
|
/// - Carry the reply type from the request to the retrieval of the response
|
||||||
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply`]
|
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply`]
|
||||||
pub trait EwmhPropertyCookieChecked {
|
pub(crate) trait EwmhPropertyCookieChecked {
|
||||||
type Reply: EwmhPropertyReply;
|
type Reply: EwmhPropertyReply;
|
||||||
|
|
||||||
/// Retrieve the inner [`xcb::Cookie`]
|
/// Retrieve the inner [`xcb::Cookie`]
|
||||||
|
@ -134,7 +134,7 @@ pub trait EwmhPropertyCookieChecked {
|
||||||
/// This is needed for 2 purposes:
|
/// This is needed for 2 purposes:
|
||||||
/// - Carry the reply type from the request to the retrieval of the response
|
/// - Carry the reply type from the request to the retrieval of the response
|
||||||
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply_unchecked`]
|
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply_unchecked`]
|
||||||
pub trait EwmhPropertyCookieUnchecked {
|
pub(crate) trait EwmhPropertyCookieUnchecked {
|
||||||
type Reply: EwmhPropertyReply;
|
type Reply: EwmhPropertyReply;
|
||||||
|
|
||||||
/// Retrieve the inner [`xcb::Cookie`]
|
/// Retrieve the inner [`xcb::Cookie`]
|
||||||
|
@ -152,5 +152,5 @@ pub trait EwmhPropertyCookieUnchecked {
|
||||||
///
|
///
|
||||||
/// The connection between a ewmh request and the reply struct is made via ewmh property cookies
|
/// The connection between a ewmh request and the reply struct is made via ewmh property cookies
|
||||||
/// ([`EwmhPropertyCookieChecked`] and [`EwmhPropertyCookieUnchecked`]
|
/// ([`EwmhPropertyCookieChecked`] and [`EwmhPropertyCookieUnchecked`]
|
||||||
pub trait EwmhPropertyReply: From<xcb::x::GetPropertyReply> {}
|
pub(crate) trait EwmhPropertyReply: From<xcb::x::GetPropertyReply> {}
|
||||||
impl<T> EwmhPropertyReply for T where T: From<xcb::x::GetPropertyReply> {}
|
impl<T> EwmhPropertyReply for T where T: From<xcb::x::GetPropertyReply> {}
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
// TODO use xcb::atom_struct!{} for this?
|
|
||||||
const ATOM_NAMES: [&str; 1] = ["WM_COLORMAP_WINDOWS"];
|
|
||||||
|
|
||||||
/// Interned [`xcb::x::Atom`]s for the `icccm` protocol
|
|
||||||
///
|
|
||||||
/// The ids for these atoms are created when the [`crate::icccm::Connection`] is established. Hence,
|
|
||||||
/// are bound to the [`crate::icccm::Connection`] and can only be retrieved from there.
|
|
||||||
///
|
|
||||||
/// See also: [`icccm spec`](https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html)
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub struct Atoms {
|
|
||||||
pub WM_COLORMAP_WINDOWS: xcb::x::Atom,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Atoms {
|
|
||||||
pub(crate) fn intern(con: &xcb::Connection) -> Atoms {
|
|
||||||
let mut cookies: HashMap<&'static str, xcb::x::InternAtomCookie> = HashMap::new();
|
|
||||||
|
|
||||||
for atom in ATOM_NAMES {
|
|
||||||
let intern_atom = xcb::x::InternAtom {
|
|
||||||
only_if_exists: false,
|
|
||||||
name: atom.as_bytes(),
|
|
||||||
};
|
|
||||||
|
|
||||||
cookies.insert(atom, con.send_request(&intern_atom));
|
|
||||||
}
|
|
||||||
|
|
||||||
let interned_atoms: HashMap<&'static str, xcb::x::Atom> = cookies
|
|
||||||
.into_iter()
|
|
||||||
.map(|(atom_name, cookie)| (atom_name, con.wait_for_reply(cookie).unwrap()))
|
|
||||||
.map(|(atom_name, reply)| (atom_name, reply.atom()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Atoms::from_interned_atoms(interned_atoms)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_interned_atoms(mut atoms: HashMap<&'static str, xcb::x::Atom>) -> Atoms {
|
|
||||||
Atoms {
|
|
||||||
WM_COLORMAP_WINDOWS: atoms.remove("WM_COLORMAP_WINDOWS").unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,166 +0,0 @@
|
||||||
use crate::icccm::atoms::Atoms;
|
|
||||||
use crate::icccm::traits::{
|
|
||||||
IcccmPropertyCookieChecked, IcccmPropertyCookieUnchecked, IcccmPropertyRequestUnchecked,
|
|
||||||
IcccmRequest, IcccmVoidRequestChecked,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The main `icccm` entry point
|
|
||||||
///
|
|
||||||
/// `Connection` is a thin wrapper around [`xcb::Connection`]. It provides a
|
|
||||||
/// subset of the [`xcb::Connection`] API covering the functionality needed for
|
|
||||||
/// `icccm`.
|
|
||||||
///
|
|
||||||
/// The provided subset works the same as the corresponding API in
|
|
||||||
/// [`xcb::Connection`]. That is, methods with the same name do the same thing.
|
|
||||||
/// The general usage pattern is the same for both crates.
|
|
||||||
///
|
|
||||||
/// This wrapper is not strictly needed for `icccm` (ICCCM Atoms are pre-defined
|
|
||||||
/// in the core protocol [1]). However, to align with `ewmh` we provide the same
|
|
||||||
/// usage pattern/API as for `ewmh`.
|
|
||||||
///
|
|
||||||
/// [1] <https://www.x.org/releases/current/doc/xproto/x11protocol.html#Predefined_Atoms>
|
|
||||||
///
|
|
||||||
pub struct Connection<'a> {
|
|
||||||
pub(crate) con: &'a xcb::Connection,
|
|
||||||
|
|
||||||
/// Interned [`Atoms`] for the `icccm` protocol
|
|
||||||
pub atoms: Atoms,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl<'a> Connection<'a> {
|
|
||||||
pub fn connect(xcb_con: &'a xcb::Connection) -> Connection<'a> {
|
|
||||||
Connection {
|
|
||||||
con: xcb_con,
|
|
||||||
atoms: Atoms::intern(xcb_con),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_request<'b, R>(&self, request: &'b R) -> R::IcccmCookie
|
|
||||||
where
|
|
||||||
R: IcccmRequest<'b>,
|
|
||||||
{
|
|
||||||
request.send(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_request_checked<'b, R>(&self, request: &'b R) -> xcb::VoidCookieChecked
|
|
||||||
where
|
|
||||||
R: IcccmVoidRequestChecked<'b>,
|
|
||||||
{
|
|
||||||
request.send(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_request_unchecked<R>(&self, request: &R) -> R::IcccmCookie
|
|
||||||
where
|
|
||||||
R: IcccmPropertyRequestUnchecked,
|
|
||||||
{
|
|
||||||
request.send(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait_for_reply<C>(&self, cookie: C) -> C::Reply
|
|
||||||
where
|
|
||||||
C: IcccmPropertyCookieChecked,
|
|
||||||
{
|
|
||||||
let xcb_reply = self.con.wait_for_reply(cookie.inner());
|
|
||||||
xcb_reply.unwrap().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait_for_reply_unchecked<C>(&self, cookie: C) -> C::Reply
|
|
||||||
where
|
|
||||||
C: IcccmPropertyCookieUnchecked,
|
|
||||||
{
|
|
||||||
let xcb_reply = self.con.wait_for_reply_unchecked(cookie.inner());
|
|
||||||
xcb_reply.unwrap().unwrap().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::icccm::proto::{
|
|
||||||
GetWmHints, GetWmNormalHints, SetWmHints, SetWmName, SetWmNormalHints, WmSizeHints,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn number_of_desktops() {
|
|
||||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
|
||||||
let icccm_con = crate::icccm::Connection::connect(&xcb_con);
|
|
||||||
|
|
||||||
use xcb::XidNew;
|
|
||||||
|
|
||||||
let window = unsafe { xcb::x::Window::new(0x2e0013e) };
|
|
||||||
|
|
||||||
let request = crate::icccm::proto::GetWmName::new(window);
|
|
||||||
let cookie = icccm_con.send_request(&request);
|
|
||||||
let reply = icccm_con.wait_for_reply(cookie);
|
|
||||||
println!("{:?}", reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn set_number_of_desktops() {
|
|
||||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
|
||||||
let icccm_con = crate::icccm::Connection::connect(&xcb_con);
|
|
||||||
|
|
||||||
use xcb::XidNew;
|
|
||||||
|
|
||||||
let window = unsafe { xcb::x::Window::new(0x4600003) };
|
|
||||||
let name = String::from("NEW NAME").into_bytes();
|
|
||||||
|
|
||||||
let request = SetWmName::new(window, xcb::x::ATOM_STRING, name);
|
|
||||||
let cookie = icccm_con.send_request_checked(&request);
|
|
||||||
let reply = xcb_con.check_request(cookie);
|
|
||||||
println!("{:?}", reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_wm_normal_hints() {
|
|
||||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
|
||||||
let icccm_con = crate::icccm::Connection::connect(&xcb_con);
|
|
||||||
|
|
||||||
use xcb::XidNew;
|
|
||||||
|
|
||||||
let window = unsafe { xcb::x::Window::new(0x440013e) };
|
|
||||||
|
|
||||||
let request = GetWmNormalHints::new(window);
|
|
||||||
let cookie = icccm_con.send_request(&request);
|
|
||||||
let reply = icccm_con.wait_for_reply(cookie);
|
|
||||||
println!("{:?}", reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_wm_hints() {
|
|
||||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
|
||||||
let icccm_con = crate::icccm::Connection::connect(&xcb_con);
|
|
||||||
|
|
||||||
use xcb::XidNew;
|
|
||||||
|
|
||||||
let window = unsafe { xcb::x::Window::new(0x3c0013e) };
|
|
||||||
|
|
||||||
let request = GetWmHints::new(window);
|
|
||||||
let cookie = icccm_con.send_request(&request);
|
|
||||||
let reply = icccm_con.wait_for_reply(cookie);
|
|
||||||
println!("{:?}", reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn set_urgent() {
|
|
||||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
|
||||||
let icccm_con = crate::icccm::Connection::connect(&xcb_con);
|
|
||||||
|
|
||||||
use xcb::XidNew;
|
|
||||||
|
|
||||||
let window = unsafe { xcb::x::Window::new(0x3c0013e) };
|
|
||||||
|
|
||||||
let request = GetWmHints::new(window);
|
|
||||||
let cookie = icccm_con.send_request(&request);
|
|
||||||
let reply = icccm_con.wait_for_reply(cookie);
|
|
||||||
println!("{:?}", reply);
|
|
||||||
|
|
||||||
let mut wm_hints = reply.size_hints;
|
|
||||||
wm_hints.toggle_urgent();
|
|
||||||
|
|
||||||
let urgent = SetWmHints::new(window, &mut wm_hints);
|
|
||||||
let cookie = icccm_con.send_request_checked(&urgent);
|
|
||||||
let reply = xcb_con.check_request(cookie);
|
|
||||||
println!("{:?}", reply);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
//! Request and response definitions for the icccm protocol
|
|
||||||
//!
|
|
||||||
//! see: <https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html>
|
|
||||||
|
|
||||||
mod traits;
|
|
||||||
|
|
||||||
mod atoms;
|
|
||||||
|
|
||||||
mod connection;
|
|
||||||
pub use connection::Connection;
|
|
||||||
|
|
||||||
pub mod proto;
|
|
|
@ -1,674 +0,0 @@
|
||||||
//! Client Properties
|
|
||||||
//!
|
|
||||||
//! see: <https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html#Client_Properties>
|
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use bitflags::bitflags;
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::mem;
|
|
||||||
use xcb::{Xid, XidNew};
|
|
||||||
|
|
||||||
use crate::icccm::traits::*;
|
|
||||||
use crate::icccm::Connection;
|
|
||||||
|
|
||||||
use paste::paste; // Needed for macros
|
|
||||||
|
|
||||||
// WM_NAME, TEXT
|
|
||||||
// {{{
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmNameReply {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmNameReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
let x = reply.value::<u8>().into();
|
|
||||||
GetWmNameReply {
|
|
||||||
// TODO Compound string
|
|
||||||
name: String::from_utf8(x).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmName{
|
|
||||||
window: client,
|
|
||||||
property: ATOM_WM_NAME,
|
|
||||||
xtype: ATOM_ANY
|
|
||||||
},
|
|
||||||
reply=GetWmNameReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmName<T: xcb::x::PropEl> {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
encoding: xcb::x::Atom,
|
|
||||||
data: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: xcb::x::PropEl> SetWmName<T> {
|
|
||||||
pub fn new(window: xcb::x::Window, encoding: xcb::x::Atom, name: Vec<T>) -> SetWmName<T> {
|
|
||||||
SetWmName {
|
|
||||||
window: window,
|
|
||||||
encoding: encoding,
|
|
||||||
data: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_text_property! {
|
|
||||||
request=SetWmName{
|
|
||||||
property: ATOM_WM_NAME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// WM_ICON_NAME, TEXT
|
|
||||||
// {{{
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmIconNameReply {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmIconNameReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
let x = reply.value::<u8>().into();
|
|
||||||
GetWmIconNameReply {
|
|
||||||
// TODO Compound string
|
|
||||||
name: String::from_utf8(x).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmIconName{
|
|
||||||
window: client,
|
|
||||||
property: ATOM_WM_ICON_NAME,
|
|
||||||
xtype: ATOM_ANY
|
|
||||||
},
|
|
||||||
reply=GetWmIconNameReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmIconName<T: xcb::x::PropEl> {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
encoding: xcb::x::Atom,
|
|
||||||
data: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: xcb::x::PropEl> SetWmIconName<T> {
|
|
||||||
pub fn new(window: xcb::x::Window, encoding: xcb::x::Atom, name: Vec<T>) -> SetWmIconName<T> {
|
|
||||||
SetWmIconName {
|
|
||||||
window: window,
|
|
||||||
encoding: encoding,
|
|
||||||
data: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_text_property! {
|
|
||||||
request=SetWmIconName{
|
|
||||||
property: ATOM_WM_ICON_NAME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// WM_COLORMAP_WINDOWS, WINDOW[]/32
|
|
||||||
// {{{
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmColorMapWindowsReply {
|
|
||||||
pub windows: Vec<xcb::x::Window>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmColorMapWindowsReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
GetWmColorMapWindowsReply {
|
|
||||||
windows: reply.value().into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmColorMapWindows {
|
|
||||||
window: client,
|
|
||||||
property: WM_COLORMAP_WINDOWS,
|
|
||||||
xtype: ATOM_WINDOW
|
|
||||||
},
|
|
||||||
reply=GetWmIconNameReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmColorMapWindows {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
data: Vec<xcb::x::Window>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetWmColorMapWindows {
|
|
||||||
pub fn new(
|
|
||||||
window: xcb::x::Window,
|
|
||||||
colormap_windows: Vec<xcb::x::Window>,
|
|
||||||
) -> SetWmColorMapWindows {
|
|
||||||
SetWmColorMapWindows {
|
|
||||||
window: window,
|
|
||||||
data: colormap_windows,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_property! {
|
|
||||||
request=SetWmColorMapWindows{
|
|
||||||
property: con.WM_COLORMAP_WINDOWS,
|
|
||||||
xtype: ATOM_WINDOW
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// WM_CLIENT_MACHINE, TEXT
|
|
||||||
// {{{
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmClientMachineReply {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmClientMachineReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
let x = reply.value::<u8>().into();
|
|
||||||
GetWmClientMachineReply {
|
|
||||||
// TODO Compound string
|
|
||||||
name: String::from_utf8(x).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmClientMachine{
|
|
||||||
window: client,
|
|
||||||
property: ATOM_WM_CLIENT_MACHINE,
|
|
||||||
xtype: ATOM_ANY
|
|
||||||
},
|
|
||||||
reply=GetWmClientMachineReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmClientMachine<T: xcb::x::PropEl> {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
encoding: xcb::x::Atom,
|
|
||||||
data: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: xcb::x::PropEl> SetWmClientMachine<T> {
|
|
||||||
pub fn new(
|
|
||||||
window: xcb::x::Window,
|
|
||||||
encoding: xcb::x::Atom,
|
|
||||||
name: Vec<T>,
|
|
||||||
) -> SetWmClientMachine<T> {
|
|
||||||
SetWmClientMachine {
|
|
||||||
window: window,
|
|
||||||
encoding: encoding,
|
|
||||||
data: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_text_property! {
|
|
||||||
request=SetWmClientMachine{
|
|
||||||
property: ATOM_WM_CLIENT_MACHINE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// WM_TRANSIENT_FOR, WINDOW/32
|
|
||||||
// {{{
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmTransientForReply {
|
|
||||||
pub window: xcb::x::Window,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmTransientForReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
GetWmTransientForReply {
|
|
||||||
window: unsafe { xcb::x::Window::new(reply.value::<u32>()[0]) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmTransientFor{
|
|
||||||
window: client,
|
|
||||||
property: ATOM_WM_TRANSIENT_FOR,
|
|
||||||
xtype: ATOM_WINDOW
|
|
||||||
},
|
|
||||||
reply=GetWmTransientForReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmTransientFor {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
data: Vec<xcb::x::Window>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetWmTransientFor {
|
|
||||||
// TODO better name for second window
|
|
||||||
pub fn new(window: xcb::x::Window, window2: xcb::x::Window) -> SetWmTransientFor {
|
|
||||||
SetWmTransientFor {
|
|
||||||
window: window,
|
|
||||||
data: vec![window2],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_property! {
|
|
||||||
request=SetWmTransientFor{
|
|
||||||
property: ATOM_WM_CLIENT_MACHINE,
|
|
||||||
xtype: ATOM_WINDOW
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// WM_NORMAL_HINTS, WM_SIZE_HINTS/32
|
|
||||||
// {{{
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
struct WmSizeHintsFlags: u32 {
|
|
||||||
const None = 0b0000_0000_0000;
|
|
||||||
const USPosition = 0b0000_0000_0001;
|
|
||||||
const USSize = 0b0000_0000_0010;
|
|
||||||
const PPosition = 0b0000_0000_0100;
|
|
||||||
const PSize = 0b0000_0000_1000;
|
|
||||||
const PMinSize = 0b0000_0001_0000;
|
|
||||||
const PMaxSize = 0b0000_0010_0000;
|
|
||||||
const PResizeInc = 0b0000_0100_0000;
|
|
||||||
const PAspect = 0b0000_1000_0000;
|
|
||||||
const PBaseSize = 0b0001_0000_0000;
|
|
||||||
const PWinGravity = 0b0010_0000_0000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WmSizeHints {
|
|
||||||
flags: WmSizeHintsFlags,
|
|
||||||
x: u32,
|
|
||||||
y: u32,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
min_width: u32,
|
|
||||||
min_height: u32,
|
|
||||||
max_width: u32,
|
|
||||||
max_height: u32,
|
|
||||||
width_inc: u32,
|
|
||||||
height_inc: u32,
|
|
||||||
min_aspect: (u32, u32),
|
|
||||||
max_aspect: (u32, u32),
|
|
||||||
base_width: u32,
|
|
||||||
base_height: u32,
|
|
||||||
win_gravity: xcb::x::Gravity,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for WmSizeHints {
|
|
||||||
fn default() -> Self {
|
|
||||||
WmSizeHints {
|
|
||||||
flags: WmSizeHintsFlags::None,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
min_width: 0,
|
|
||||||
min_height: 0,
|
|
||||||
max_width: 0,
|
|
||||||
max_height: 0,
|
|
||||||
width_inc: 0,
|
|
||||||
height_inc: 0,
|
|
||||||
min_aspect: (0, 0),
|
|
||||||
max_aspect: (0, 0),
|
|
||||||
base_width: 0,
|
|
||||||
base_height: 0,
|
|
||||||
win_gravity: xcb::x::Gravity::NorthWest,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WmSizeHints {
|
|
||||||
pub fn as_data(&mut self) -> Vec<u32> {
|
|
||||||
vec![
|
|
||||||
self.flags.bits,
|
|
||||||
self.x,
|
|
||||||
self.y,
|
|
||||||
self.width,
|
|
||||||
self.height,
|
|
||||||
self.min_width,
|
|
||||||
self.min_height,
|
|
||||||
self.max_width,
|
|
||||||
self.max_height,
|
|
||||||
self.width_inc,
|
|
||||||
self.height_inc,
|
|
||||||
self.min_aspect.0,
|
|
||||||
self.min_aspect.1,
|
|
||||||
self.max_aspect.0,
|
|
||||||
self.max_aspect.1,
|
|
||||||
self.base_width,
|
|
||||||
self.base_height,
|
|
||||||
self.win_gravity as u32,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_reply(reply: xcb::x::GetPropertyReply) -> WmSizeHints {
|
|
||||||
let packed_vals = reply.value::<u32>();
|
|
||||||
WmSizeHints {
|
|
||||||
flags: WmSizeHintsFlags::from_bits_truncate(packed_vals[0]),
|
|
||||||
x: packed_vals[1],
|
|
||||||
y: packed_vals[2],
|
|
||||||
width: packed_vals[3],
|
|
||||||
height: packed_vals[4],
|
|
||||||
min_width: packed_vals[5],
|
|
||||||
min_height: packed_vals[6],
|
|
||||||
max_width: packed_vals[7],
|
|
||||||
max_height: packed_vals[8],
|
|
||||||
width_inc: packed_vals[9],
|
|
||||||
height_inc: packed_vals[10],
|
|
||||||
min_aspect: (packed_vals[11], packed_vals[12]),
|
|
||||||
max_aspect: (packed_vals[13], packed_vals[14]),
|
|
||||||
base_width: packed_vals[15],
|
|
||||||
base_height: packed_vals[16],
|
|
||||||
win_gravity: unsafe { std::mem::transmute(packed_vals[17]) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn position(&mut self, user_specified: bool, x: u32, y: u32) {
|
|
||||||
// reset
|
|
||||||
self.flags &= !(WmSizeHintsFlags::USPosition | WmSizeHintsFlags::PPosition);
|
|
||||||
|
|
||||||
if user_specified {
|
|
||||||
self.flags |= WmSizeHintsFlags::USPosition
|
|
||||||
} else {
|
|
||||||
self.flags |= WmSizeHintsFlags::PPosition
|
|
||||||
}
|
|
||||||
|
|
||||||
self.x = x;
|
|
||||||
self.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(&mut self, user_specified: bool, width: u32, height: u32) {
|
|
||||||
// reset
|
|
||||||
self.flags &= !(WmSizeHintsFlags::USSize | WmSizeHintsFlags::PSize);
|
|
||||||
|
|
||||||
if user_specified {
|
|
||||||
self.flags |= WmSizeHintsFlags::USSize
|
|
||||||
} else {
|
|
||||||
self.flags |= WmSizeHintsFlags::PSize
|
|
||||||
}
|
|
||||||
|
|
||||||
self.width = width;
|
|
||||||
self.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn min_size(&mut self, min_width: u32, min_height: u32) {
|
|
||||||
self.flags |= WmSizeHintsFlags::PMinSize;
|
|
||||||
|
|
||||||
self.min_width = min_width;
|
|
||||||
self.min_height = min_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn max_size(&mut self, max_width: u32, max_height: u32) {
|
|
||||||
self.flags |= WmSizeHintsFlags::PMaxSize;
|
|
||||||
|
|
||||||
self.max_width = max_width;
|
|
||||||
self.max_height = max_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize_inc(&mut self, width_inc: u32, height_inc: u32) {
|
|
||||||
self.flags |= WmSizeHintsFlags::PResizeInc;
|
|
||||||
|
|
||||||
self.width_inc = width_inc;
|
|
||||||
self.height_inc = height_inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn aspect(&mut self, min_aspect: (u32, u32), max_aspect: (u32, u32)) {
|
|
||||||
self.flags |= WmSizeHintsFlags::PAspect;
|
|
||||||
|
|
||||||
self.min_aspect = min_aspect;
|
|
||||||
self.max_aspect = max_aspect;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn base_size(&mut self, base_width: u32, base_height: u32) {
|
|
||||||
self.flags |= WmSizeHintsFlags::PBaseSize;
|
|
||||||
|
|
||||||
self.base_width = base_width;
|
|
||||||
self.base_height = base_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn win_gravity(&mut self, win_gravity: xcb::x::Gravity) {
|
|
||||||
self.flags |= WmSizeHintsFlags::PWinGravity;
|
|
||||||
|
|
||||||
self.win_gravity = win_gravity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmNormalHintsReply {
|
|
||||||
pub size_hints: WmSizeHints,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmNormalHintsReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
GetWmNormalHintsReply {
|
|
||||||
size_hints: WmSizeHints::from_reply(reply),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmNormalHints{
|
|
||||||
window: client,
|
|
||||||
property: ATOM_WM_NORMAL_HINTS,
|
|
||||||
xtype: ATOM_WM_SIZE_HINTS
|
|
||||||
},
|
|
||||||
reply=GetWmNormalHintsReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmNormalHints {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
data: Vec<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetWmNormalHints {
|
|
||||||
pub fn new(window: xcb::x::Window, size_hints: &mut WmSizeHints) -> SetWmNormalHints {
|
|
||||||
SetWmNormalHints {
|
|
||||||
window: window,
|
|
||||||
data: size_hints.as_data(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_hint_property! {
|
|
||||||
request=SetWmNormalHints{
|
|
||||||
property: ATOM_WM_NORMAL_HINTS,
|
|
||||||
xtype: ATOM_WM_SIZE_HINTS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// WM_HINTS, WM_HINTS//32
|
|
||||||
// {{{
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
struct WmHintsFlags: u32 {
|
|
||||||
const None = 0b0000_0000_0000;
|
|
||||||
const InputHint = 0b0000_0000_0001;
|
|
||||||
const StateHint = 0b0000_0000_0010;
|
|
||||||
const IconPixmapHint = 0b0000_0000_0100;
|
|
||||||
const IconWindowHint = 0b0000_0000_1000;
|
|
||||||
const IconPositionHint = 0b0000_0001_0000;
|
|
||||||
const IconMaskHint = 0b0000_0010_0000;
|
|
||||||
const WindowGroupHint = 0b0000_0100_0000;
|
|
||||||
const MessageHint = 0b0000_1000_0000;
|
|
||||||
const UrgencyHint = 0b0001_0000_0000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
#[repr(u32)]
|
|
||||||
pub enum WmInitialState {
|
|
||||||
None = 4,
|
|
||||||
Withdrawn = 0,
|
|
||||||
Normal = 1,
|
|
||||||
Iconic = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WmHints {
|
|
||||||
flags: WmHintsFlags,
|
|
||||||
input: bool,
|
|
||||||
initial_state: WmInitialState,
|
|
||||||
icon_pixmap: xcb::x::Pixmap,
|
|
||||||
icon_window: xcb::x::Window,
|
|
||||||
icon_x: u32,
|
|
||||||
icon_y: u32,
|
|
||||||
icon_mask: xcb::x::Pixmap,
|
|
||||||
window_group: xcb::x::Window,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for WmHints {
|
|
||||||
fn default() -> Self {
|
|
||||||
WmHints {
|
|
||||||
flags: WmHintsFlags::None,
|
|
||||||
input: true,
|
|
||||||
initial_state: WmInitialState::None,
|
|
||||||
icon_pixmap: xcb::x::Pixmap::none(),
|
|
||||||
icon_window: xcb::x::Window::none(),
|
|
||||||
icon_x: 0,
|
|
||||||
icon_y: 0,
|
|
||||||
icon_mask: xcb::x::Pixmap::none(),
|
|
||||||
window_group: xcb::x::Window::none(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WmHints {
|
|
||||||
pub fn as_data(&mut self) -> Vec<u32> {
|
|
||||||
let initial_state = if self.flags.contains(WmHintsFlags::StateHint) {
|
|
||||||
self.initial_state as u32
|
|
||||||
} else {
|
|
||||||
0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
vec![
|
|
||||||
self.flags.bits,
|
|
||||||
self.input as u32,
|
|
||||||
initial_state,
|
|
||||||
self.icon_pixmap.resource_id(),
|
|
||||||
self.icon_window.resource_id(),
|
|
||||||
self.icon_x,
|
|
||||||
self.icon_y,
|
|
||||||
self.icon_mask.resource_id(),
|
|
||||||
self.window_group.resource_id(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_reply(reply: xcb::x::GetPropertyReply) -> WmHints {
|
|
||||||
let packed_vals = reply.value::<u32>();
|
|
||||||
let flags: WmHintsFlags = WmHintsFlags::from_bits_truncate(packed_vals[0]);
|
|
||||||
|
|
||||||
let initial_state = if flags.contains(WmHintsFlags::StateHint) {
|
|
||||||
unsafe { mem::transmute(packed_vals[2]) }
|
|
||||||
} else {
|
|
||||||
WmInitialState::None
|
|
||||||
};
|
|
||||||
|
|
||||||
WmHints {
|
|
||||||
flags: flags,
|
|
||||||
input: packed_vals[1] != 0,
|
|
||||||
initial_state: initial_state,
|
|
||||||
icon_pixmap: unsafe { xcb::x::Pixmap::new(packed_vals[3]) },
|
|
||||||
icon_window: unsafe { xcb::x::Window::new(packed_vals[4]) },
|
|
||||||
icon_x: packed_vals[5],
|
|
||||||
icon_y: packed_vals[6],
|
|
||||||
icon_mask: unsafe { xcb::x::Pixmap::new(packed_vals[7]) },
|
|
||||||
window_group: unsafe { xcb::x::Window::new(packed_vals[8]) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn input(&mut self, input: bool) {
|
|
||||||
self.flags |= WmHintsFlags::InputHint;
|
|
||||||
self.input = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initial_state(&mut self, state: WmInitialState) {
|
|
||||||
match state {
|
|
||||||
WmInitialState::None => {
|
|
||||||
self.flags &= !WmHintsFlags::StateHint;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.flags |= WmHintsFlags::StateHint;
|
|
||||||
self.initial_state = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn icon_pixmap(&mut self, pixmap: xcb::x::Pixmap) {
|
|
||||||
self.flags |= WmHintsFlags::IconPixmapHint;
|
|
||||||
self.icon_pixmap = pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn icon_mask(&mut self, mask: xcb::x::Pixmap) {
|
|
||||||
self.flags |= WmHintsFlags::IconMaskHint;
|
|
||||||
self.icon_mask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn icon_window(&mut self, window: xcb::x::Window) {
|
|
||||||
self.flags |= WmHintsFlags::IconWindowHint;
|
|
||||||
self.icon_window = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn window_group(&mut self, window: xcb::x::Window) {
|
|
||||||
self.flags |= WmHintsFlags::WindowGroupHint;
|
|
||||||
self.window_group = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggle_urgent(&mut self) {
|
|
||||||
self.flags.toggle(WmHintsFlags::UrgencyHint);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_urgent(&mut self) -> bool {
|
|
||||||
self.flags.contains(WmHintsFlags::UrgencyHint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GetWmHintsReply {
|
|
||||||
pub size_hints: WmHints,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xcb::x::GetPropertyReply> for GetWmHintsReply {
|
|
||||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
|
||||||
GetWmHintsReply {
|
|
||||||
size_hints: WmHints::from_reply(reply),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_get_property! {
|
|
||||||
request=GetWmHints{
|
|
||||||
window: client,
|
|
||||||
property: ATOM_WM_HINTS,
|
|
||||||
xtype: ATOM_WM_HINTS
|
|
||||||
},
|
|
||||||
reply=GetWmHintsReply
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetWmHints {
|
|
||||||
window: xcb::x::Window,
|
|
||||||
data: Vec<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetWmHints {
|
|
||||||
pub fn new(window: xcb::x::Window, hints: &mut WmHints) -> SetWmHints {
|
|
||||||
SetWmHints {
|
|
||||||
window: window,
|
|
||||||
data: hints.as_data(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icccm_set_hint_property! {
|
|
||||||
request=SetWmHints{
|
|
||||||
property: ATOM_WM_HINTS,
|
|
||||||
xtype: ATOM_WM_HINTS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }}}
|
|
|
@ -1,99 +0,0 @@
|
||||||
macro_rules! _get_property_cookies {
|
|
||||||
(@icccm_priv $request:ident, $reply:ident) => {
|
|
||||||
paste! {
|
|
||||||
impl IcccmCookie for [<$request Cookie>] {
|
|
||||||
type XcbCookie = xcb::x::GetPropertyCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IcccmPropertyCookieChecked for [<$request Cookie>] {
|
|
||||||
type Reply = $reply;
|
|
||||||
|
|
||||||
fn inner(self) -> xcb::x::GetPropertyCookie {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IcccmPropertyCookieUnchecked for [<$request CookieUnchecked>] {
|
|
||||||
type Reply = $reply;
|
|
||||||
|
|
||||||
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! _get_property_request {
|
|
||||||
//TODO do we need the `client` here? Probs just c&p
|
|
||||||
(@icccm_priv client, WM_COLORMAP_WINDOWS, $xtype:ident) => {
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
|
||||||
xcb::x::GetProperty {
|
|
||||||
delete: false,
|
|
||||||
window: self.0,
|
|
||||||
property: con.atoms.WM_COLORMAP_WINDOWS,
|
|
||||||
r#type: xcb::x::$xtype,
|
|
||||||
long_offset: 0,
|
|
||||||
long_length: u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(@icccm_priv client, $property:ident, $xtype:ident) => {
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
|
||||||
xcb::x::GetProperty {
|
|
||||||
delete: false,
|
|
||||||
window: self.0,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: xcb::x::$xtype,
|
|
||||||
long_offset: 0,
|
|
||||||
long_length: u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! icccm_get_property {
|
|
||||||
(request=$request:ident{
|
|
||||||
window: $window:ident,
|
|
||||||
property: $property:ident,
|
|
||||||
xtype: $xtype: ident
|
|
||||||
},
|
|
||||||
reply=$reply:ident) => {
|
|
||||||
paste!{
|
|
||||||
pub struct $request(xcb::x::Window);
|
|
||||||
pub struct [<$request Cookie>](xcb::x::GetPropertyCookie);
|
|
||||||
pub struct [<$request CookieUnchecked>](xcb::x::GetPropertyCookieUnchecked);
|
|
||||||
|
|
||||||
impl $request {
|
|
||||||
pub fn new(window: xcb::x::Window) -> $request {
|
|
||||||
$request(window)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IcccmRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::GetProperty;
|
|
||||||
type IcccmCookie = [<$request Cookie>];
|
|
||||||
|
|
||||||
_get_property_request! {@icccm_priv $window, $property, $xtype}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::x::GetPropertyCookie) -> Self::IcccmCookie {
|
|
||||||
[<$request Cookie>](xcb_cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IcccmPropertyRequestUnchecked for $request {
|
|
||||||
paste!{type IcccmCookie = [<$request CookieUnchecked>];}
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn convert_cookie(&self, xcb_cookie: xcb::x::GetPropertyCookieUnchecked) -> Self::IcccmCookie {
|
|
||||||
[<$request CookieUnchecked>](xcb_cookie)
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_property_request! {@icccm_priv $window, $property, $xtype}
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_property_cookies! {@icccm_priv $request, $reply}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
mod get_property;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod set_property;
|
|
|
@ -1,168 +0,0 @@
|
||||||
macro_rules! icccm_set_text_property {
|
|
||||||
(request=$request:ident{
|
|
||||||
property: $property:ident
|
|
||||||
}) => {
|
|
||||||
impl<'a, T: 'a + xcb::x::PropEl> IcccmRequest<'a> for $request<T> {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, T>;
|
|
||||||
type IcccmCookie = xcb::VoidCookie;
|
|
||||||
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, T> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: self.encoding,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::IcccmCookie {
|
|
||||||
xcb_cookie
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: 'a + xcb::x::PropEl> IcccmVoidRequestChecked<'a> for $request<T> {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, T>;
|
|
||||||
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, T> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: self.encoding,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! icccm_set_property {
|
|
||||||
(request=$request:ident{
|
|
||||||
property: con.$property:ident,
|
|
||||||
xtype: $type:ident
|
|
||||||
}) => {
|
|
||||||
impl<'a> IcccmRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, xcb::x::Window>;
|
|
||||||
type IcccmCookie = xcb::VoidCookie;
|
|
||||||
|
|
||||||
fn xcb_request(
|
|
||||||
&'a self,
|
|
||||||
con: &Connection,
|
|
||||||
) -> xcb::x::ChangeProperty<'a, xcb::x::Window> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: xcb::x::$type,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::IcccmCookie {
|
|
||||||
xcb_cookie
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IcccmVoidRequestChecked<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, xcb::x::Window>;
|
|
||||||
|
|
||||||
fn xcb_request(
|
|
||||||
&'a self,
|
|
||||||
con: &Connection,
|
|
||||||
) -> xcb::x::ChangeProperty<'a, xcb::x::Window> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: con.atoms.$property,
|
|
||||||
r#type: xcb::x::$type,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(request=$request:ident{
|
|
||||||
property: $property:ident,
|
|
||||||
xtype: $type:ident
|
|
||||||
}) => {
|
|
||||||
impl<'a> IcccmRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, xcb::x::Window>;
|
|
||||||
type IcccmCookie = xcb::VoidCookie;
|
|
||||||
|
|
||||||
fn xcb_request(
|
|
||||||
&'a self,
|
|
||||||
con: &Connection,
|
|
||||||
) -> xcb::x::ChangeProperty<'a, xcb::x::Window> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: xcb::x::$type,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::IcccmCookie {
|
|
||||||
xcb_cookie
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IcccmVoidRequestChecked<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, xcb::x::Window>;
|
|
||||||
|
|
||||||
fn xcb_request(
|
|
||||||
&'a self,
|
|
||||||
con: &Connection,
|
|
||||||
) -> xcb::x::ChangeProperty<'a, xcb::x::Window> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: xcb::x::$type,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! icccm_set_hint_property {
|
|
||||||
(request=$request:ident{
|
|
||||||
property: $property:ident,
|
|
||||||
xtype: $type:ident
|
|
||||||
}) => {
|
|
||||||
impl<'a> IcccmRequest<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, u32>;
|
|
||||||
type IcccmCookie = xcb::VoidCookie;
|
|
||||||
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: xcb::x::$type,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::IcccmCookie {
|
|
||||||
xcb_cookie
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IcccmVoidRequestChecked<'a> for $request {
|
|
||||||
type XcbRequest = xcb::x::ChangeProperty<'a, u32>;
|
|
||||||
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u32> {
|
|
||||||
xcb::x::ChangeProperty {
|
|
||||||
mode: xcb::x::PropMode::Replace,
|
|
||||||
window: self.window,
|
|
||||||
property: xcb::x::$property,
|
|
||||||
r#type: xcb::x::$type,
|
|
||||||
data: &self.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
//! Request and response definitions for the icccm protocol
|
|
||||||
//!
|
|
||||||
//! # Example
|
|
||||||
//! ```
|
|
||||||
//! let connection = xcb_wm::icccm::Connection();
|
|
||||||
//! let request = xcb_wm::ewmh::proto::GetSupported;
|
|
||||||
//! let cookie = connection.send_request(request);
|
|
||||||
//! let response = connection.wait_for_reply(cookie);
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
// mod application_props;
|
|
||||||
// #[allow(unused)]
|
|
||||||
// mod root_props;
|
|
||||||
//
|
|
||||||
// pub use application_props::*;
|
|
||||||
// pub use root_props::*;
|
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
mod client_props;
|
|
||||||
pub use client_props::*;
|
|
|
@ -1,156 +0,0 @@
|
||||||
use crate::icccm::connection::Connection;
|
|
||||||
|
|
||||||
/// Default for a request sent by [`Connection::send_request`]
|
|
||||||
///
|
|
||||||
/// For `GetProperty` request (i.e. requests that expect a reply) this is usually
|
|
||||||
/// a checked request.
|
|
||||||
/// For `SetProperty` and `ClientMessage` requests (i.e. requests that expect void/no reply) this
|
|
||||||
/// is usually an unchecked request.
|
|
||||||
///
|
|
||||||
/// This is a bit mind-bending and makes these traits hard to grasp. This was however done to align
|
|
||||||
/// with how the parent [`xcb`] crate works.
|
|
||||||
pub trait IcccmRequest<'a> {
|
|
||||||
/// The underlying [`xcb::Request`] used to do the actual heavy lifting
|
|
||||||
type XcbRequest: xcb::Request;
|
|
||||||
|
|
||||||
/// The icccm wrapper for the [`xcb::Request::Cookie`]
|
|
||||||
type IcccmCookie: IcccmCookie<XcbCookie = <Self::XcbRequest as xcb::Request>::Cookie>;
|
|
||||||
|
|
||||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest;
|
|
||||||
|
|
||||||
/// Convert the [`xcb::Request::Cookie`] to the icccm cookie wrapper
|
|
||||||
fn convert_cookie(
|
|
||||||
&'a self,
|
|
||||||
xcb_cookie: <Self::XcbRequest as xcb::Request>::Cookie,
|
|
||||||
) -> Self::IcccmCookie;
|
|
||||||
|
|
||||||
/// Default implementation. Delegate the request to the [`xcb::Connection`] and wrap the
|
|
||||||
/// response in the icccm cookie wrapper.
|
|
||||||
///
|
|
||||||
/// There is usually no need to override the provided default implementation.
|
|
||||||
fn send(&'a self, con: &Connection) -> Self::IcccmCookie {
|
|
||||||
let xcb_request = self.xcb_request(con);
|
|
||||||
let xcb_cookie = con.con.send_request(&xcb_request);
|
|
||||||
self.convert_cookie(xcb_cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Requests that can be sent by [`Connection::send_request_checked`]
|
|
||||||
///
|
|
||||||
/// To quote the parent [`xcb`]:
|
|
||||||
/// > Checked requests do not expect a reply, but the returned cookie can be used to check for
|
|
||||||
/// > errors using Connection::check_request.
|
|
||||||
///
|
|
||||||
/// For [`xcb-wm`] this means either `SetProperty` or `ClientMessage` requests.
|
|
||||||
pub trait IcccmVoidRequestChecked<'a> {
|
|
||||||
type XcbRequest: xcb::RequestWithoutReply;
|
|
||||||
|
|
||||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
|
||||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest;
|
|
||||||
|
|
||||||
/// Default implementation. Delegate the request to the [`xcb::Connection`].
|
|
||||||
///
|
|
||||||
/// Since we don't need to convert the reply we just re-use the [`xcb::VoidCookieChecked`]
|
|
||||||
/// without wrapping it.
|
|
||||||
///
|
|
||||||
/// There is usually no need to override the provided default implementation.
|
|
||||||
fn send(&'a self, con: &Connection) -> xcb::VoidCookieChecked {
|
|
||||||
let xcb_request = self.xcb_request(con);
|
|
||||||
con.con.send_request_checked(&xcb_request)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Requests that can be sent by [`Connection::send_request_unchecked`]
|
|
||||||
///
|
|
||||||
/// To quote the parent [`xcb`]:
|
|
||||||
/// > Unchecked requests expect a reply that is to be retrieved by Connection::wait_for_reply_unchecked.
|
|
||||||
/// > Unchecked means that the error is not checked when the reply is fetched. Instead, the error will
|
|
||||||
/// > be sent to the event loop
|
|
||||||
///
|
|
||||||
/// For [`xcb-wm`] this means a `GetProperty` requests.
|
|
||||||
pub trait IcccmPropertyRequestUnchecked {
|
|
||||||
type IcccmCookie: IcccmPropertyCookieUnchecked;
|
|
||||||
|
|
||||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
|
||||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty;
|
|
||||||
|
|
||||||
/// Convert the [`xcb::Request::Cookie`] to the ewmh cookie wrapper
|
|
||||||
fn convert_cookie(&self, xcb_cookie: xcb::x::GetPropertyCookieUnchecked) -> Self::IcccmCookie;
|
|
||||||
|
|
||||||
/// Default implementation. Delegate the request to the [`xcb::Connection`].
|
|
||||||
///
|
|
||||||
/// Returns a wrapped cookie that tracks the IcccmReply type which is needed
|
|
||||||
/// to convert the reply after it is retrieved via [`Connection::wait_for_reply_unchecked`].
|
|
||||||
///
|
|
||||||
/// There is usually no need to override the provided default implementation.
|
|
||||||
fn send(&self, con: &Connection) -> Self::IcccmCookie {
|
|
||||||
let xcb_request = self.xcb_request(con);
|
|
||||||
let xcb_cookie = con.con.send_request_unchecked(&xcb_request);
|
|
||||||
self.convert_cookie(xcb_cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Most generic icccm wrapper for an [`xcb::Cookie`]
|
|
||||||
///
|
|
||||||
/// This is needed for [`IcccmRequest`] which basically cuts through
|
|
||||||
/// all traits. I.e. it is an _unchecked_ request for void requests
|
|
||||||
/// but a _checked_ request for requests with replies.
|
|
||||||
///
|
|
||||||
/// At the same time it may have a _response_ for reply requests or it
|
|
||||||
/// may have no _response_ for void requests.
|
|
||||||
pub trait IcccmCookie {
|
|
||||||
/// The wrapped [`xcb::Cookie`]
|
|
||||||
type XcbCookie: xcb::Cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Blanket impl for [`xcb::VoidCookie`] (basically unchecked void cookies)
|
|
||||||
///
|
|
||||||
/// This is implemented here because there are no special icccm cookie wrapper
|
|
||||||
/// for SetProperty and ClientMessage requests needed. [`xcb::VoidCookie`] satisfies
|
|
||||||
/// all that is needed for [`icccm`]. In order to use it with [`IcccmRequest`] we need
|
|
||||||
/// this impl.
|
|
||||||
impl IcccmCookie for xcb::VoidCookie {
|
|
||||||
type XcbCookie = xcb::VoidCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// icccm wrapper for checked GetProperty requests
|
|
||||||
///
|
|
||||||
/// This is needed for 2 purposes:
|
|
||||||
/// - Carry the reply type from the request to the retrieval of the response
|
|
||||||
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply`]
|
|
||||||
pub trait IcccmPropertyCookieChecked {
|
|
||||||
type Reply: IcccmPropertyReply;
|
|
||||||
|
|
||||||
/// Retrieve the inner [`xcb::Cookie`]
|
|
||||||
///
|
|
||||||
/// This is needed for sending a [`xcb::Connection::wait_reply`] request which
|
|
||||||
/// expects the xcb cookie
|
|
||||||
fn inner(self) -> xcb::x::GetPropertyCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// icccm wrapper for unchecked GetProperty requests
|
|
||||||
///
|
|
||||||
/// This is needed for 2 purposes:
|
|
||||||
/// - Carry the reply type from the request to the retrieval of the response
|
|
||||||
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply_unchecked`]
|
|
||||||
pub trait IcccmPropertyCookieUnchecked {
|
|
||||||
type Reply: IcccmPropertyReply;
|
|
||||||
|
|
||||||
/// Retrieve the inner [`xcb::Cookie`]
|
|
||||||
///
|
|
||||||
/// This is needed for sending a [`xcb::Connection::wait_reply_unchecked`] request which
|
|
||||||
/// expects the xcb cookie
|
|
||||||
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Marker trait with blanket implementation for everything that implements
|
|
||||||
/// [`From<xcb::x::GetPropertyReply`].
|
|
||||||
///
|
|
||||||
/// The icccm property reply trait is used to convert a generic reply to a [`xcb::x::GetProperty`]
|
|
||||||
/// request to a specific icccm reply struct.
|
|
||||||
///
|
|
||||||
/// The connection between a icccm request and the reply struct is made via icccm property cookies
|
|
||||||
/// ([`IcccmPropertyCookieChecked`] and [`IcccmPropertyCookieUnchecked`]
|
|
||||||
pub trait IcccmPropertyReply: From<xcb::x::GetPropertyReply> {}
|
|
||||||
impl<T> IcccmPropertyReply for T where T: From<xcb::x::GetPropertyReply> {}
|
|
|
@ -4,9 +4,6 @@
|
||||||
#[cfg(feature = "ewmh")]
|
#[cfg(feature = "ewmh")]
|
||||||
pub mod ewmh;
|
pub mod ewmh;
|
||||||
|
|
||||||
#[cfg(feature = "icccm")]
|
|
||||||
pub mod icccm;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue