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}