Expand description
Rust bindings to the XCB library.
The X protocol C-language Binding (XCB - https://xcb.freedesktop.org/) is a replacement for Xlib featuring a small footprint, latency hiding, direct access to the protocol, improved threading support, and extensibility.
The communication is established with the X server by the creation of a Connection object.
A client communicates with the server by sending requests. There are 2 types of requests:
- void requests: requests that do not expect an answer (e.g. x::ChangeProperty)
- non-void requests: requests that need a
Reply
(e.g. x::GetProperty)
Requests are passed to the server by filling a request structure e.g. x::CreateWindow and passing it to Connection::send_request.
The server can also communicate with clients by sending Event
s.
The client listens to events with calls such as Connection::wait_for_event
(blocking) or Connection::poll_for_event (non-blocking).
The x module contains definitions of the core X protocol. Each extension is defined in its own module such as xkb or render, and is activated by a cargo feature of the same name.
Example
Here is a walk-through of a simple xcb
client.
// we import the necessary modules (only the core X module in this application).
use xcb::{x};
// we need to import the `Xid` trait for the `resource_id` call down there.
use xcb::{Xid};
// Many xcb functions return a `xcb::Result` or compatible result.
fn main() -> xcb::Result<()> {
// Connect to the X server.
let (conn, screen_num) = xcb::Connection::connect(None)?;
// Fetch the `x::Setup` and get the main `x::Screen` object.
let setup = conn.get_setup();
let screen = setup.roots().nth(screen_num as usize).unwrap();
// Generate an `Xid` for the client window.
// The type inference is needed here.
let window: x::Window = conn.generate_id();
// We can now create a window. For this we pass a `Request`
// object to the `send_request_checked` method. The method
// returns a cookie that will be used to check for success.
let cookie = conn.send_request_checked(&x::CreateWindow {
depth: x::COPY_FROM_PARENT as u8,
wid: window,
parent: screen.root(),
x: 0,
y: 0,
width: 150,
height: 150,
border_width: 0,
class: x::WindowClass::InputOutput,
visual: screen.root_visual(),
// this list must be in same order than `Cw` enum order
value_list: &[
x::Cw::BackPixel(screen.white_pixel()),
x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS)
],
});
// We now check if the window creation worked.
// A cookie can't be cloned; it is moved to the function.
conn.check_request(cookie)?;
// Let's change the window title
let cookie = conn.send_request_checked(&x::ChangeProperty {
mode: x::PropMode::Replace,
window,
property: x::ATOM_WM_NAME,
r#type: x::ATOM_STRING,
data: b"My XCB Window",
});
// And check for success again
conn.check_request(cookie);
// We now show ("map" in X terminology) the window.
// This time we do not check for success, so we discard the cookie.
conn.send_request(&x::MapWindow {
window,
});
// We need a few atoms for our application.
// We send a few requests in a row and wait for the replies after.
let (wm_protocols, wm_del_window, wm_state, wm_state_maxv, wm_state_maxh) = {
let cookies = (
conn.send_request(&x::InternAtom {
only_if_exists: true,
name: b"WM_PROTOCOLS",
}),
conn.send_request(&x::InternAtom {
only_if_exists: true,
name: b"WM_DELETE_WINDOW",
}),
conn.send_request(&x::InternAtom {
only_if_exists: true,
name: b"_NET_WM_STATE",
}),
conn.send_request(&x::InternAtom {
only_if_exists: true,
name: b"_NET_WM_STATE_MAXIMIZED_VERT",
}),
conn.send_request(&x::InternAtom {
only_if_exists: true,
name: b"_NET_WM_STATE_MAXIMIZED_HORZ",
}),
);
(
conn.wait_for_reply(cookies.0)?.atom(),
conn.wait_for_reply(cookies.1)?.atom(),
conn.wait_for_reply(cookies.2)?.atom(),
conn.wait_for_reply(cookies.3)?.atom(),
conn.wait_for_reply(cookies.4)?.atom(),
)
};
// We now activate the window close event by sending the following request.
// If we don't do this we can still close the window by clicking on the "x" button,
// but the event loop is notified through a connection shutdown error.
conn.check_request(conn.send_request_checked(&x::ChangeProperty {
mode: x::PropMode::Replace,
window,
property: wm_protocols,
r#type: x::ATOM_ATOM,
data: &[wm_del_window],
}))?;
// Previous request was checked, so a flush is not necessary in this case.
// Otherwise, here is how to perform a connection flush.
conn.flush()?;
let mut maximized = false;
// We enter the main event loop
loop {
match conn.wait_for_event()? {
xcb::Event::X(x::Event::KeyPress(ev)) => {
if ev.detail() == 0x3a {
// The M key was pressed
// (M only on qwerty keyboards. Keymap support is done
// with the `xkb` extension and the `xkbcommon-rs` crate)
// We toggle maximized state, for this we send a message
// by building a `x::ClientMessageEvent` with the proper
// atoms and send it to the server.
let data = x::ClientMessageData::Data32([
if maximized { 0 } else { 1 },
wm_state_maxv.resource_id(),
wm_state_maxh.resource_id(),
0,
0,
]);
let event = x::ClientMessageEvent::new(window, wm_state, data);
let cookie = conn.send_request_checked(&x::SendEvent {
propagate: false,
destination: x::SendEventDest::Window(screen.root()),
event_mask: x::EventMask::STRUCTURE_NOTIFY,
event: &event,
});
conn.check_request(cookie)?;
// Same as before, if we don't check for error, we have to flush
// the connection.
// conn.flush()?;
maximized = !maximized;
} else if ev.detail() == 0x18 {
// Q (on qwerty)
// We exit the event loop (and the program)
break Ok(());
}
}
xcb::Event::X(x::Event::ClientMessage(ev)) => {
// We have received a message from the server
if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
if atom == wm_del_window.resource_id() {
// The received atom is "WM_DELETE_WINDOW".
// We can check here if the user needs to save before
// exit, or in our case, exit right away.
break Ok(());
}
}
}
_ => {}
}
}
}
Cargo features
The following Cargo features are available
xlib_xcb
This feature activates the use of xlib::Display
to connect to XCB, therefore making
available both Xlib and XCB functions to the same connection.
While XCB is sufficient to handle all communication with the X server, some things can
still only be done by Xlib. E.g. hardware initialization for OpenGL is done by Xlib only.
debug_atom_names
When this feature is activated, the fmt::Debug
implementation for x::Atom
will print
out the name of the atom in addition to its value.
E.g. the feature would turn Atom { res_id: 303 }
into Atom("Abs Pressure" ; 303)
.
This can be useful in situations where you are not sure which atom you have to intern in order to look up some data in a reply.
It should be noted that the feature sets global variable to have access to
the connection in the fmt::Debug
implementation, and that the Debug
print
have side effects (x::GetAtomName
requests) which can sometimes not be desirable.
The feature should therefore only be activated when needed.
Extension features
The following X extensions are activated by a cargo feature:
Extension name | Cargo feature |
---|---|
Composite | composite |
DAMAGE | damage |
DPMS | dpms |
DRI2 | dri2 |
DRI3 | dri3 |
Generic Event Extension | ge |
GLX | glx |
Present | present |
RANDR | randr |
RECORD | record |
RENDER | render |
X-Resource | res |
MIT-SCREEN-SAVER | screensaver |
SHAPE | shape |
MIT-SHM | shm |
SYNC | sync |
XEVIE | xevie |
XFree86-DRI | xf86dri |
XFree86-VidModeExtension | xf86vidmode |
XFIXES | xfixes |
XINERAMA | xinerama |
XInputExtension | xinput |
XKEYBOARD | xkb |
XpExtension | xprint |
SELinux | xselinux |
TEST | xtest |
XVideo | xv |
XVideo-MotionCompensation | xvmc |
Modules
The BIG-REQUESTS
extension.
The Composite
X extension.
The DAMAGE
X extension.
The DPMS
X extension.
The DRI2
X extension.
The DRI3
X extension.
Module for Foreign Function Interface bindings.
The Generic Event Extension
X extension.
The GLX
X extension.
The Present
X extension.
The RANDR
X extension.
The RECORD
X extension.
The RENDER
X extension.
The X-Resource
X extension.
The MIT-SCREEN-SAVER
X extension.
The SHAPE
X extension.
The MIT-SHM
X extension.
The SYNC
X extension.
The core X protocol definitions
The XC-MISC
extension.
The XEVIE
X extension.
The XFree86-DRI
X extension.
The XFree86-VidModeExtension
X extension.
The XFIXES
X extension.
The XINERAMA
X extension.
The XInputExtension
X extension.
The XKEYBOARD
X extension.
The XpExtension
X extension.
The SELinux
X extension.
The XTEST
X extension.
The XVideo
X extension.
The XVideo-MotionCompensation
X extension.
Macros
An helper macro that generate a struct of atoms.
Structs
Container for authentication information to connect to the X server
Connection
is the central object of XCB.
Display info returned by parse_display
Extension data as returned by each extensions get_extension_data
.
A slice to a Latin-1 (aka. ISO 8859-1) string.
Latin-1 (aka. ISO 8859-1) of fixed size
A struct owning a Latin-1 (aka. ISO 8859-1) string.
A struct that serve as an identifier for internal special queue in XCB
an event was not recognized as part of the core protocol or any enabled extension
The default cookie type returned by void-requests.
The checked cookie type returned by void-requests.
Enums
Error type that is returned by Connection::has_error
.
The general error type for Rust-XCB.
Unified Event type from the X server.
Determines whether Xlib or XCB owns the event queue of Connection
.
Refers to a X protocol extension.
Error that can produce Latin-1 string operations
A protocol error issued from the X server
Traits
A trait to designate base protocol errors.
Trait for base events (aka. non GE_GENERIC events)
General trait for cookies returned by requests.
A marker trait for a cookie that allows synchronized error checking.
A trait for checked cookies of requests that send a reply.
A trait for unchecked cookies of requests that send a reply.
A trait for GE_GENERIC events
Trait for types that own a C allocated pointer and are represented by the data pointed to.
Trait implemented by all requests to send the serialized data over the wire.
Trait for request replies
Trait implemented by requests types.
Trait for requests that return a reply.
Marker trait for requests that do not return a reply.
A X resource trait
Trait for X resources that can be created directly from Connection::generate_id
Functions
Parses a display string in the form documented by X (7x).
Type Definitions
The result type associated with ConnError.
The result type associated with ProtocolError.
The general result type for Rust-XCB.