Crate xcb

Source
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:

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 Events. 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.

§libxcb_v1_14

This feature is enabled by default and activates the libxcb API version 1.14. To use a version of the libxcb API prior to 1.14, you must disable it.

§Extension features

The following X extensions are activated by a cargo feature:

Extension nameCargo feature
Compositecomposite
DAMAGEdamage
DPMSdpms
DRI2dri2
DRI3dri3
Generic Event Extensionge
GLXglx
Presentpresent
RANDRrandr
RECORDrecord
RENDERrender
X-Resourceres
MIT-SCREEN-SAVERscreensaver
SHAPEshape
MIT-SHMshm
SYNCsync
XEVIExevie
XFree86-DRIxf86dri
XFree86-VidModeExtensionxf86vidmode
XFIXESxfixes
XINERAMAxinerama
XInputExtensionxinput
XKEYBOARDxkb
XpExtensionxprint
SELinuxxselinux
TESTxtest
XVideoxv
XVideo-MotionCompensationxvmc

Modules§

bigreq
The BIG-REQUESTS extension.
composite
The Composite X extension.
damage
The DAMAGE X extension.
dpms
The DPMS X extension.
dri2
The DRI2 X extension.
dri3
The DRI3 X extension.
ffi
Module for Foreign Function Interface bindings.
ge
The Generic Event Extension X extension.
glx
The GLX X extension.
present
The Present X extension.
randr
The RANDR X extension.
record
The RECORD X extension.
render
The RENDER X extension.
res
The X-Resource X extension.
screensaver
The MIT-SCREEN-SAVER X extension.
shape
The SHAPE X extension.
shm
The MIT-SHM X extension.
sync
The SYNC X extension.
x
The core X protocol definitions
xc_misc
The XC-MISC extension.
xevie
The XEVIE X extension.
xf86dri
The XFree86-DRI X extension.
xf86vidmode
The XFree86-VidModeExtension X extension.
xfixes
The XFIXES X extension.
xinerama
The XINERAMA X extension.
xinput
The XInputExtension X extension.
xkb
The XKEYBOARD X extension.
xprint
The XpExtension X extension.
xselinux
The SELinux X extension.
xtest
The XTEST X extension.
xv
The XVideo X extension.
xvmc
The XVideo-MotionCompensation X extension.

Macros§

atoms_struct
An helper macro that generate a struct of atoms.

Structs§

AuthInfo
Container for authentication information to connect to the X server
Connection
Connection is the central object of XCB.
DisplayInfo
Display info returned by parse_display
ExtensionData
Extension data as returned by each extensions get_extension_data.
Lat1Str
A slice to a Latin-1 (aka. ISO 8859-1) string.
Lat1StrF
Latin-1 (aka. ISO 8859-1) of fixed size
Lat1String
A struct owning a Latin-1 (aka. ISO 8859-1) string.
SpecialEvent
A struct that serve as an identifier for internal special queue in XCB
SpecialEventIdDeprecated
A struct that serve as an identifier for internal special queue in XCB
UnknownError
an error that was not recognized as part of the core protocol or any enabled extension
UnknownEvent
an event was not recognized as part of the core protocol or any enabled extension
VoidCookie
The default cookie type returned by void-requests.
VoidCookieChecked
The checked cookie type returned by void-requests.

Enums§

ConnError
Error type that is returned by Connection::has_error.
Error
The general error type for Rust-XCB.
Event
Unified Event type from the X server.
EventQueueOwner
Determines whether Xlib or XCB owns the event queue of Connection.
Extension
Refers to a X protocol extension.
Lat1Error
Error that can produce Latin-1 string operations
ProtocolError
A protocol error issued from the X server

Traits§

BaseError
A trait to designate base protocol errors.
BaseEvent
Trait for base events (aka. non GE_GENERIC events)
Cookie
General trait for cookies returned by requests.
CookieChecked
A marker trait for a cookie that allows synchronized error checking.
CookieWithReplyChecked
A trait for checked cookies of requests that send a reply.
CookieWithReplyUnchecked
A trait for unchecked cookies of requests that send a reply.
GeEvent
A trait for GE_GENERIC events
Raw
Trait for types that own a C allocated pointer and are represented by the data pointed to.
RawRequest
Trait implemented by all requests to send the serialized data over the wire.
Reply
Trait for request replies
Request
Trait implemented by requests types.
RequestWithReply
Trait for requests that return a reply.
RequestWithoutReply
Marker trait for requests that do not return a reply.
Xid
A X resource trait
XidNew
Trait for X resources that can be created directly from Connection::generate_id

Functions§

cache_extensions_data
Returns the extension data for the given extensions. This function may block as the data will be queried from the server if not already cached.
parse_display
Parses a display string in the form documented by X (7x).
resolve_error
Resolve an error from the X server
resolve_event
Resolve an event from the X server

Type Aliases§

ConnResult
The result type associated with ConnError.
ProtocolResult
The result type associated with ProtocolError.
Result
The general result type for Rust-XCB.