1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//! X11 rust bindings.
//!
//! This library allows to interact with an X11 server from rust code. A connection to an X11
//! server is represented by an implementation of the `Connection` trait.
//!
//! The client can interact with the server by sending requests. The server can answer requests and
//! can also generate events.
//!
//! The examples that come with this library might be a good starting point for new users.
//!
//!
//! # Getting started with X11
//!
//! X11 is a big protocol. I would claim that most of it is not actually that complicated, but it
//! is still difficult to get into it. A good starting point might be some [libxcb
//! tutorial](https://www.x.org/releases/X11R7.7/doc/libxcb/tutorial/index.html). This tutorial
//! was adapted in this crate [as an
//! example](https://github.com/psychon/x11rb/blob/master/examples/tutorial.rs). A more in-depth
//! look at the X11 protocol can be gained from the [protocol reference
//! manual](https://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.html), but this requires some
//! existing basic understanding of X11. If you want to figure out what some specific request does,
//! be sure to look it up in the specification!
//!
//! Most extensions can be understood by reading their specification. Most of them can be found
//! [here](https://www.x.org/releases/current/doc/index.html#protocol). For example, [the
//! specification of Composite
//! 0.4](https://www.x.org/releases/X11R7.5/doc/compositeproto/compositeproto.txt) consists of
//! about six pages of text.
//!
//! The notable exception is the X keyboard extension, which is documented in a [PDF file with 168
//! pages](https://www.x.org/releases/current/doc/kbproto/xkbproto.pdf) which I am never going to
//! read completely.
//!
//!
//! # Getting started with x11rb
//!
//! Most code in this code is automatically generated from an XML description of the protocol. This
//! is the same approach as taken by [libxcb](https://xcb.freedesktop.org/) (and in fact this uses
//! the same XML description). This means that if you know your way around X11, most things should
//! be obvious to you.
//!
//! For example, here is how to create a new window with x11rb:
//! ```no_run
//! use x11rb::connection::Connection;
//! use x11rb::errors::ReplyOrIdError;
//! use x11rb::protocol::xproto::*;
//! use x11rb::COPY_DEPTH_FROM_PARENT;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let (conn, screen_num) = x11rb::connect(None).unwrap();
//!     let screen = &conn.setup().roots[screen_num];
//!     let win_id = conn.generate_id()?;
//!     conn.create_window(
//!         COPY_DEPTH_FROM_PARENT,
//!         win_id,
//!         screen.root,
//!         0,
//!         0,
//!         100,
//!         100,
//!         0,
//!         WindowClass::INPUT_OUTPUT,
//!         0,
//!         &CreateWindowAux::new().background_pixel(screen.white_pixel),
//!     )?;
//!     conn.map_window(win_id)?;
//!     conn.flush();
//!     loop {
//!         println!("Event: {:?}", conn.wait_for_event()?);
//!     }
//! }
//! ```
//! More examples can be found in the
//! [examples](https://github.com/psychon/x11rb/tree/master/examples) directory.
//!
//! ## Feature flags
//!
//! This crate uses [feature
//! flags](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section) to reduce
//! the amount of compiled code. There are two kinds of feature flags available:
//!
//! * Feature flags for specific X11 extensions
//! * Feature flags for additional functionality
//!
//! ### Feature flags for specific X11 extensions
//!
//! By default, only the core X11 protocol and X11 extensions that are
//! needed internally are enabled. Further extensions need to be explicitly enabled via their
//! feature flag:
//!
//! `composite`, `damage`, `dpms`, `dri2`, `dri3`, `glx`, `present`, `randr`, `record`, `render`,
//! `res`, `screensaver`, `shape`, `shm`, `sync`, `xevie`, `xf86dri`, `xf86vidmode`, `xfixes`,
//! `xinerama`, `xinput`, `xkb`, `xprint`, `xselinux`, `xtest`, `xv`, `xvmc`.
//!
//! If you want to take the "I do not want to think about this"-approach, you can enable the
//! `all-extensions` feature to just enable, well, all extensions.
//!
//! ### Feature flags for additional functionality
//!
//! Additionally, the following flags exist:
//! * `allow-unsafe-code`: Enable features that require `unsafe`. Without this flag,
//!   `x11rb::xcb_ffi::XCBConnection` and some support code for it are unavailable.
//! * `cursor`: Enable the code in [crate::cursor] for loading cursor files.
//! * `resource_manager`: Enable the code in [crate::resource_manager] for loading and querying the
//!   X11 resource database.
//! * `image`: Enable the code in [crate::image] for working with pixel image data.
//! * `dl-libxcb`: Enabling this feature will prevent from libxcb being linked to the
//!   resulting executable. Instead libxcb will be dynamically loaded at runtime.
//!   This feature adds the [`crate::xcb_ffi::load_libxcb`] function, that allows to load
//!   libxcb and check for success or failure.
//!
//! # Integrating x11rb with an Event Loop
//!
//! The [event_loop_integration](event_loop_integration/index.html) module contains some hints for
//! integrating x11rb with an event loop as doc comments.

#![forbid(
    missing_copy_implementations,
    missing_debug_implementations,
    private_doc_tests,
    rust_2018_idioms,
    //single_use_lifetimes,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unused_import_braces,
    unused_results,
    clippy::cast_lossless,
    clippy::needless_pass_by_value,
)]
// A list of lints that are only #![deny] and not the stronger #![forbid]. Each one has a comment
// explaining why it gets the weaker treatment.
#![deny(
    // #[derive] generates an #[allow] for this
    unused_qualifications,
    // Not everything in x11rb::protocol has doc comments
    missing_docs,
)]
#![allow(
    // This suggests a method that was stabilised in Rust 1.45, while our MSRV is 1.40.
    clippy::manual_strip,
    // This suggests a macro that was stabilised in Rust 1.42, while our MSRV is 1.40.
    clippy::match_like_matches_macro,
)]
#![cfg_attr(not(feature = "allow-unsafe-code"), forbid(unsafe_code))]

// Only contains documentation, but no "actual rust"
pub mod event_loop_integration;

pub mod utils;
#[cfg(feature = "allow-unsafe-code")]
pub mod xcb_ffi;
#[macro_use]
pub mod x11_utils;
pub mod connection;
pub mod cookie;
#[cfg(feature = "cursor")]
pub mod cursor;
pub mod errors;
pub mod extension_manager;
#[cfg(feature = "image")]
pub mod image;
pub mod properties;
pub mod rust_connection;
pub mod wrapper;
#[rustfmt::skip]
#[allow(missing_docs)]
pub mod protocol;
#[cfg(feature = "resource_manager")]
pub mod resource_manager;
#[cfg(test)]
mod test;

use connection::Connection;
use errors::ConnectError;
use protocol::xproto::{Keysym, Timestamp};

/// Establish a new connection to an X11 server.
///
/// If a `dpy_name` is provided, it describes the display that should be connected to, for
/// example `127.0.0.1:1`. If no value is provided, the `$DISPLAY` environment variable is
/// used.
pub fn connect(
    dpy_name: Option<&str>,
) -> Result<(impl Connection + Send + Sync, usize), ConnectError> {
    #[cfg(feature = "allow-unsafe-code")]
    {
        let dpy_name = dpy_name
            .map(std::ffi::CString::new)
            .transpose()
            .map_err(|_| ConnectError::DisplayParsingError)?;
        let dpy_name = dpy_name.as_deref();
        xcb_ffi::XCBConnection::connect(dpy_name)
    }
    #[cfg(not(feature = "allow-unsafe-code"))]
    {
        rust_connection::RustConnection::connect(dpy_name)
    }
}

/// The universal null resource or null atom parameter value for many core X requests
pub const NONE: u32 = 0;

/// This constant can be used for many parameters in `create_window`
pub const COPY_FROM_PARENT: u32 = 0;

/// This constant can be used for the depth parameter in `create_window`. It indicates to use the
/// parent window's depth.
pub const COPY_DEPTH_FROM_PARENT: u8 = 0;

/// This constant can be used for the class parameter in `create_window`. It indicates to use the
/// parent window's class.
pub const COPY_CLASS_FROM_PARENT: u16 = 0;

/// This constant can be used in most request that take a timestamp argument
pub const CURRENT_TIME: Timestamp = 0;

/// This constant can be used to fill unused entries in `Keysym` tables
pub const NO_SYMBOL: Keysym = 0;