xcb/
lib.rs

1/*
2 * Copyright (C) 2013 James Miller <james@aatch.net>
3 * Copyright (c) 2016
4 *         Remi Thebault <remi.thebault@gmail.com>
5 *         Thomas Bracht Laumann Jespersen <laumann.thomas@gmail.com>
6 * Copyright (c) 2017-2021 Remi Thebault <remi.thebault@gmail.com>
7 *
8 * Permission is hereby granted, free of charge, to any
9 * person obtaining a copy of this software and associated
10 * documentation files (the "Software"), to deal in the
11 * Software without restriction, including without
12 * limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of
14 * the Software, and to permit persons to whom the Software
15 * is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice
19 * shall be included in all copies or substantial portions
20 * of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
23 * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
24 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
25 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
26 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
29 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
31 */
32
33#![allow(dead_code)]
34#![allow(unused_imports)]
35#![allow(unused_parens)]
36#![allow(clippy::len_without_is_empty)]
37#![allow(clippy::diverging_sub_expression)]
38
39//! Rust bindings to the XCB library.
40//!
41//! The X protocol C-language Binding (XCB - <https://xcb.freedesktop.org/>) is
42//! a replacement for Xlib featuring a small footprint, latency hiding, direct
43//! access to the protocol, improved threading support, and extensibility.
44//!
45//! The communication is established with the X server by the creation of a
46//! [Connection] object.
47//!
48//! A client communicates with the server by sending requests. There are 2 types
49//! of requests:
50//!
51//!   - void requests: requests that do not expect an answer
52//!     (e.g. [x::ChangeProperty])
53//!   - non-void requests: requests that need a `Reply` (e.g. [x::GetProperty])
54//!
55//! Requests are passed to the server by filling a request structure e.g.
56//! [x::CreateWindow] and passing it to [Connection::send_request].
57//!
58//! The server can also communicate with clients by sending `Event`s.
59//! The client listens to events with calls such as [Connection::wait_for_event]
60//! (blocking) or [Connection::poll_for_event] (non-blocking).
61//!
62//! The [x] module contains definitions of the core X protocol.
63//! Each extension is defined in its own module such as [xkb] or [render], and
64//! is activated by a cargo feature of the same name.
65//!
66//! # Example
67//!
68//! Here is a walk-through of a simple `xcb` client.
69//! ```no_run
70//! // we import the necessary modules (only the core X module in this application).
71//! use xcb::{x};
72//! // we need to import the `Xid` trait for the `resource_id` call down there.
73//! use xcb::{Xid};
74//!
75//! // Many xcb functions return a `xcb::Result` or compatible result.
76//! fn main() -> xcb::Result<()> {
77//!     // Connect to the X server.
78//!     let (conn, screen_num) = xcb::Connection::connect(None)?;
79//!
80//!     // Fetch the `x::Setup` and get the main `x::Screen` object.
81//!     let setup = conn.get_setup();
82//!     let screen = setup.roots().nth(screen_num as usize).unwrap();
83//!
84//!     // Generate an `Xid` for the client window.
85//!     // The type inference is needed here.
86//!     let window: x::Window = conn.generate_id();
87//!
88//!     // We can now create a window. For this we pass a `Request`
89//!     // object to the `send_request_checked` method. The method
90//!     // returns a cookie that will be used to check for success.
91//!     let cookie = conn.send_request_checked(&x::CreateWindow {
92//!         depth: x::COPY_FROM_PARENT as u8,
93//!         wid: window,
94//!         parent: screen.root(),
95//!         x: 0,
96//!         y: 0,
97//!         width: 150,
98//!         height: 150,
99//!         border_width: 0,
100//!         class: x::WindowClass::InputOutput,
101//!         visual: screen.root_visual(),
102//!         // this list must be in same order than `Cw` enum order
103//!         value_list: &[
104//!             x::Cw::BackPixel(screen.white_pixel()),
105//!             x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS)
106//!         ],
107//!     });
108//!     // We now check if the window creation worked.
109//!     // A cookie can't be cloned; it is moved to the function.
110//!     conn.check_request(cookie)?;
111//!
112//!     // Let's change the window title
113//!     let cookie = conn.send_request_checked(&x::ChangeProperty {
114//!         mode: x::PropMode::Replace,
115//!         window,
116//!         property: x::ATOM_WM_NAME,
117//!         r#type: x::ATOM_STRING,
118//!         data: b"My XCB Window",
119//!     });
120//!     // And check for success again
121//!     conn.check_request(cookie)?;
122//!
123//!     // We now show ("map" in X terminology) the window.
124//!     // This time we do not check for success, so we discard the cookie.
125//!     conn.send_request(&x::MapWindow {
126//!         window,
127//!     });
128//!
129//!     // We need a few atoms for our application.
130//!     // We send a few requests in a row and wait for the replies after.
131//!     let (wm_protocols, wm_del_window, wm_state, wm_state_maxv, wm_state_maxh) = {
132//!         let cookies = (
133//!             conn.send_request(&x::InternAtom {
134//!                 only_if_exists: true,
135//!                 name: b"WM_PROTOCOLS",
136//!             }),
137//!             conn.send_request(&x::InternAtom {
138//!                 only_if_exists: true,
139//!                 name: b"WM_DELETE_WINDOW",
140//!             }),
141//!             conn.send_request(&x::InternAtom {
142//!                 only_if_exists: true,
143//!                 name: b"_NET_WM_STATE",
144//!             }),
145//!             conn.send_request(&x::InternAtom {
146//!                 only_if_exists: true,
147//!                 name: b"_NET_WM_STATE_MAXIMIZED_VERT",
148//!             }),
149//!             conn.send_request(&x::InternAtom {
150//!                 only_if_exists: true,
151//!                 name: b"_NET_WM_STATE_MAXIMIZED_HORZ",
152//!             }),
153//!         );
154//!         (
155//!             conn.wait_for_reply(cookies.0)?.atom(),
156//!             conn.wait_for_reply(cookies.1)?.atom(),
157//!             conn.wait_for_reply(cookies.2)?.atom(),
158//!             conn.wait_for_reply(cookies.3)?.atom(),
159//!             conn.wait_for_reply(cookies.4)?.atom(),
160//!         )
161//!     };
162//!
163//!     // We now activate the window close event by sending the following request.
164//!     // If we don't do this we can still close the window by clicking on the "x" button,
165//!     // but the event loop is notified through a connection shutdown error.
166//!     conn.check_request(conn.send_request_checked(&x::ChangeProperty {
167//!         mode: x::PropMode::Replace,
168//!         window,
169//!         property: wm_protocols,
170//!         r#type: x::ATOM_ATOM,
171//!         data: &[wm_del_window],
172//!     }))?;
173//!
174//!     // Previous request was checked, so a flush is not necessary in this case.
175//!     // Otherwise, here is how to perform a connection flush.
176//!     conn.flush()?;
177//!
178//!     let mut maximized = false;
179//!
180//!     // We enter the main event loop
181//!     loop {
182//!         match conn.wait_for_event()? {
183//!             xcb::Event::X(x::Event::KeyPress(ev)) => {
184//!                 if ev.detail() == 0x3a {
185//!                     // The M key was pressed
186//!                     // (M only on qwerty keyboards. Keymap support is done
187//!                     // with the `xkb` extension and the `xkbcommon-rs` crate)
188//!
189//!                     // We toggle maximized state, for this we send a message
190//!                     // by building a `x::ClientMessageEvent` with the proper
191//!                     // atoms and send it to the server.
192//!
193//!                     let data = x::ClientMessageData::Data32([
194//!                         if maximized { 0 } else { 1 },
195//!                         wm_state_maxv.resource_id(),
196//!                         wm_state_maxh.resource_id(),
197//!                         0,
198//!                         0,
199//!                     ]);
200//!                     let event = x::ClientMessageEvent::new(window, wm_state, data);
201//!                     let cookie = conn.send_request_checked(&x::SendEvent {
202//!                         propagate: false,
203//!                         destination: x::SendEventDest::Window(screen.root()),
204//!                         event_mask: x::EventMask::STRUCTURE_NOTIFY,
205//!                         event: &event,
206//!                     });
207//!                     conn.check_request(cookie)?;
208//!
209//!                     // Same as before, if we don't check for error, we have to flush
210//!                     // the connection.
211//!                     // conn.flush()?;
212//!
213//!                     maximized = !maximized;
214//!                 } else if ev.detail() == 0x18 {
215//!                     // Q (on qwerty)
216//!
217//!                     // We exit the event loop (and the program)
218//!                     break Ok(());
219//!                 }
220//!             }
221//!             xcb::Event::X(x::Event::ClientMessage(ev)) => {
222//!                 // We have received a message from the server
223//!                 if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
224//!                     if atom == wm_del_window.resource_id() {
225//!                         // The received atom is "WM_DELETE_WINDOW".
226//!                         // We can check here if the user needs to save before
227//!                         // exit, or in our case, exit right away.
228//!                         break Ok(());
229//!                     }
230//!                 }
231//!             }
232//!             _ => {}
233//!         }
234//!     }
235//! }
236//! ```
237//!
238//! # Cargo features
239//!
240//! The following Cargo features are available
241//!
242//! ## `xlib_xcb`
243//!
244//! This feature activates the use of `xlib::Display` to connect to XCB, therefore making
245//! available both Xlib and XCB functions to the same connection.
246//! While XCB is sufficient to handle all communication with the X server, some things can
247//! still only be done by Xlib. E.g. hardware initialization for OpenGL is done by Xlib only.
248//!
249//! ## `debug_atom_names`
250//!
251//! When this feature is activated, the `fmt::Debug` implementation for `x::Atom` will print
252//! out the name of the atom in addition to its value.
253//!
254//! E.g. the feature would turn `Atom { res_id: 303 }` into `Atom("Abs Pressure" ; 303)`.
255//!
256//! This can be useful in situations where you are not sure which atom you have to intern
257//! in order to look up some data in a reply.
258//!
259//! It should be noted that the feature sets global variable to have access to
260//! the connection in the `fmt::Debug` implementation, and that the `Debug` print
261//! have side effects (`x::GetAtomName` requests) which can sometimes not be desirable.
262//! The feature should therefore only be activated when needed.
263//!
264//! ## `libxcb_v1_14`
265//!
266//! This feature is enabled by default and activates the libxcb API version 1.14.
267//! To use a version of the libxcb API prior to 1.14, you must disable it.
268//!
269//! ## Extension features
270//!
271//! The following X extensions are activated by a cargo feature:
272//!
273//! | Extension name                | Cargo feature |
274//! |-------------------------------|---------------|
275//! | `Composite`                   | `composite`   |
276//! | `DAMAGE`                      | `damage`      |
277//! | `DPMS`                        | `dpms`        |
278//! | `DRI2`                        | `dri2`        |
279//! | `DRI3`                        | `dri3`        |
280//! | `Generic Event Extension`     | `ge`          |
281//! | `GLX`                         | `glx`         |
282//! | `Present`                     | `present`     |
283//! | `RANDR`                       | `randr`       |
284//! | `RECORD`                      | `record`      |
285//! | `RENDER`                      | `render`      |
286//! | `X-Resource`                  | `res`         |
287//! | `MIT-SCREEN-SAVER`            | `screensaver` |
288//! | `SHAPE`                       | `shape`       |
289//! | `MIT-SHM`                     | `shm`         |
290//! | `SYNC`                        | `sync`        |
291//! | `XEVIE`                       | `xevie`       |
292//! | `XFree86-DRI`                 | `xf86dri`     |
293//! | `XFree86-VidModeExtension`    | `xf86vidmode` |
294//! | `XFIXES`                      | `xfixes`      |
295//! | `XINERAMA`                    | `xinerama`    |
296//! | `XInputExtension`             | `xinput`      |
297//! | `XKEYBOARD`                   | `xkb`         |
298//! | `XpExtension`                 | `xprint`      |
299//! | `SELinux`                     | `xselinux`    |
300//! | `TEST`                        | `xtest`       |
301//! | `XVideo`                      | `xv`          |
302//! | `XVideo-MotionCompensation`   | `xvmc`        |
303
304mod base;
305mod error;
306mod event;
307mod ext;
308mod lat1_str;
309
310pub use base::*;
311pub use error::*;
312pub use event::*;
313pub use ext::*;
314pub use lat1_str::*;
315
316pub mod x {
317    //! The core X protocol definitions
318
319    pub use super::xproto::*;
320}
321
322pub mod ffi {
323    //! Module for Foreign Function Interface bindings.
324
325    #![allow(non_camel_case_types)]
326    #![allow(improper_ctypes)]
327
328    pub(crate) mod base;
329    pub(crate) mod ext;
330
331    #[cfg(feature = "xlib_xcb")]
332    pub(crate) mod xlib_xcb;
333
334    pub use base::*;
335    pub use ext::*;
336
337    #[cfg(feature = "xlib_xcb")]
338    pub use xlib_xcb::*;
339}
340
341#[cfg(test)]
342mod test;
343
344mod xproto {
345    #![allow(unused_variables)]
346    #![allow(clippy::unit_arg)]
347    #![allow(clippy::new_ret_no_self)]
348    #![allow(clippy::too_many_arguments)]
349
350    /// `COPY_FROM_PARENT` can be used for many `CreateWindow` fields
351    pub const COPY_FROM_PARENT: u32 = 0;
352
353    /// `CURRENT_TIME` can be used in most requests that take a `Timestamp`
354    pub const CURRENT_TIME: Timestamp = 0;
355
356    /// `NO_SYMBOL` fills in unused entries in `Keysym` tables
357    pub const NO_SYMBOL: Keysym = 0;
358
359    /// `GRAB_ANY` can be used in various requests such as `GrabKey`, `UngrabKey`, `xinput::GrabDeviceKey`...
360    pub const GRAB_ANY: Keycode = 0;
361
362    pub const ATOM_ANY: Atom = Atom { res_id: 0 };
363
364    /// Trait for element in a property list
365    ///
366    /// In events (e.g. `GetProperty::value`), it allows to assert that the format
367    /// correspond to the type cast and therefore to do the cast safely at runtime.
368    ///
369    /// In request (e.g. `ChangeProperty::data`), it allows to infer the format value
370    /// from the type of passed data.
371    pub trait PropEl {
372        const FORMAT: u8;
373    }
374
375    impl PropEl for u8 {
376        const FORMAT: u8 = 8;
377    }
378
379    impl PropEl for u16 {
380        const FORMAT: u8 = 16;
381    }
382
383    impl PropEl for u32 {
384        const FORMAT: u8 = 32;
385    }
386
387    impl PropEl for Atom {
388        const FORMAT: u8 = 32;
389    }
390
391    impl PropEl for Window {
392        // _NET_CLIENT_LIST returns a list of windows
393        const FORMAT: u8 = 32;
394    }
395
396    include!(concat!(env!("OUT_DIR"), "/xproto.rs"));
397}
398
399/// An helper macro that generate a struct of atoms.
400///
401/// The struct provide a constructor `intern_all` that takes a `Connection` as parameter,
402/// interns all the atoms and return `xcb::Result<[struct name]>`.
403/// `intern_all` takes advantage of XCB asynchronous design by sending all the
404/// [`x::InternAtom`] requests before starting to wait for the first reply.
405/// Fields that refer to atoms not existing in the server are set to `x::ATOM_NONE`
406/// (i.e. `only_if_exists` is always set to `true`).
407///
408/// Both the struct and each field can receive visibility attributes.
409///
410/// # Example
411/// ```no_run
412/// # use xcb::x;
413/// xcb::atoms_struct! {
414///     #[derive(Copy, Clone, Debug)]
415///     pub(crate) struct Atoms {
416///         pub wm_protocols    => b"WM_PROTOCOLS",
417///         pub wm_del_window   => b"WM_DELETE_WINDOW",
418///         /// Supported EWMH hints
419///         pub net_supported  => b"_NET_SUPPORTED",
420///
421///         // You can also explicitly set the `only_if_exists` argument when interning
422///         // each atom with the following syntax (the default is `true`):
423///         pub custom_atom    => b"MY_CUSTOM_ATOM" only_if_exists = false,
424///     }
425/// }
426///
427/// fn main() -> xcb::Result<()> {
428/// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
429/// #   let window = conn.generate_id();
430///     // ...
431///     let atoms = Atoms::intern_all(&conn)?;
432///
433///     conn.check_request(conn.send_request_checked(&x::ChangeProperty {
434///         mode: x::PropMode::Replace,
435///         window,
436///         property: atoms.wm_protocols,
437///         r#type: x::ATOM_ATOM,
438///         data: &[atoms.wm_del_window],
439///     }))?;
440///     // ...
441/// #   Ok(())
442/// }
443/// ```
444#[macro_export]
445macro_rules! atoms_struct {
446    (
447        $(#[$outer:meta])*
448        $vis:vis struct $Atoms:ident {
449            $(
450                $(#[$fmeta:meta])* $fvis:vis $field:ident => $name:tt $( only_if_exists = $only_if_exists:expr)?,
451            )*
452        }
453    ) => {
454        $(#[$outer])*
455        $vis struct $Atoms {
456            $($(#[$fmeta])* $fvis $field: xcb::x::Atom,)*
457        }
458        impl $Atoms {
459            #[allow(dead_code)]
460            pub fn intern_all(conn: &xcb::Connection) -> xcb::Result<$Atoms> {
461                $(
462                    #[allow(unused_assignments)]
463                    let mut only_if_exists = true;
464                    $( only_if_exists = $only_if_exists; )?
465                    let $field = conn.send_request(&xcb::x::InternAtom {
466                        only_if_exists,
467                        name: $name,
468                    });
469                )*
470                $(
471                    let $field = conn.wait_for_reply($field)?.atom();
472                )*
473                Ok($Atoms {
474                    $($field,)*
475                })
476            }
477        }
478    };
479}
480
481pub mod bigreq {
482    //! The `BIG-REQUESTS` extension.
483    include!(concat!(env!("OUT_DIR"), "/bigreq.rs"));
484}
485
486pub mod xc_misc {
487    //! The `XC-MISC` extension.
488    include!(concat!(env!("OUT_DIR"), "/xc_misc.rs"));
489}
490
491#[cfg(feature = "composite")]
492pub mod composite {
493    //! The `Composite` X extension.
494    //!
495    //! Accessible with the `composite` cargo feature.
496    include!(concat!(env!("OUT_DIR"), "/composite.rs"));
497}
498
499#[cfg(feature = "damage")]
500pub mod damage {
501    //! The `DAMAGE` X extension.
502    //!
503    //! Accessible with the `damage` cargo feature.
504    include!(concat!(env!("OUT_DIR"), "/damage.rs"));
505}
506
507#[cfg(feature = "dpms")]
508pub mod dpms {
509    //! The `DPMS` X extension.
510    //!
511    //! Accessible with the `dpms` cargo feature.
512    include!(concat!(env!("OUT_DIR"), "/dpms.rs"));
513}
514
515#[cfg(feature = "dri2")]
516pub mod dri2 {
517    //! The `DRI2` X extension.
518    //!
519    //! Accessible with the `dri2` cargo feature.
520    #![allow(clippy::too_many_arguments)]
521    include!(concat!(env!("OUT_DIR"), "/dri2.rs"));
522}
523
524#[cfg(feature = "dri3")]
525pub mod dri3 {
526    //! The `DRI3` X extension.
527    //!
528    //! Accessible with the `dri3` cargo feature.
529    include!(concat!(env!("OUT_DIR"), "/dri3.rs"));
530}
531
532#[cfg(feature = "ge")]
533pub mod ge {
534    //! The `Generic Event Extension` X extension.
535    //!
536    //! Accessible with the `ge` cargo feature.
537    include!(concat!(env!("OUT_DIR"), "/ge.rs"));
538}
539
540#[cfg(feature = "glx")]
541pub mod glx {
542    //! The `GLX` X extension.
543    //!
544    //! Accessible with the `glx` cargo feature.
545    #![allow(clippy::too_many_arguments)]
546    include!(concat!(env!("OUT_DIR"), "/glx.rs"));
547}
548
549#[cfg(feature = "xinput")]
550pub mod xinput {
551    //! The `XInputExtension` X extension.
552    //!
553    //! Accessible with the `xinput` cargo feature.
554    #![allow(unused_variables)]
555    #![allow(unused_mut)]
556    #![allow(clippy::unit_arg)]
557    #![allow(clippy::too_many_arguments)]
558
559    #[derive(Copy, Clone, Debug)]
560    pub enum Device {
561        All,
562        AllMaster,
563        Id(u16),
564    }
565
566    impl Device {
567        pub fn from_id(id: u16) -> Self {
568            match id {
569                0 => Device::All,
570                1 => Device::AllMaster,
571                id => Device::Id(id),
572            }
573        }
574
575        pub fn id(&self) -> u16 {
576            match self {
577                Device::All => 0,
578                Device::AllMaster => 1,
579                Device::Id(id) => *id,
580            }
581        }
582    }
583
584    impl WiredOut for Device {
585        fn wire_len(&self) -> usize {
586            2
587        }
588        fn serialize(&self, wire_buf: &mut [u8]) -> usize {
589            assert!(wire_buf.len() >= 2);
590            unsafe {
591                *(wire_buf.as_mut_ptr() as *mut u16) = self.id();
592            }
593            2
594        }
595    }
596
597    impl WiredIn for Device {
598        type Params = ();
599        unsafe fn compute_wire_len(_ptr: *const u8, _params: ()) -> usize {
600            2
601        }
602        unsafe fn unserialize(ptr: *const u8, params: Self::Params, offset: &mut usize) -> Self {
603            *offset = 2;
604            let id = *(ptr as *const u16);
605            Device::from_id(id)
606        }
607    }
608
609    include!(concat!(env!("OUT_DIR"), "/xinput.rs"));
610}
611
612#[cfg(feature = "present")]
613pub mod present {
614    //! The `Present` X extension.
615    //!
616    //! Accessible with the `present` cargo feature.
617    #![allow(clippy::unit_arg)]
618    include!(concat!(env!("OUT_DIR"), "/present.rs"));
619}
620
621#[cfg(feature = "randr")]
622pub mod randr {
623    //! The `RANDR` X extension.
624    //!
625    //! Accessible with the `randr` cargo feature.
626    #![allow(clippy::unit_arg)]
627    #![allow(clippy::too_many_arguments)]
628    include!(concat!(env!("OUT_DIR"), "/randr.rs"));
629
630    /// For information on what the various properties mean, see the [RandR specification][randr-spec]
631    ///
632    /// [randr-spec]: https://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt#n1860
633    mod property {
634        #[doc(alias = "RR_PROPERTY_BACKLIGHT")]
635        pub const BACKLIGHT: &str = "Backlight";
636
637        #[doc(alias = "RR_PROPERTY_CLONE_LIST")]
638        pub const CLONE_LIST: &str = "CloneList";
639
640        #[doc(alias = "RR_PROPERTY_COMPATIBILITY_LIST")]
641        pub const COMPATIBILITY_LIST: &str = "CompatibilityList";
642
643        #[doc(alias = "RR_PROPERTY_CONNECTOR_NUMBER")]
644        pub const CONNECTOR_NUMBER: &str = "ConnectorNumber";
645
646        #[doc(alias = "RR_PROPERTY_CONNECTOR_TYPE")]
647        pub const CONNECTOR_TYPE: &str = "ConnectorType";
648
649        #[doc(alias = "RR_PROPERTY_RANDR_EDID")]
650        pub const EDID: &str = "EDID";
651
652        #[doc(alias = "RR_PROPERTY_SIGNAL_FORMAT")]
653        pub const SIGNAL_FORMAT: &str = "SignalFormat";
654
655        #[doc(alias = "RR_PROPERTY_SIGNAL_PROPERTIES")]
656        pub const SIGNAL_PROPERTIES: &str = "SignalProperties";
657
658        #[doc(alias = "RR_PROPERTY_BORDER")]
659        pub const BORDER: &str = "Border";
660
661        #[doc(alias = "RR_PROPERTY_BORDER_DIMENSIONS")]
662        pub const BORDER_DIMENSIONS: &str = "BorderDimensions";
663
664        #[doc(alias = "RR_PROPERTY_GUID")]
665        pub const GUID: &str = "GUID";
666
667        #[doc(alias = "RR_PROPERTY_RANDR_TILE")]
668        pub const TILE: &str = "TILE";
669
670        #[doc(alias = "RR_PROPERTY_NON_DESKTOP")]
671        pub const NON_DESKTOP: &str = "non-desktop";
672    }
673}
674
675#[cfg(feature = "record")]
676pub mod record {
677    //! The `RECORD` X extension.
678    //!
679    //! Accessible with the `record` cargo feature.
680    #![allow(clippy::unit_arg)]
681    #![allow(clippy::too_many_arguments)]
682    include!(concat!(env!("OUT_DIR"), "/record.rs"));
683}
684
685#[cfg(feature = "render")]
686pub mod render {
687    //! The `RENDER` X extension.
688    //!
689    //! Accessible with the `render` cargo feature.
690    #![allow(unused_variables)]
691    #![allow(clippy::unit_arg)]
692    include!(concat!(env!("OUT_DIR"), "/render.rs"));
693}
694
695#[cfg(feature = "res")]
696pub mod res {
697    //! The `X-Resource` X extension.
698    //!
699    //! Accessible with the `res` cargo feature.
700    #![allow(unused_variables)]
701    #![allow(clippy::unit_arg)]
702    include!(concat!(env!("OUT_DIR"), "/res.rs"));
703}
704
705#[cfg(feature = "screensaver")]
706pub mod screensaver {
707    //! The `MIT-SCREEN-SAVER` X extension.
708    //!
709    //! Accessible with the `screensaver` cargo feature.
710    #![allow(unused_variables)]
711    include!(concat!(env!("OUT_DIR"), "/screensaver.rs"));
712}
713
714#[cfg(feature = "xselinux")]
715pub mod xselinux {
716    //! The `SELinux` X extension.
717    //!
718    //! Accessible with the `xselinux` cargo feature.
719    #![allow(clippy::unit_arg)]
720    include!(concat!(env!("OUT_DIR"), "/xselinux.rs"));
721}
722
723#[cfg(feature = "shape")]
724pub mod shape {
725    //! The `SHAPE` X extension.
726    //!
727    //! Accessible with the `shape` cargo feature.
728    #![allow(clippy::too_many_arguments)]
729    include!(concat!(env!("OUT_DIR"), "/shape.rs"));
730}
731
732#[cfg(feature = "shm")]
733pub mod shm {
734    //! The `MIT-SHM` X extension.
735    //!
736    //! Accessible with the `shm` cargo feature.
737    include!(concat!(env!("OUT_DIR"), "/shm.rs"));
738}
739
740#[cfg(feature = "sync")]
741pub mod sync {
742    //! The `SYNC` X extension.
743    //!
744    //! Accessible with the `sync` cargo feature.
745    #![allow(unused_variables)]
746    #![allow(clippy::unit_arg)]
747    #![allow(clippy::too_many_arguments)]
748    include!(concat!(env!("OUT_DIR"), "/sync.rs"));
749}
750
751#[cfg(feature = "xtest")]
752pub mod xtest {
753    //! The `XTEST` X extension.
754    //!
755    //! Accessible with the `xtest` cargo feature.
756    include!(concat!(env!("OUT_DIR"), "/xtest.rs"));
757}
758
759#[cfg(feature = "xprint")]
760pub mod xprint {
761    //! The `XpExtension` X extension.
762    //!
763    //! Accessible with the `xprint` cargo feature.
764    #![allow(clippy::unit_arg)]
765    include!(concat!(env!("OUT_DIR"), "/xprint.rs"));
766}
767
768#[cfg(feature = "xevie")]
769pub mod xevie {
770    //! The `XEVIE` X extension.
771    //!
772    //! Accessible with the `xevie` cargo feature.
773    include!(concat!(env!("OUT_DIR"), "/xevie.rs"));
774}
775
776#[cfg(feature = "xf86dri")]
777pub mod xf86dri {
778    //! The `XFree86-DRI` X extension.
779    //!
780    //! Accessible with the `xf86dri` cargo feature.
781    include!(concat!(env!("OUT_DIR"), "/xf86dri.rs"));
782}
783
784#[cfg(feature = "xf86vidmode")]
785pub mod xf86vidmode {
786    //! The `XFree86-VidModeExtension` X extension.
787    //!
788    //! Accessible with the `xf86vidmode` cargo feature.
789    #![allow(clippy::too_many_arguments)]
790    include!(concat!(env!("OUT_DIR"), "/xf86vidmode.rs"));
791}
792
793#[cfg(feature = "xfixes")]
794pub mod xfixes {
795    //! The `XFIXES` X extension.
796    //!
797    //! Accessible with the `xfixes` cargo feature.
798    include!(concat!(env!("OUT_DIR"), "/xfixes.rs"));
799}
800
801#[cfg(feature = "xinerama")]
802pub mod xinerama {
803    //! The `XINERAMA` X extension.
804    //!
805    //! Accessible with the `xinerama` cargo feature.
806    include!(concat!(env!("OUT_DIR"), "/xinerama.rs"));
807}
808
809#[cfg(feature = "xkb")]
810pub mod xkb {
811    //! The `XKEYBOARD` X extension.
812    //!
813    //! Accessible with the `xkb` cargo feature.
814    #![allow(unused_variables)]
815    #![allow(clippy::let_unit_value)]
816    #![allow(clippy::unit_arg)]
817    #![allow(clippy::too_many_arguments)]
818    include!(concat!(env!("OUT_DIR"), "/xkb.rs"));
819}
820
821#[cfg(feature = "xv")]
822pub mod xv {
823    //! The `XVideo` X extension.
824    //!
825    //! Accessible with the `xv` cargo feature.
826    #![allow(clippy::unit_arg)]
827    #![allow(clippy::too_many_arguments)]
828    include!(concat!(env!("OUT_DIR"), "/xv.rs"));
829}
830
831#[cfg(feature = "xvmc")]
832pub mod xvmc {
833    //! The `XVideo-MotionCompensation` X extension.
834    //!
835    //! Accessible with the `xvmc` cargo feature.
836    include!(concat!(env!("OUT_DIR"), "/xvmc.rs"));
837}