xcb/
base.rs

1use crate::error::{self, ProtocolError};
2use crate::event::{self, Event};
3use crate::ext::{Extension, ExtensionData};
4#[cfg(feature = "present")]
5use crate::present;
6use crate::x::{Atom, Keysym, Setup, Timestamp};
7#[cfg(feature = "xinput")]
8use crate::xinput;
9use crate::{cache_extensions_data, ffi::*};
10
11#[cfg(feature = "xlib_xcb")]
12use x11::xlib;
13
14use bitflags::bitflags;
15
16use libc::{c_char, c_int};
17
18use std::cell::RefCell;
19use std::ffi::{c_void, CStr, CString};
20use std::fmt::{self, Display, Formatter};
21use std::marker::{self, PhantomData};
22use std::mem;
23use std::os::unix::prelude::{AsRawFd, RawFd};
24use std::ptr;
25use std::result;
26use std::slice;
27
28/// A X resource trait
29pub trait Xid {
30    /// Build a null X resource
31    fn none() -> Self;
32
33    /// Get the underlying id of the resource
34    fn resource_id(&self) -> u32;
35
36    /// Check whether this resource is null or not
37    fn is_none(&self) -> bool {
38        self.resource_id() == 0
39    }
40}
41
42/// Trait for X resources that can be created directly from `Connection::generate_id`
43///
44/// The resources that cannot be created that way are the Xid unions, which are created
45/// from their underlying resource.
46pub trait XidNew: Xid {
47    /// Build a new X resource
48    ///
49    /// # Safety
50    /// res_id must be obtained from `xcb_generate_id`. `0` is also a valid value to create a null resource.
51    /// Users should not use this function directly but rather use
52    /// `Connection::generate_id`
53    unsafe fn new(res_id: u32) -> Self;
54}
55
56/// Trait for types that own a C allocated pointer and are represented by the data pointed to.
57pub trait Raw<T>: Sized {
58    /// Build `Self` from a raw pointer
59    ///
60    /// # Safety
61    /// `raw` must be a valid pointer to the representation of Self, and be allocated with `libc::malloc`
62    unsafe fn from_raw(raw: *mut T) -> Self;
63
64    /// Convert self into a raw pointer
65    ///
66    /// Returned value should be freed with `libc::free` or sent back to `from_raw` to avoid memory leak.
67    fn into_raw(self) -> *mut T {
68        let raw = self.as_raw();
69        mem::forget(self);
70        raw
71    }
72
73    /// Obtain the raw pointer representation
74    fn as_raw(&self) -> *mut T;
75}
76
77/// Trait for base events (aka. non GE_GENERIC events)
78pub trait BaseEvent: Raw<xcb_generic_event_t> {
79    /// The extension associated to this event, or `None` for the main protocol
80    const EXTENSION: Option<Extension>;
81
82    /// The number associated to this event
83    const NUMBER: u32;
84
85    /// Check whether this event was emitted by the SendEvent request
86    /// See `[crate::x::SendEvent]`.
87    fn is_from_send_event(&self) -> bool {
88        let ev = self.as_raw();
89        let response_type = unsafe { (*ev).response_type };
90        (response_type & 0x80) != 0
91    }
92}
93
94/// A trait for GE_GENERIC events
95///
96/// A GE_GENERIC event is an extension event that does not follow
97/// the regular `response_type` offset.
98/// This system was introduced because the protocol eventually run
99/// out of event numbers.
100///
101/// This should be completely transparent to the user, as [Event] is
102/// resolving all types of events together.
103pub trait GeEvent: Raw<xcb_ge_generic_event_t> {
104    /// The extension associated to this event
105    const EXTENSION: Extension;
106
107    /// The number associated to this event
108    const NUMBER: u32;
109}
110
111/// A trait to designate base protocol errors.
112///
113/// The base errors follow the usual resolution idiom of `error_code` offset.
114///
115/// This should be completely transparent to the user, as [ProtocolError] is
116/// resolving all types of errors together.
117pub trait BaseError: Raw<xcb_generic_error_t> {
118    /// The extension associated to this error, or `None` for the main protocol
119    const EXTENSION: Option<Extension>;
120
121    /// The number associated to this error
122    const NUMBER: u32;
123}
124
125/// Trait for the resolution of raw wire event to a unified event enum.
126///
127/// `Self` is normally an enum of several event subtypes.
128/// See [crate::x::Event] and [crate::Event]
129pub(crate) trait ResolveWireEvent: Sized {
130    /// Resolve a pointer to `xcb_generic_event_t` to `Self`, inferring the correct subtype
131    /// using `response_type` field and `first_event`
132    ///
133    /// # Safety
134    /// `event` must be a valid, non-null event returned by `xcb_wait_for_event`
135    /// or similar function
136    unsafe fn resolve_wire_event(first_event: u8, event: *mut xcb_generic_event_t) -> Option<Self>;
137}
138
139/// Trait for the resolution of raw wire GE_GENERIC event to a unified event enum.
140///
141/// `Self` is normally an enum of several event subtypes.
142/// See [crate::xinput::Event] and [crate::Event]
143pub(crate) trait ResolveWireGeEvent: Sized {
144    /// Resolve a pointer to `xcb_ge_generic_event_t` to `Self`, inferring the correct subtype
145    /// using `event_type` field.
146    ///
147    /// # Panics
148    /// Panics if the event subtype cannot be resolved for `Self`. That is, `event_type`
149    /// must be checked beforehand to be in range.
150    ///
151    /// # Safety
152    /// `event` must be a valid, non-null event returned by `xcb_wait_for_event`
153    /// or similar function
154    unsafe fn resolve_wire_ge_event(event: *mut xcb_ge_generic_event_t) -> Self;
155}
156
157/// Trait for the resolution of raw wire error to a unified error enum.
158///
159/// `Self` is normally an enum of several event subtypes.
160/// See [crate::x::Error] and [crate::ProtocolError]
161pub(crate) trait ResolveWireError: Sized {
162    /// Convert a pointer to `xcb_generic_error_t` to `Self`, inferring the correct subtype
163    /// using `response_type` field and `first_error`.
164    ///
165    /// # Safety
166    /// `err` must be a valid, non-null error obtained by `xcb_wait_for_reply`
167    /// or similar function
168    unsafe fn resolve_wire_error(first_error: u8, error: *mut xcb_generic_error_t) -> Option<Self>;
169}
170
171/// Trait for types that can serialize themselves to the X wire.
172///
173/// This trait is used internally for requests serialization.
174pub(crate) trait WiredOut {
175    /// Compute the length of wired serialized data of self
176    fn wire_len(&self) -> usize;
177
178    /// Serialize `self` over the X wire and returns how many bytes were written.
179    ///
180    /// `wire_buf` must be larger or as long as the value returned by `wire_len`.
181    /// `serialize` MUST write the data in its entirety at once, at the begining of `wire_buf`.
182    /// That is, it returns the same value as `wire_len`.
183    /// The interest in returning the value is that it is easy to compute in `serialize` and allow
184    /// to easily chain serialization of fields in a struct.
185    ///
186    /// # Panics
187    /// Panics if `wire_buf` is too small to contain the serialized representation of `self`.
188    fn serialize(&self, wire_buf: &mut [u8]) -> usize;
189}
190
191/// Trait for types that can unserialize themselves from the X wire.
192pub(crate) trait WiredIn {
193    /// type of external context necessary to figure out the representation of the data
194    type Params: Copy;
195
196    /// Compute the length of serialized data of an instance starting by `ptr`.
197    ///
198    /// # Safety
199    /// This function is highly unsafe as the pointer must point to data that is a valid
200    /// wired representation of `Self`. Failure to respect this will lead to dereferencing invalid memory.
201    unsafe fn compute_wire_len(ptr: *const u8, params: Self::Params) -> usize;
202
203    /// Unserialize an instance of `Self` from the X wire
204    ///
205    /// `offset` value is increased by the number of bytes corresponding to the representation of `Self`.
206    /// This allows for efficient chaining of unserialization as the data offset is either known at
207    /// compile time, or has to be computed anyway.
208    ///
209    /// # Safety
210    /// This function is highly unsafe as the pointer must point to data that is a valid
211    /// wired representation of `Self`. Failure to respect this will lead to dereferencing invalid memory.
212    unsafe fn unserialize(ptr: *const u8, params: Self::Params, offset: &mut usize) -> Self;
213}
214
215macro_rules! impl_wired_simple {
216    ($typ:ty) => {
217        impl WiredOut for $typ {
218            fn wire_len(&self) -> usize {
219                mem::size_of::<Self>()
220            }
221
222            fn serialize(&self, wire_buf: &mut [u8]) -> usize {
223                debug_assert!(wire_buf.len() >= mem::size_of::<Self>());
224                let buf_size = self.wire_len();
225                let src =
226                    unsafe { slice::from_raw_parts(self as *const Self as *const u8, buf_size) };
227                wire_buf[..buf_size].copy_from_slice(src);
228                buf_size
229            }
230        }
231
232        impl WiredIn for $typ {
233            type Params = ();
234
235            unsafe fn compute_wire_len(_ptr: *const u8, _params: Self::Params) -> usize {
236                mem::size_of::<Self>()
237            }
238
239            unsafe fn unserialize(
240                ptr: *const u8,
241                _params: Self::Params,
242                offset: &mut usize,
243            ) -> Self {
244                *offset += mem::size_of::<Self>();
245                *(ptr as *const Self)
246            }
247        }
248    };
249}
250
251impl_wired_simple!(u8);
252impl_wired_simple!(u16);
253impl_wired_simple!(u32);
254impl_wired_simple!(u64);
255impl_wired_simple!(i8);
256impl_wired_simple!(i16);
257impl_wired_simple!(i32);
258impl_wired_simple!(f32);
259
260impl<T: Xid> WiredOut for T {
261    fn wire_len(&self) -> usize {
262        4
263    }
264
265    fn serialize(&self, wire_buf: &mut [u8]) -> usize {
266        debug_assert!(wire_buf.len() >= 4);
267        let buf_size = self.wire_len();
268        let resource_id = self.resource_id();
269        let src =
270            unsafe { slice::from_raw_parts(&resource_id as *const u32 as *const u8, buf_size) };
271        wire_buf[..buf_size].copy_from_slice(src);
272        buf_size
273    }
274}
275
276impl<T: XidNew> WiredIn for T {
277    type Params = ();
278
279    unsafe fn compute_wire_len(_ptr: *const u8, _params: Self::Params) -> usize {
280        4
281    }
282
283    unsafe fn unserialize(ptr: *const u8, _params: Self::Params, offset: &mut usize) -> Self {
284        *offset += 4;
285        let xid = *(ptr as *const u32);
286        T::new(xid)
287    }
288}
289
290/// Trait for request replies
291pub trait Reply {
292    /// Build the reply struct from a raw pointer.
293    ///
294    /// # Safety
295    /// `raw` must be a pointer to a valid wire representation of `Self`, allocated with [`libc::malloc`].
296    unsafe fn from_raw(raw: *const u8) -> Self;
297
298    /// Consume the reply struct into a raw pointer.
299    ///
300    /// # Safety
301    /// The returned pointer must be freed with [`libc::free`] to avoid any memory leak, or be used
302    /// to build another reply.
303    unsafe fn into_raw(self) -> *const u8;
304
305    /// Get the raw pointer of the XCB reply.
306    ///
307    /// # Safety
308    /// The returned pointer must NOT be freed. Passing this pointer to [`libc::free`] will result in a double free
309    /// when the reply is dropped.
310    unsafe fn as_raw(&self) -> *const u8;
311}
312
313/// General trait for cookies returned by requests.
314pub trait Cookie {
315    /// # Safety
316    /// `seq` must be a valid cookie for a given `Request` or `Reply`.
317    unsafe fn from_sequence(seq: u64) -> Self;
318
319    /// The raw sequence number associated with the cookie.
320    fn sequence(&self) -> u64;
321}
322
323/// A marker trait for a cookie that allows synchronized error checking.
324///
325/// # Safety
326/// Cookies not implementing this trait acknowledge that the error is sent to the event loop
327///
328/// See also [Connection::send_request], [Connection::send_request_checked] and [Connection::check_request]
329pub unsafe trait CookieChecked: Cookie {}
330
331/// A trait for checked cookies of requests that send a reply.
332///
333/// # Safety
334/// Cookies implementing this trait acknowledge that their error is checked when the reply is fetched from the server.
335/// This is the default cookie type for requests with reply.
336///
337/// See also [Connection::send_request], [Connection::wait_for_reply]
338pub unsafe trait CookieWithReplyChecked: CookieChecked {
339    /// The reply type associated with the cookie
340    type Reply: Reply;
341}
342
343/// A trait for unchecked cookies of requests that send a reply.
344///
345/// # Safety
346/// Cookies implementing this trait acknowledge that their error is not checked when the reply is fetched from the server
347/// but in the event loop.
348///
349/// See also [Connection::send_request_unchecked], [Connection::wait_for_event]
350pub unsafe trait CookieWithReplyUnchecked: Cookie {
351    /// The reply type associated with the cookie
352    type Reply: Reply;
353}
354
355/// The default cookie type returned by void-requests.
356///
357/// See [Connection::send_request]
358#[derive(Debug)]
359pub struct VoidCookie {
360    seq: u64,
361}
362
363impl Cookie for VoidCookie {
364    unsafe fn from_sequence(seq: u64) -> Self {
365        VoidCookie { seq }
366    }
367
368    fn sequence(&self) -> u64 {
369        self.seq
370    }
371}
372
373/// The checked cookie type returned by void-requests.
374///
375/// See [Connection::send_request_checked]
376#[derive(Debug)]
377pub struct VoidCookieChecked {
378    seq: u64,
379}
380
381impl Cookie for VoidCookieChecked {
382    unsafe fn from_sequence(seq: u64) -> Self {
383        VoidCookieChecked { seq }
384    }
385
386    fn sequence(&self) -> u64 {
387        self.seq
388    }
389}
390
391unsafe impl CookieChecked for VoidCookieChecked {}
392
393/// Trait implemented by all requests to send the serialized data over the wire.
394///
395/// # Safety
396/// Types implementing this trait acknowledge that the returned value of `raw_request` correspond
397/// to a cookie for `Self` request and is checked or unchecked depending on the `checked` flag value.
398pub unsafe trait RawRequest {
399    /// Actual implementation of the request sending
400    ///
401    /// Send the request over the `conn` wire and return a cookie sequence fitting with the `checked` flag
402    /// of `Self`
403    fn raw_request(&self, conn: &Connection, checked: bool) -> u64;
404}
405
406/// Trait implemented by requests types.
407///
408/// See [crate::x::CreateWindow] as an example.
409pub trait Request: RawRequest {
410    /// The default cookie associated to this request.
411    type Cookie: Cookie;
412
413    /// `false` if the request returns a reply, `true` otherwise.
414    const IS_VOID: bool;
415}
416
417/// Marker trait for requests that do not return a reply.
418///
419/// These trait is implicitely associated with [`VoidCookie`] and [`VoidCookieChecked`].
420pub trait RequestWithoutReply: Request {}
421
422/// Trait for requests that return a reply.
423pub trait RequestWithReply: Request {
424    /// Reply associated with the request
425    type Reply: Reply;
426    /// Default cookie type for the request, as returned by [Connection::send_request].
427    type Cookie: CookieWithReplyChecked<Reply = Self::Reply>;
428    /// Unchecked cookie type for the request, as returned by [Connection::send_request_unchecked].
429    type CookieUnchecked: CookieWithReplyUnchecked<Reply = Self::Reply>;
430}
431
432/// Determines whether Xlib or XCB owns the event queue of [`Connection`].
433///
434/// This item is behind the `xlib_xcb` cargo feature.
435///
436/// See [`Connection::set_event_queue_owner`].
437#[cfg(feature = "xlib_xcb")]
438#[derive(Debug)]
439pub enum EventQueueOwner {
440    /// XCB owns the event queue
441    Xcb,
442    /// Xlib owns the event queue
443    Xlib,
444}
445
446/// Container for authentication information to connect to the X server
447///
448/// See [Connection::connect_to_display_with_auth_info] and [Connection::connect_to_fd].
449#[derive(Copy, Clone, Debug)]
450pub struct AuthInfo<'a> {
451    /// String containing the authentication protocol name,
452    /// such as "MIT-MAGIC-COOKIE-1" or "XDM-AUTHORIZATION-1".
453    pub name: &'a str,
454    /// data interpreted in a protocol specific manner
455    pub data: &'a str,
456}
457
458/// Display info returned by [`parse_display`]
459#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
460pub struct DisplayInfo {
461    /// The hostname
462    pub host: String,
463    /// The display number
464    pub display: i32,
465    /// The screen number
466    pub screen: i32,
467}
468
469/// Parses a display string in the form documented by [X (7x)](https://linux.die.net/man/7/x).
470///
471/// Returns `Some(DisplayInfo)` on success and `None` otherwise.
472/// Has no side effects on failure.
473///
474/// If `name` empty, it uses the environment variable `DISPLAY`.
475///
476/// If `name` does not contain a screen number, `DisplayInfo::screen` is set to `0`.
477///
478/// # Example
479/// ```
480/// use xcb::{DisplayInfo, parse_display};
481///
482/// assert_eq!(parse_display(":0"), Some(DisplayInfo {
483///     host: "".to_string(),
484///     display: 0,
485///     screen: 0,
486/// }));
487/// assert_eq!(parse_display("localhost:0.1"), Some(DisplayInfo {
488///     host: "localhost".to_string(),
489///     display: 0,
490///     screen: 1,
491/// }));
492///
493/// assert!(parse_display("0").is_none());
494/// ```
495pub fn parse_display(name: &str) -> Option<DisplayInfo> {
496    let name = CString::new(name).unwrap();
497    let mut hostp: *mut c_char = ptr::null_mut();
498    let mut display = 0i32;
499    let mut screen = 0i32;
500
501    let success = unsafe {
502        xcb_parse_display(
503            name.as_ptr(),
504            &mut hostp as *mut _,
505            &mut display as *mut _,
506            &mut screen as *mut _,
507        )
508    };
509
510    if success != 0 {
511        let host = unsafe { CStr::from_ptr(hostp as *const _) }
512            .to_str()
513            .unwrap()
514            .to_string();
515
516        unsafe {
517            libc::free(hostp as *mut _);
518        }
519
520        Some(DisplayInfo {
521            host,
522            display,
523            screen,
524        })
525    } else {
526        None
527    }
528}
529
530/// A struct that serve as an identifier for internal special queue in XCB
531///
532/// See [Connection::register_for_special_xge].
533#[deprecated(note = "Broken API: use `SpecialEvent` instead")]
534#[cfg(any(feature = "xinput", feature = "present"))]
535#[derive(Debug)]
536pub struct SpecialEventId {
537    raw: *mut xcb_special_event_t,
538    stamp: Timestamp,
539}
540
541#[allow(deprecated)]
542#[cfg(any(feature = "xinput", feature = "present"))]
543impl SpecialEventId {
544    /// The X timestamp associated with this special event Id
545    pub fn stamp(&self) -> Timestamp {
546        self.stamp
547    }
548}
549
550/// A struct that serve as an identifier for internal special queue in XCB
551///
552/// See [Connection::register_for_special_event].
553#[cfg(any(feature = "xinput", feature = "present"))]
554#[derive(Debug)]
555pub struct SpecialEvent {
556    raw: *mut xcb_special_event_t,
557}
558
559// safe because XCB is thread safe.
560#[cfg(any(feature = "xinput", feature = "present"))]
561unsafe impl Send for SpecialEvent {}
562
563#[cfg(any(feature = "xinput", feature = "present"))]
564unsafe impl Sync for SpecialEvent {}
565
566/// Error type that is returned by `Connection::has_error`.
567#[derive(Debug)]
568pub enum ConnError {
569    /// xcb connection errors because of socket, pipe and other stream errors.
570    Connection,
571    /// xcb connection shutdown because of extension not supported
572    ClosedExtNotSupported,
573    /// malloc(), calloc() and realloc() error upon failure, for eg ENOMEM
574    ClosedMemInsufficient,
575    /// Connection closed, exceeding request length that server accepts.
576    ClosedReqLenExceed,
577    /// Connection closed, error during parsing display string.
578    ClosedParseErr,
579    /// Connection closed because the server does not have a screen
580    /// matching the display.
581    ClosedInvalidScreen,
582    /// Connection closed because some file descriptor passing operation failed.
583    ClosedFdPassingFailed,
584    /// XOpenDisplay returned NULL
585    #[cfg(feature = "xlib_xcb")]
586    XOpenDisplay,
587}
588
589impl ConnError {
590    fn to_str(&self) -> &str {
591        match *self {
592            ConnError::Connection => "Connection error, possible I/O error",
593            ConnError::ClosedExtNotSupported => "Connection closed, X extension not supported",
594            ConnError::ClosedMemInsufficient => "Connection closed, insufficient memory",
595            ConnError::ClosedReqLenExceed => {
596                "Connection closed, exceeded request length that server accepts."
597            }
598            ConnError::ClosedParseErr => "Connection closed, error during parsing display string",
599            ConnError::ClosedInvalidScreen => {
600                "Connection closed, the server does not have a screen matching the display"
601            }
602            ConnError::ClosedFdPassingFailed => {
603                "Connection closed, some file descriptor passing operation failed"
604            }
605            #[cfg(feature = "xlib_xcb")]
606            ConnError::XOpenDisplay => {
607                "XOpenDisplay failed to open a display. Check the $DISPLAY env var"
608            }
609        }
610    }
611}
612
613impl Display for ConnError {
614    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
615        self.to_str().fmt(f)
616    }
617}
618
619impl std::error::Error for ConnError {
620    fn description(&self) -> &str {
621        self.to_str()
622    }
623}
624
625/// The result type associated with [ConnError].
626pub type ConnResult<T> = result::Result<T, ConnError>;
627
628/// The result type associated with [ProtocolError].
629pub type ProtocolResult<T> = result::Result<T, ProtocolError>;
630
631/// The general error type for Rust-XCB.
632#[derive(Debug)]
633pub enum Error {
634    /// I/O error issued from the connection.
635    Connection(ConnError),
636    /// A protocol related error issued by the X server.
637    Protocol(ProtocolError),
638}
639
640impl Display for Error {
641    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
642        match self {
643            Error::Connection(_) => f.write_str("xcb connection error"),
644            Error::Protocol(_) => f.write_str("xcb protocol error"),
645        }
646    }
647}
648
649impl std::error::Error for Error {
650    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
651        match self {
652            Error::Connection(err) => Some(err),
653            Error::Protocol(err) => Some(err),
654        }
655    }
656}
657
658impl From<ConnError> for Error {
659    fn from(err: ConnError) -> Error {
660        Error::Connection(err)
661    }
662}
663
664impl From<ProtocolError> for Error {
665    fn from(err: ProtocolError) -> Error {
666        Error::Protocol(err)
667    }
668}
669
670/// The general result type for Rust-XCB.
671pub type Result<T> = result::Result<T, Error>;
672
673/// `Connection` is the central object of XCB.
674///
675/// It handles all communications with the X server.
676/// It dispatches the requests, receives the replies, poll/wait the events.
677/// It also resolves the errors and events from X server.
678///
679/// `Connection` is thread safe.
680///
681/// It internally wraps an `xcb_connection_t` object and
682/// will call `xcb_disconnect` when the `Connection` goes out of scope.
683pub struct Connection {
684    c: *mut xcb_connection_t,
685
686    #[cfg(feature = "xlib_xcb")]
687    dpy: *mut xlib::Display,
688
689    ext_data: Vec<ExtensionData>,
690
691    // Following field is used to handle the
692    // rare (if existing) cases of multiple connections
693    // per application.
694    // Only the first established connections is used
695    // to print the name of atoms during Debug
696    #[cfg(feature = "debug_atom_names")]
697    dbg_atom_names: bool,
698}
699
700unsafe impl Send for Connection {}
701unsafe impl Sync for Connection {}
702
703impl Connection {
704    /// Connects to the X server.
705    ///
706    /// Connects to the X server specified by `display_name.` If
707    /// `display_name` is `None,` uses the value of the `DISPLAY` environment
708    /// variable.
709    ///
710    /// If no screen is preferred, the second member of the tuple is set to 0.
711    ///
712    /// # Example
713    /// ```no_run
714    /// fn main() -> xcb::Result<()> {
715    ///     let (conn, screen) = xcb::Connection::connect(None)?;
716    ///     Ok(())
717    /// }
718    /// ```
719    pub fn connect(display_name: Option<&str>) -> ConnResult<(Connection, i32)> {
720        Self::connect_with_extensions(display_name, &[], &[])
721    }
722
723    /// Connects to the X server and cache extension data.
724    ///
725    /// Connects to the X server specified by `display_name.` If
726    /// `display_name` is `None,` uses the value of the `DISPLAY` environment
727    /// variable.
728    ///
729    /// Extension data specified by `mandatory` and `optional` is cached to allow
730    /// the resolution of events and errors in these extensions.
731    ///
732    /// If no screen is preferred, the second member of the tuple is set to 0.
733    ///
734    /// # Panics
735    /// Panics if one of the mandatory extension is not present.
736    ///
737    /// # Example
738    /// ```no_run
739    /// fn main() -> xcb::Result<()> {
740    ///     let (conn, screen) = xcb::Connection::connect_with_extensions(
741    ///         None, &[xcb::Extension::Input, xcb::Extension::Xkb], &[]
742    ///     )?;
743    ///     Ok(())
744    /// }
745    /// ```
746    pub fn connect_with_extensions(
747        display_name: Option<&str>,
748        mandatory: &[Extension],
749        optional: &[Extension],
750    ) -> ConnResult<(Connection, i32)> {
751        let mut screen_num: c_int = 0;
752        let displayname = display_name.map(|s| CString::new(s).unwrap());
753        unsafe {
754            let conn = if let Some(display) = displayname {
755                xcb_connect(display.as_ptr(), &mut screen_num)
756            } else {
757                xcb_connect(ptr::null(), &mut screen_num)
758            };
759
760            check_connection_error(conn)?;
761
762            let conn = Self::from_raw_conn_and_extensions(conn, mandatory, optional);
763            conn.has_error().map(|_| (conn, screen_num as i32))
764        }
765    }
766
767    /// Open a new connection with Xlib.
768    ///
769    /// The event queue owner defaults to Xlib.
770    /// One would need to open an XCB connection with Xlib in order to use
771    /// OpenGL.
772    ///
773    /// This function is behind the `xlib_xcb` cargo feature.
774    #[cfg(feature = "xlib_xcb")]
775    pub fn connect_with_xlib_display() -> ConnResult<(Connection, i32)> {
776        unsafe {
777            let dpy = xlib::XOpenDisplay(ptr::null());
778            if dpy.is_null() {
779                return Err(ConnError::XOpenDisplay);
780            }
781
782            check_connection_error(XGetXCBConnection(dpy))?;
783
784            let conn = Self::from_xlib_display(dpy);
785
786            conn.has_error()
787                .map(|_| (conn, xlib::XDefaultScreen(dpy) as i32))
788        }
789    }
790
791    /// Open a new connection with Xlib and cache the provided extensions data.
792    ///
793    /// Data of extensions specified by `mandatory` and `optional` is cached to allow
794    /// the resolution of events and errors in these extensions.
795    ///
796    /// The event queue owner defaults to Xlib.
797    /// One would need to open an XCB connection with Xlib in order to use
798    /// OpenGL.
799    ///
800    /// This function is behind the `xlib_xcb` cargo feature.
801    ///
802    /// # Panics
803    /// Panics if one of the mandatory extension is not present.
804    #[cfg(feature = "xlib_xcb")]
805    pub fn connect_with_xlib_display_and_extensions(
806        mandatory: &[Extension],
807        optional: &[Extension],
808    ) -> ConnResult<(Connection, i32)> {
809        unsafe {
810            let dpy = xlib::XOpenDisplay(ptr::null());
811            if dpy.is_null() {
812                return Err(ConnError::XOpenDisplay);
813            }
814
815            check_connection_error(XGetXCBConnection(dpy))?;
816
817            let conn = Self::from_xlib_display_and_extensions(dpy, mandatory, optional);
818
819            conn.has_error()
820                .map(|_| (conn, xlib::XDefaultScreen(dpy) as i32))
821        }
822    }
823
824    /// Connects to the X server with an open socket file descriptor and optional authentification info.
825    ///
826    /// Connects to an X server, given the open socket fd and the
827    /// `auth_info`. The file descriptor `fd` is bidirectionally connected to an X server.
828    /// If the connection should be unauthenticated, `auth_info` must be `None`.
829    pub fn connect_to_fd(fd: RawFd, auth_info: Option<AuthInfo<'_>>) -> ConnResult<Self> {
830        Self::connect_to_fd_with_extensions(fd, auth_info, &[], &[])
831    }
832
833    /// Connects to the X server with an open socket file descriptor and optional authentification info.
834    ///
835    /// Extension data specified by `mandatory` and `optional` is cached to allow
836    /// the resolution of events and errors in these extensions.
837    ///
838    /// Connects to an X server, given the open socket fd and the
839    /// `auth_info`. The file descriptor `fd` is bidirectionally connected to an X server.
840    /// If the connection should be unauthenticated, `auth_info` must be `None`.
841    ///
842    /// # Panics
843    /// Panics if one of the mandatory extension is not present.
844    pub fn connect_to_fd_with_extensions(
845        fd: RawFd,
846        auth_info: Option<AuthInfo<'_>>,
847        mandatory: &[Extension],
848        optional: &[Extension],
849    ) -> ConnResult<Self> {
850        let mut auth_info = auth_info.map(|auth_info| {
851            let auth_name = CString::new(auth_info.name).unwrap();
852            let auth_data = CString::new(auth_info.data).unwrap();
853
854            let auth_info = xcb_auth_info_t {
855                namelen: auth_name.as_bytes().len() as _,
856                name: auth_name.as_ptr() as *mut _,
857                datalen: auth_data.as_bytes().len() as _,
858                data: auth_data.as_ptr() as *mut _,
859            };
860            // return the strings too otherwise they would drop
861            (auth_info, auth_name, auth_data)
862        });
863
864        let ai_ptr = if let Some(auth_info) = auth_info.as_mut() {
865            &mut auth_info.0 as *mut _
866        } else {
867            ptr::null_mut()
868        };
869
870        let conn = unsafe {
871            let conn = xcb_connect_to_fd(fd, ai_ptr);
872            check_connection_error(conn)?;
873
874            Self::from_raw_conn_and_extensions(conn, mandatory, optional)
875        };
876
877        conn.has_error().map(|_| conn)
878    }
879
880    /// Connects to the X server, using an authorization information.
881    ///
882    /// Connects to the X server specified by `display_name`, using the
883    /// authorization `auth_info`. If a particular screen on that server, it is
884    /// returned in the second tuple member, which is otherwise set to `0`.
885    pub fn connect_to_display_with_auth_info(
886        display_name: Option<&str>,
887        auth_info: AuthInfo<'_>,
888    ) -> ConnResult<(Connection, i32)> {
889        Self::connect_to_display_with_auth_info_and_extensions(display_name, auth_info, &[], &[])
890    }
891
892    /// Connects to the X server, using an authorization information.
893    ///
894    /// Extension data specified by `mandatory` and `optional` is cached to allow
895    /// the resolution of events and errors in these extensions.
896    ///
897    /// Connects to the X server specified by `display_name`, using the
898    /// authorization `auth_info`. If a particular screen on that server, it is
899    /// returned in the second tuple member, which is otherwise set to `0`.
900    ///
901    /// # Panics
902    /// Panics if one of the mandatory extension is not present.
903    pub fn connect_to_display_with_auth_info_and_extensions(
904        display_name: Option<&str>,
905        auth_info: AuthInfo<'_>,
906        mandatory: &[Extension],
907        optional: &[Extension],
908    ) -> ConnResult<(Connection, i32)> {
909        let mut screen_num: c_int = 0;
910        let display_name = display_name.map(|s| CString::new(s).unwrap());
911
912        unsafe {
913            let display_name = if let Some(display_name) = &display_name {
914                display_name.as_ptr()
915            } else {
916                ptr::null()
917            };
918
919            let auth_name = CString::new(auth_info.name).unwrap();
920            let auth_data = CString::new(auth_info.data).unwrap();
921
922            let mut auth_info = xcb_auth_info_t {
923                namelen: auth_name.as_bytes().len() as _,
924                name: auth_name.as_ptr() as *mut _,
925                datalen: auth_data.as_bytes().len() as _,
926                data: auth_data.as_ptr() as *mut _,
927            };
928
929            let conn = xcb_connect_to_display_with_auth_info(
930                display_name,
931                &mut auth_info as *mut _,
932                &mut screen_num as *mut _,
933            );
934
935            check_connection_error(conn)?;
936
937            let conn = Self::from_raw_conn_and_extensions(conn, mandatory, optional);
938            conn.has_error().map(|_| (conn, screen_num as i32))
939        }
940    }
941
942    /// builds a new Connection object from an available connection
943    ///
944    /// # Safety
945    /// The `conn` pointer must point to a valid `xcb_connection_t`
946    pub unsafe fn from_raw_conn(conn: *mut xcb_connection_t) -> Connection {
947        Self::from_raw_conn_and_extensions(conn, &[], &[])
948    }
949
950    /// Builds a new `Connection` object from an available connection and cache the extension data
951    ///
952    /// Extension data specified by `mandatory` and `optional` is cached to allow
953    /// the resolution of events and errors in these extensions.
954    ///
955    /// # Panics
956    /// Panics if the connection is null or in error state.
957    /// Panics if one of the mandatory extension is not present.
958    ///
959    /// # Safety
960    /// The `conn` pointer must point to a valid `xcb_connection_t`
961    pub unsafe fn from_raw_conn_and_extensions(
962        conn: *mut xcb_connection_t,
963        mandatory: &[Extension],
964        optional: &[Extension],
965    ) -> Connection {
966        assert!(!conn.is_null());
967        assert!(check_connection_error(conn).is_ok());
968
969        #[cfg(feature = "debug_atom_names")]
970        let dbg_atom_names = {
971            if dan::DAN_CONN.is_null() {
972                dan::DAN_CONN = conn;
973                true
974            } else {
975                false
976            }
977        };
978
979        let ext_data = cache_extensions_data(conn, mandatory, optional);
980
981        #[cfg(not(feature = "xlib_xcb"))]
982        #[cfg(not(feature = "debug_atom_names"))]
983        return Connection { c: conn, ext_data };
984
985        #[cfg(not(feature = "xlib_xcb"))]
986        #[cfg(feature = "debug_atom_names")]
987        return Connection {
988            c: conn,
989            ext_data,
990            dbg_atom_names,
991        };
992
993        #[cfg(feature = "xlib_xcb")]
994        #[cfg(not(feature = "debug_atom_names"))]
995        return Connection {
996            c: conn,
997            dpy: ptr::null_mut(),
998            ext_data,
999        };
1000
1001        #[cfg(feature = "xlib_xcb")]
1002        #[cfg(feature = "debug_atom_names")]
1003        return Connection {
1004            c: conn,
1005            dpy: ptr::null_mut(),
1006            ext_data,
1007            dbg_atom_names,
1008        };
1009    }
1010
1011    /// Initialize a new `Connection` from an existing Xlib display.
1012    ///
1013    /// Wraps a `xlib::Display` and get an XCB connection from an exisiting object
1014    /// `xlib::XCloseDisplay` will be called when the returned object is dropped.
1015    ///
1016    /// This function is behind the `xlib_xcb` cargo feature.
1017    ///
1018    /// # Safety
1019    /// The `dpy` pointer must be a pointer to a valid `xlib::Display`
1020    #[cfg(feature = "xlib_xcb")]
1021    pub unsafe fn from_xlib_display(dpy: *mut xlib::Display) -> Connection {
1022        Self::from_xlib_display_and_extensions(dpy, &[], &[])
1023    }
1024
1025    /// Initialize a new `Connection` from an existing Xlib display.
1026    ///
1027    /// Wraps a `xlib::Display` and get an XCB connection from an exisiting object
1028    /// `xlib::XCloseDisplay` will be called when the returned object is dropped.
1029    ///
1030    /// Extension data specified by `mandatory` and `optional` is cached to allow
1031    /// the resolution of events and errors in these extensions.
1032    ///
1033    /// This function is behind the `xlib_xcb` cargo feature.
1034    ///
1035    /// # Panics
1036    /// Panics if the connection is null or in error state.
1037    ///
1038    /// # Safety
1039    /// The `dpy` pointer must be a pointer to a valid `xlib::Display`.
1040    #[cfg(feature = "xlib_xcb")]
1041    pub unsafe fn from_xlib_display_and_extensions(
1042        dpy: *mut xlib::Display,
1043        mandatory: &[Extension],
1044        optional: &[Extension],
1045    ) -> Connection {
1046        assert!(!dpy.is_null(), "attempt connect with null display");
1047        let c = XGetXCBConnection(dpy);
1048
1049        assert!(check_connection_error(c).is_ok());
1050
1051        #[cfg(feature = "debug_atom_names")]
1052        let dbg_atom_names = {
1053            if dan::DAN_CONN.is_null() {
1054                dan::DAN_CONN = c;
1055                true
1056            } else {
1057                false
1058            }
1059        };
1060
1061        let ext_data = cache_extensions_data(c, mandatory, optional);
1062
1063        #[cfg(feature = "debug_atom_names")]
1064        return Connection {
1065            c,
1066            dpy,
1067            ext_data,
1068            dbg_atom_names,
1069        };
1070
1071        #[cfg(not(feature = "debug_atom_names"))]
1072        return Connection { c, dpy, ext_data };
1073    }
1074
1075    /// Get the extensions activated for this connection.
1076    ///
1077    /// You may use this to check if an optional extension is present or not.
1078    ///
1079    /// # Example
1080    /// ```no_run
1081    /// # fn main() -> xcb::Result<()> {
1082    ///     // Xkb is mandatory, Input is optional
1083    ///     let (conn, screen) = xcb::Connection::connect_with_extensions(
1084    ///         None, &[xcb::Extension::Xkb], &[xcb::Extension::Input]
1085    ///     )?;
1086    ///     // now we check if Input is present or not
1087    ///     let has_input_ext = conn.active_extensions().any(|e| e == xcb::Extension::Input);
1088    /// #   Ok(())
1089    /// # }
1090    /// ```
1091    pub fn active_extensions(&self) -> impl Iterator<Item = Extension> + '_ {
1092        self.ext_data.iter().map(|eed| eed.ext)
1093    }
1094
1095    /// Get the data of the extensions activated for this connection.
1096    ///
1097    /// You may use this to manually resolve an event or an error with
1098    /// `xcb::event::resolve_event` or `xcb::error::resolve_error`.
1099    pub fn active_extensions_data(&self) -> &[ExtensionData] {
1100        &self.ext_data
1101    }
1102
1103    /// Returns the inner ffi `xcb_connection_t` pointer
1104    pub fn get_raw_conn(&self) -> *mut xcb_connection_t {
1105        self.c
1106    }
1107
1108    /// Consumes this object, returning the inner ffi `xcb_connection_t` pointer
1109    pub fn into_raw_conn(self) -> *mut xcb_connection_t {
1110        let c = self.c;
1111        mem::forget(self);
1112        c
1113    }
1114
1115    /// Returns the inner ffi `xlib::Display` pointer.
1116    ///
1117    /// This function is behind the `xlib_xcb` cargo feature.
1118    #[cfg(feature = "xlib_xcb")]
1119    pub fn get_raw_dpy(&self) -> *mut xlib::Display {
1120        self.dpy
1121    }
1122
1123    /// Sets the owner of the event queue in the case if the connection is opened
1124    /// with the Xlib interface. In that case, the default owner is Xlib.
1125    ///
1126    /// This function is behind the `xlib_xcb` cargo feature.
1127    #[cfg(feature = "xlib_xcb")]
1128    pub fn set_event_queue_owner(&self, owner: EventQueueOwner) {
1129        debug_assert!(!self.dpy.is_null());
1130        unsafe {
1131            XSetEventQueueOwner(
1132                self.dpy,
1133                match owner {
1134                    EventQueueOwner::Xcb => XCBOwnsEventQueue,
1135                    EventQueueOwner::Xlib => XlibOwnsEventQueue,
1136                },
1137            );
1138        }
1139    }
1140
1141    /// Returns the maximum request length that this server accepts.
1142    ///
1143    /// In the absence of the BIG-REQUESTS extension, returns the
1144    /// maximum request length field from the connection setup data, which
1145    /// may be as much as 65535. If the server supports BIG-REQUESTS, then
1146    /// the maximum request length field from the reply to the
1147    /// BigRequestsEnable request will be returned instead.
1148    ///
1149    /// Note that this length is measured in four-byte units, making the
1150    /// theoretical maximum lengths roughly 256kB without BIG-REQUESTS and
1151    /// 16GB with.
1152    pub fn get_maximum_request_length(&self) -> u32 {
1153        unsafe { xcb_get_maximum_request_length(self.c) }
1154    }
1155
1156    /// Prefetch the maximum request length without blocking.
1157    ///
1158    /// Without blocking, does as much work as possible toward computing
1159    /// the maximum request length accepted by the X server.
1160    ///
1161    /// Invoking this function may send the [crate::bigreq::Enable] request,
1162    /// but will not block waiting for the reply.
1163    /// [Connection::get_maximum_request_length] will return the prefetched data
1164    /// after possibly blocking while the reply is retrieved.
1165    ///
1166    /// Note that in order for this function to be fully non-blocking, the
1167    /// application must previously have called [crate::bigreq::prefetch_extension_data].
1168    pub fn prefetch_maximum_request_length(&self) {
1169        unsafe {
1170            xcb_prefetch_maximum_request_length(self.c);
1171        }
1172    }
1173
1174    /// Allocates an XID for a new object.
1175    ///
1176    /// Returned value is typically used in requests such as `CreateWindow`.
1177    ///
1178    /// # Example
1179    /// ```no_run
1180    /// # use xcb::x;
1181    /// # fn main() -> xcb::Result<()> {
1182    /// # let conn = xcb::Connection::connect(None)?.0;
1183    /// let window: x::Window = conn.generate_id();
1184    /// # Ok(())
1185    /// # }
1186    /// ```
1187    pub fn generate_id<T: XidNew>(&self) -> T {
1188        unsafe { XidNew::new(xcb_generate_id(self.c)) }
1189    }
1190
1191    /// Forces any buffered output to be written to the server.
1192    ///
1193    /// Forces any buffered output to be written to the server. Blocks
1194    /// until the write is complete.
1195    ///
1196    /// There are several occasions ones want to flush the connection.
1197    /// One of them is before entering or re-entering the event loop after performing unchecked requests.
1198    ///
1199    /// The main difference between `flush` and `check_request` is that `flush` will not report protocol errors.
1200    /// If a protocol error is emitted by an unchecked void request, it will be reported through the event loop.
1201    ///
1202    /// See also: [wait_for_event](Connection::wait_for_event), [check_request](Connection::check_request),
1203    /// [send_and_check_request](Connection::send_and_check_request).
1204    pub fn flush(&self) -> ConnResult<()> {
1205        unsafe {
1206            let ret = xcb_flush(self.c);
1207            if ret > 0 {
1208                Ok(())
1209            } else {
1210                self.has_error()?;
1211                unreachable!()
1212            }
1213        }
1214    }
1215
1216    /// Resolve an xcb_generic_event_t pointer into an Event.
1217    /// # Safety
1218    /// The caller is repsonsible to ensure that the `ev` pointer is not NULL.
1219    /// The ownership of the pointer is effectively transferred to the
1220    /// returned Event and it will be destroyed when the Event is
1221    /// dropped.
1222    pub unsafe fn resolve_event(&self, ev: &mut xcb_generic_event_t) -> Event {
1223        event::resolve_event(ev, &self.ext_data)
1224    }
1225
1226    /// Resolve an xcb_generic_error_t pointer into an Error.
1227    /// # Safety
1228    /// The caller is repsonsible to ensure that the `err` pointer is not NULL.
1229    /// The ownership of the pointer is effectively transferred to the
1230    /// returned Error and it will be destroyed when the Error is
1231    /// dropped.
1232    pub unsafe fn resolve_error(&self, err: &mut xcb_generic_error_t) -> error::ProtocolError {
1233        error::resolve_error(err, &self.ext_data)
1234    }
1235
1236    /// Blocks and returns the next event or error from the server.
1237    ///
1238    /// # Example
1239    /// ```no_run
1240    /// use xcb::x;
1241    /// fn main() -> xcb::Result<()> {
1242    /// #   let conn = xcb::Connection::connect(None)?.0;
1243    ///     // ...
1244    ///     loop {
1245    ///         let event = match conn.wait_for_event() {
1246    ///             Err(xcb::Error::Connection(err)) => {
1247    ///                 panic!("unexpected I/O error: {}", err);
1248    ///             }
1249    ///             Err(xcb::Error::Protocol(xcb::ProtocolError::X(x::Error::Font(err), _req_name))) => {
1250    ///                 // may be this particular error is fine?
1251    ///                 continue;
1252    ///             }
1253    ///             Err(xcb::Error::Protocol(err)) => {
1254    ///                 panic!("unexpected protocol error: {:#?}", err);
1255    ///             }
1256    ///             Ok(event) => event,
1257    ///         };
1258    ///         match event {
1259    ///             xcb::Event::X(x::Event::KeyPress(ev)) => {
1260    ///                 // do stuff with the key press
1261    ///             }
1262    ///             // handle other events
1263    ///             _ => {
1264    ///                 break Ok(());
1265    ///             }
1266    ///         }
1267    ///     }
1268    ///  }
1269    /// ```
1270    pub fn wait_for_event(&self) -> Result<Event> {
1271        unsafe {
1272            let ev = xcb_wait_for_event(self.c);
1273            self.handle_wait_for_event(ev)
1274        }
1275    }
1276
1277    /// Returns the next event or error from the server without blocking.
1278    ///
1279    /// Returns the next event or error from the server, if one is
1280    /// available. If no event is available, that
1281    /// might be because an I/O error like connection close occurred while
1282    /// attempting to read the next event, in which case the connection is
1283    /// shut down when this function returns.
1284    pub fn poll_for_event(&self) -> Result<Option<Event>> {
1285        unsafe {
1286            let ev = xcb_poll_for_event(self.c);
1287            self.handle_poll_for_event(ev)
1288        }
1289    }
1290
1291    /// Returns the next event without reading from the connection.
1292    ///
1293    /// This is a version of [Connection::poll_for_event] that only examines the
1294    /// event queue for new events. The function doesn't try to read new
1295    /// events from the connection if no queued events are found.
1296    ///
1297    /// This function is useful for callers that know in advance that all
1298    /// interesting events have already been read from the connection. For
1299    /// example, callers might use [Connection::wait_for_reply] and be interested
1300    /// only of events that preceded a specific reply.
1301    pub fn poll_for_queued_event(&self) -> ProtocolResult<Option<Event>> {
1302        unsafe {
1303            let ev = xcb_poll_for_queued_event(self.c);
1304            if ev.is_null() {
1305                Ok(None)
1306            } else if is_error(ev) {
1307                Err(error::resolve_error(ev as *mut _, &self.ext_data))
1308            } else {
1309                Ok(Some(event::resolve_event(ev, &self.ext_data)))
1310            }
1311        }
1312    }
1313
1314    /// Start listening for a special event.
1315    ///
1316    /// Effectively creates an internal special queue for this event
1317    /// XGE events are only defined in the `xinput` and `present` extensions
1318    ///
1319    /// This function is present only if either of the `xinput` or `present` cargo features are active.
1320    #[deprecated(note = "Broken API: use `register_for_special_event` instead")]
1321    #[cfg(any(feature = "xinput", feature = "present"))]
1322    #[allow(deprecated)]
1323    pub fn register_for_special_xge<XGE: GeEvent>(&self) -> SpecialEventId {
1324        unsafe {
1325            let ext: *mut xcb_extension_t = match XGE::EXTENSION {
1326                #[cfg(feature = "xinput")]
1327                Extension::Input => ptr::addr_of_mut!(xinput::FFI_EXT),
1328                #[cfg(feature = "present")]
1329                Extension::Present => ptr::addr_of_mut!(present::FFI_EXT),
1330                _ => unreachable!("only Input and Present have XGE events"),
1331            };
1332
1333            let mut stamp: Timestamp = 0;
1334
1335            let raw = xcb_register_for_special_xge(self.c, ext, XGE::NUMBER, &mut stamp as *mut _);
1336
1337            SpecialEventId { raw, stamp }
1338        }
1339    }
1340
1341    /// Stop listening to a special event
1342    #[deprecated(note = "use `unregister_for_special_event` instead")]
1343    #[cfg(any(feature = "xinput", feature = "present"))]
1344    #[allow(deprecated)]
1345    pub fn unregister_for_special_xge(&self, se: SpecialEventId) {
1346        unsafe {
1347            xcb_unregister_for_special_event(self.c, se.raw);
1348        }
1349    }
1350
1351    /// Returns the next event from a special queue, blocking until one arrives
1352    #[deprecated(note = "Broken API: use `wait_for_special_event2` instead")]
1353    #[cfg(any(feature = "xinput", feature = "present"))]
1354    #[allow(deprecated)]
1355    pub fn wait_for_special_event(&self, se: SpecialEventId) -> Result<Event> {
1356        unsafe {
1357            let ev = xcb_wait_for_special_event(self.c, se.raw);
1358            self.handle_wait_for_event(ev)
1359        }
1360    }
1361
1362    /// Returns the next event from a special queue
1363    #[deprecated(note = "Broken API: use `poll_for_special_event2` instead")]
1364    #[cfg(any(feature = "xinput", feature = "present"))]
1365    #[allow(deprecated)]
1366    pub fn poll_for_special_event(&self, se: SpecialEventId) -> Result<Option<Event>> {
1367        unsafe {
1368            let ev = xcb_poll_for_special_event(self.c, se.raw);
1369            self.handle_poll_for_event(ev)
1370        }
1371    }
1372
1373    /// Start listening for a special event.
1374    ///
1375    /// Effectively creates an internal special queue for this event
1376    /// XGE events are only defined in the `xinput` and `present` extensions
1377    ///
1378    /// This function is present only if either of the `xinput` or `present` cargo features are active.
1379    #[cfg(any(feature = "xinput", feature = "present"))]
1380    pub fn register_for_special_event<EID: Xid>(
1381        &self,
1382        extension: Extension,
1383        eid: EID,
1384    ) -> SpecialEvent {
1385        unsafe {
1386            let ext: *mut xcb_extension_t = match extension {
1387                #[cfg(feature = "xinput")]
1388                Extension::Input => ptr::addr_of_mut!(xinput::FFI_EXT),
1389                #[cfg(feature = "present")]
1390                Extension::Present => ptr::addr_of_mut!(present::FFI_EXT),
1391                _ => unreachable!("only Input and Present have XGE events"),
1392            };
1393
1394            let raw = xcb_register_for_special_xge(self.c, ext, eid.resource_id(), ptr::null_mut());
1395
1396            SpecialEvent { raw }
1397        }
1398    }
1399
1400    /// Stop listening to a special event
1401    #[cfg(any(feature = "xinput", feature = "present"))]
1402    pub fn unregister_for_special_event(&self, se: SpecialEvent) {
1403        unsafe {
1404            xcb_unregister_for_special_event(self.c, se.raw);
1405        }
1406    }
1407
1408    /// Returns the next event from a special queue, blocking until one arrives
1409    #[cfg(any(feature = "xinput", feature = "present"))]
1410    pub fn wait_for_special_event2(&self, se: &SpecialEvent) -> Result<Event> {
1411        unsafe {
1412            let ev = xcb_wait_for_special_event(self.c, se.raw);
1413            self.handle_wait_for_event(ev)
1414        }
1415    }
1416
1417    /// Returns the next event from a special queue
1418    #[cfg(any(feature = "xinput", feature = "present"))]
1419    pub fn poll_for_special_event2(&self, se: &SpecialEvent) -> Result<Option<Event>> {
1420        unsafe {
1421            let ev = xcb_poll_for_special_event(self.c, se.raw);
1422            self.handle_poll_for_event(ev)
1423        }
1424    }
1425
1426    /// Discards the reply for a request.
1427    ///
1428    /// Discards the reply for a request. Additionally, any error generated
1429    /// by the request is also discarded (unless it was an _unchecked request
1430    /// and the error has already arrived).
1431    ///
1432    /// This function will not block even if the reply is not yet available.
1433    fn discard_reply<C: Cookie>(&self, cookie: C) {
1434        unsafe {
1435            xcb_discard_reply64(self.c, cookie.sequence());
1436        }
1437    }
1438
1439    /// Access the data returned by the server.
1440    ///
1441    /// Accessor for the data returned by the server when the connection
1442    /// was initialized. This data includes
1443    /// - the server's required format for images,
1444    /// - a list of available visuals,
1445    /// - a list of available screens,
1446    /// - the server's maximum request length (in the absence of the
1447    /// BIG-REQUESTS extension),
1448    /// - and other assorted information.
1449    ///
1450    /// See the X protocol specification for more details.
1451    pub fn get_setup(&self) -> &Setup {
1452        unsafe {
1453            let ptr = xcb_get_setup(self.c);
1454            // let len = <&Setup as WiredIn>::compute_wire_len(ptr, ());
1455            let mut _offset = 0;
1456            <&Setup as WiredIn>::unserialize(ptr, (), &mut _offset)
1457        }
1458    }
1459
1460    /// Test whether the connection has shut down due to a fatal error.
1461    ///
1462    /// Some errors that occur in the context of a connection
1463    /// are unrecoverable. When such an error occurs, the
1464    /// connection is shut down and further operations on the
1465    /// connection have no effect.
1466    pub fn has_error(&self) -> ConnResult<()> {
1467        unsafe { check_connection_error(self.c) }
1468    }
1469
1470    /// Send a request to the X server.
1471    ///
1472    /// This function never blocks. A cookie is returned to keep track of the request.
1473    /// If the request expect a reply, the cookie can be used to retrieve the reply with
1474    /// [Connection::wait_for_reply].
1475    ///
1476    /// # Example
1477    /// ```no_run
1478    /// # use xcb::x;
1479    /// # fn main() -> xcb::Result<()> {
1480    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1481    /// #   let setup = conn.get_setup();
1482    /// #   let screen = setup.roots().nth(screen_num as usize).unwrap();
1483    /// #   let window: x::Window = conn.generate_id();
1484    ///     // Example of void request.
1485    ///     // Error (if any) will be sent to the event loop (see `wait_for_event`).
1486    ///     // In this case, the cookie can be discarded.
1487    ///     conn.send_request(&x::CreateWindow {
1488    ///         depth: x::COPY_FROM_PARENT as u8,
1489    ///         wid: window,
1490    ///         parent: screen.root(),
1491    ///         x: 0,
1492    ///         y: 0,
1493    ///         width: 150,
1494    ///         height: 150,
1495    ///         border_width: 10,
1496    ///         class: x::WindowClass::InputOutput,
1497    ///         visual: screen.root_visual(),
1498    ///         value_list: &[
1499    ///             x::Cw::BackPixel(screen.white_pixel()),
1500    ///             x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS),
1501    ///         ],
1502    ///     });
1503    ///
1504    ///     // Example of request with reply. The error (if any) is obtained with the reply.
1505    ///     let cookie = conn.send_request(&x::InternAtom {
1506    ///         only_if_exists: true,
1507    ///         name: b"WM_PROTOCOLS",
1508    ///     });
1509    ///     let wm_protocols_atom: x::Atom = conn
1510    ///             .wait_for_reply(cookie)?
1511    ///             .atom();
1512    /// #   Ok(())
1513    /// # }
1514    /// ```
1515    pub fn send_request<R>(&self, req: &R) -> R::Cookie
1516    where
1517        R: Request,
1518    {
1519        unsafe { R::Cookie::from_sequence(req.raw_request(self, !R::IS_VOID)) }
1520    }
1521
1522    /// Send a checked request to the X server.
1523    ///
1524    /// Checked requests do not expect a reply, but the returned cookie can be used to check for
1525    /// errors using `Connection::check_request`.
1526    ///
1527    /// # Example
1528    /// ```no_run
1529    /// # use xcb::x;
1530    /// # fn main() -> xcb::Result<()> {
1531    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1532    /// #   let window: x::Window = conn.generate_id();
1533    ///     let cookie = conn.send_request_checked(&x::MapWindow { window });
1534    ///     conn.check_request(cookie)?;
1535    /// #   Ok(())
1536    /// # }
1537    /// ```
1538    pub fn send_request_checked<R>(&self, req: &R) -> VoidCookieChecked
1539    where
1540        R: RequestWithoutReply,
1541    {
1542        unsafe { VoidCookieChecked::from_sequence(req.raw_request(self, true)) }
1543    }
1544
1545    /// Send an unchecked request to the X server.
1546    ///
1547    /// Unchecked requests expect a reply that is to be retrieved by [Connection::wait_for_reply_unchecked].
1548    /// Unchecked means that the error is not checked when the reply is fetched. Instead, the error will
1549    /// be sent to the event loop
1550    ///
1551    /// # Example
1552    /// ```no_run
1553    /// # use xcb::x;
1554    /// # fn main() -> xcb::Result<()> {
1555    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1556    ///     let cookie = conn.send_request_unchecked(&x::InternAtom {
1557    ///         only_if_exists: true,
1558    ///         name: b"WM_PROTOCOLS",
1559    ///     });
1560    ///     let wm_protocols_atom: Option<x::Atom> = conn
1561    ///             .wait_for_reply_unchecked(cookie)?
1562    ///             .map(|rep| rep.atom());
1563    /// #   Ok(())
1564    /// # }
1565    /// ```
1566    pub fn send_request_unchecked<R>(&self, req: &R) -> R::CookieUnchecked
1567    where
1568        R: RequestWithReply,
1569    {
1570        unsafe { R::CookieUnchecked::from_sequence(req.raw_request(self, false)) }
1571    }
1572
1573    /// Check a checked request for errors.
1574    ///
1575    /// The cookie supplied to this function must have resulted
1576    /// from a call to [Connection::send_request_checked].  This function will block
1577    /// until one of two conditions happens.  If an error is received, it will be
1578    /// returned.  If a reply to a subsequent request has already arrived, no error
1579    /// can arrive for this request, so this function will return `Ok(())`.
1580    ///
1581    /// Note that this function will perform a sync if needed to ensure that the
1582    /// sequence number will advance beyond that provided in cookie; this is a
1583    /// convenience to avoid races in determining whether the sync is needed.
1584    ///
1585    /// # Example
1586    /// ```no_run
1587    /// # use xcb::x;
1588    /// # fn main() -> xcb::Result<()> {
1589    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1590    /// #   let window: x::Window = conn.generate_id();
1591    ///     conn.check_request(conn.send_request_checked(&x::MapWindow { window }))?;
1592    /// #   Ok(())
1593    /// # }
1594    /// ```
1595    pub fn check_request(&self, cookie: VoidCookieChecked) -> ProtocolResult<()> {
1596        let cookie = xcb_void_cookie_t {
1597            seq: cookie.sequence() as u32,
1598        };
1599        let error = unsafe { xcb_request_check(self.c, cookie) };
1600        if error.is_null() {
1601            Ok(())
1602        } else {
1603            unsafe {
1604                let res = error::resolve_error(error, &self.ext_data);
1605                Err(res)
1606            }
1607        }
1608    }
1609
1610    /// Send the request to the server and check it.
1611    ///
1612    /// This is a sugar for `conn.check_request(conn.send_request_checked(req))`
1613    ///
1614    /// This method is useful as well in place of code sending a void request
1615    /// and flushing the connection right after. Checking the request effectively
1616    /// flushes the connection, but in addition reports possible protocol errors
1617    /// at the calling site instead of reporting them through the event loop.
1618    ///
1619    /// # Example
1620    /// ```no_run
1621    /// # use xcb::x;
1622    /// # fn main() -> xcb::Result<()> {
1623    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1624    /// #   let window: x::Window = conn.generate_id();
1625    ///     conn.send_and_check_request(&x::MapWindow { window })?;
1626    /// #   Ok(())
1627    /// # }
1628    /// ```
1629    pub fn send_and_check_request<R>(&self, req: &R) -> ProtocolResult<()>
1630    where
1631        R: RequestWithoutReply,
1632    {
1633        self.check_request(self.send_request_checked(req))
1634    }
1635
1636    /// Gets the reply of a previous request, or an error if one occurred.
1637    ///
1638    /// This is blocking; it does not return until the reply has been received. For the non-blocking
1639    /// version, see [`poll_for_reply`].
1640    ///
1641    /// # Example
1642    /// ```no_run
1643    /// # use xcb::x;
1644    /// # fn main() -> xcb::Result<()> {
1645    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1646    ///     let cookie = conn.send_request(&x::InternAtom {
1647    ///         only_if_exists: true,
1648    ///         name: b"WM_PROTOCOLS",
1649    ///     });
1650    ///     let wm_protocols_atom: x::Atom = conn
1651    ///             .wait_for_reply(cookie)?
1652    ///             .atom();
1653    /// #   Ok(())
1654    /// # }
1655    /// ```
1656    ///
1657    /// [`poll_for_reply`]: Self::poll_for_reply
1658    pub fn wait_for_reply<C>(&self, cookie: C) -> Result<C::Reply>
1659    where
1660        C: CookieWithReplyChecked,
1661    {
1662        unsafe {
1663            let mut error: *mut xcb_generic_error_t = ptr::null_mut();
1664            let reply = xcb_wait_for_reply64(self.c, cookie.sequence(), &mut error as *mut _);
1665            self.handle_reply_checked::<C>(reply, error)
1666        }
1667    }
1668
1669    /// Get the reply of a previous unchecked request.
1670    ///
1671    /// If an error occurred, `None` is returned and the error will be delivered to the event loop.
1672    ///
1673    /// This is blocking; it does not return until the reply has been received. For the non-blocking
1674    /// version, see [`poll_for_reply_unchecked`].
1675    ///
1676    /// # Example
1677    /// ```no_run
1678    /// # use xcb::x;
1679    /// # fn main() -> xcb::Result<()> {
1680    /// #   let (conn, screen_num) = xcb::Connection::connect(None)?;
1681    ///     let cookie = conn.send_request_unchecked(&x::InternAtom {
1682    ///         only_if_exists: true,
1683    ///         name: b"WM_PROTOCOLS",
1684    ///     });
1685    ///     let wm_protocols_atom: Option<x::Atom> = conn
1686    ///             .wait_for_reply_unchecked(cookie)?  // connection error may happen
1687    ///             .map(|rep| rep.atom());
1688    /// #   Ok(())
1689    /// # }
1690    /// ```
1691    ///
1692    /// [`poll_for_reply_unchecked`]: Self::poll_for_reply_unchecked
1693    pub fn wait_for_reply_unchecked<C>(&self, cookie: C) -> ConnResult<Option<C::Reply>>
1694    where
1695        C: CookieWithReplyUnchecked,
1696    {
1697        unsafe {
1698            let reply = xcb_wait_for_reply64(self.c, cookie.sequence(), ptr::null_mut());
1699            self.handle_reply_unchecked::<C>(reply)
1700        }
1701    }
1702
1703    /// Gets the reply of a previous request if it has been received, or an error if one occurred.
1704    ///
1705    /// This is non-blocking; if no reply has been received yet, it returns [`None`]. For the
1706    /// blocking version, see [`wait_for_reply`].
1707    ///
1708    /// # Examples
1709    /// ```no_run
1710    /// # use xcb::x;
1711    /// # fn main() -> xcb::Result<()> {
1712    /// #     let (conn, screen_num) = xcb::Connection::connect(None)?;
1713    /// let (wm_protocols_cookie, wm_name_cookie) = (
1714    ///     conn.send_request(&x::InternAtom {
1715    ///         only_if_exists: true,
1716    ///         name: b"WM_PROTOCOLS",
1717    ///     }),
1718    ///     conn.send_request(&x::InternAtom {
1719    ///         only_if_exists: true,
1720    ///         name: b"WM_NAME",
1721    ///     }),
1722    /// );
1723    /// let (wm_protocols_atom, wm_name_atom) = {
1724    ///     let (
1725    ///         mut wm_protocols_atom,
1726    ///         mut wm_name_atom,
1727    ///     ) = (None, None);
1728    ///
1729    ///     loop {
1730    ///         // If `wm_protocols_atom` is yet to be received, poll for it.
1731    ///         if wm_protocols_atom.is_none() {
1732    ///             wm_protocols_atom = conn
1733    ///                 .poll_for_reply(&wm_protocols_cookie)
1734    ///                 .transpose()?
1735    ///                 .map(|reply| reply.atom());
1736    ///         }
1737    ///         // If `wm_name_atom` is yet to be received, poll for it.
1738    ///         if wm_name_atom.is_none() {
1739    ///             wm_name_atom = conn
1740    ///                 .poll_for_reply(&wm_name_cookie)
1741    ///                 .transpose()?
1742    ///                 .map(|reply| reply.atom());
1743    ///         }
1744    ///
1745    ///         // If both `wm_protocols_atom` and `wm_name_atom` have been
1746    ///         // received, break from the loop.
1747    ///         if let (
1748    ///             Some(wm_protocols_atom),
1749    ///             Some(wm_name_atom),
1750    ///         ) = (wm_protocols_atom, wm_name_atom) {
1751    ///             break (wm_protocols_atom, wm_name_atom);
1752    ///         }
1753    ///     }
1754    /// };
1755    /// #     Ok(())
1756    /// # }
1757    /// ```
1758    ///
1759    /// [`wait_for_reply`]: Self::wait_for_reply
1760    pub fn poll_for_reply<C>(&self, cookie: &C) -> Option<Result<C::Reply>>
1761    where
1762        C: CookieWithReplyChecked,
1763    {
1764        unsafe {
1765            let mut error: *mut xcb_generic_error_t = ptr::null_mut();
1766            let mut reply: *mut c_void = ptr::null_mut();
1767
1768            let received = xcb_poll_for_reply64(
1769                self.c,
1770                cookie.sequence(),
1771                &mut reply as *mut _,
1772                &mut error as *mut _,
1773            );
1774
1775            match received {
1776                0 => None,
1777                1 => Some(self.handle_reply_checked::<C>(reply, error)),
1778                _ => panic!("unexpected return value from xcb_poll_for_reply64"),
1779            }
1780        }
1781    }
1782
1783    /// Gets the reply of a previous unchecked request if it has been received.
1784    ///
1785    /// If an error occurred, [`None`] is returned and the error is delivered to the event loop.
1786    ///
1787    /// This is non-blocking; if no reply has been received yet, it returns
1788    /// <code>[Some]\([None])</code>. For the blocking version, see [`wait_for_reply_unchecked`].
1789    ///
1790    /// # Examples
1791    /// ```no_run
1792    /// # use xcb::x;
1793    /// # fn main() -> xcb::Result<()> {
1794    /// #     let (conn, screen_num) = xcb::Connection::connect(None)?;
1795    /// let (wm_protocols_cookie, wm_name_cookie) = (
1796    ///     conn.send_request_unchecked(&x::InternAtom {
1797    ///         only_if_exists: true,
1798    ///         name: b"WM_PROTOCOLS",
1799    ///     }),
1800    ///     conn.send_request_unchecked(&x::InternAtom {
1801    ///         only_if_exists: true,
1802    ///         name: b"WM_NAME",
1803    ///     }),
1804    /// );
1805    /// let (wm_protocols_atom, wm_name_atom) = {
1806    ///     let (
1807    ///         mut wm_protocols_atom,
1808    ///         mut wm_name_atom,
1809    ///     ) = (Some(None), Some(None));
1810    ///
1811    ///     loop {
1812    ///         // If `wm_protocols_atom` is yet to be received, poll for it.
1813    ///         if let Some(None) = wm_protocols_atom {
1814    ///             wm_protocols_atom = conn
1815    ///                 // connection error may happen
1816    ///                 .poll_for_reply_unchecked(&wm_protocols_cookie)
1817    ///                 .transpose()?
1818    ///                 .map(|result| result.map(|reply| reply.atom()));
1819    ///         }
1820    ///         // If `wm_name_atom` is yet to be received, poll for it.
1821    ///         if let Some(None) = wm_name_atom {
1822    ///             wm_name_atom = conn
1823    ///                 // connection error may happen
1824    ///                 .poll_for_reply_unchecked(&wm_name_cookie)
1825    ///                 .transpose()?
1826    ///                 .map(|result| result.map(|reply| reply.atom()));
1827    ///         }
1828    ///
1829    ///         match (wm_protocols_atom, wm_name_atom) {
1830    ///             // If either `wm_protocols_atom` or `wm_name_atom` hasn't
1831    ///             // been received, continue the loop.
1832    ///             (Some(None), _) | (_, Some(None)) => continue,
1833    ///
1834    ///             // Otherwise, if both have been received, break from the
1835    ///             // loop.
1836    ///             (
1837    ///                 wm_protocols_atom,
1838    ///                 wm_name_atom,
1839    ///             ) => break (
1840    ///                 wm_protocols_atom.flatten(),
1841    ///                 wm_name_atom.flatten(),
1842    ///             ),
1843    ///         }
1844    ///     }
1845    /// };
1846    /// #     Ok(())
1847    /// # }
1848    /// ```
1849    ///
1850    /// [`wait_for_reply_unchecked`]: Self::wait_for_reply_unchecked
1851    pub fn poll_for_reply_unchecked<C>(&self, cookie: &C) -> Option<ConnResult<Option<C::Reply>>>
1852    where
1853        C: CookieWithReplyUnchecked,
1854    {
1855        unsafe {
1856            let mut reply: *mut c_void = ptr::null_mut();
1857
1858            let received = xcb_poll_for_reply64(
1859                self.c,
1860                cookie.sequence(),
1861                &mut reply as *mut _,
1862                ptr::null_mut(),
1863            );
1864
1865            match received {
1866                0 => None,
1867                1 => Some(self.handle_reply_unchecked::<C>(reply)),
1868                _ => panic!("unexpected return value from xcb_poll_for_reply64"),
1869            }
1870        }
1871    }
1872
1873    /// Obtain number of bytes read from the connection.
1874    ///
1875    /// Returns cumulative number of bytes received from the connection.
1876    ///
1877    /// This retrieves the total number of bytes read from this connection,
1878    /// to be used for diagnostic/monitoring/informative purposes.
1879    ///
1880    /// Since: libxcb 1.14
1881    #[cfg(feature = "libxcb_v1_14")]
1882    pub fn total_read(&self) -> usize {
1883        unsafe { xcb_total_read(self.c) as usize }
1884    }
1885
1886    /// Obtain number of bytes written to the connection.
1887    ///
1888    /// Returns cumulative number of bytes sent to the connection.
1889    ///
1890    /// This retrieves the total number of bytes written to this connection,
1891    /// to be used for diagnostic/monitoring/informative purposes.
1892    ///
1893    /// Since: libxcb 1.14
1894    #[cfg(feature = "libxcb_v1_14")]
1895    pub fn total_written(&self) -> usize {
1896        unsafe { xcb_total_written(self.c) as usize }
1897    }
1898}
1899
1900impl Connection {
1901    unsafe fn handle_wait_for_event(&self, ev: *mut xcb_generic_event_t) -> Result<Event> {
1902        if ev.is_null() {
1903            self.has_error()?;
1904            panic!("xcb_wait_for_event returned null with I/O error");
1905        } else if is_error(ev) {
1906            Err(error::resolve_error(ev as *mut _, &self.ext_data).into())
1907        } else {
1908            Ok(event::resolve_event(ev, &self.ext_data))
1909        }
1910    }
1911
1912    unsafe fn handle_poll_for_event(&self, ev: *mut xcb_generic_event_t) -> Result<Option<Event>> {
1913        if ev.is_null() {
1914            self.has_error()?;
1915            Ok(None)
1916        } else if is_error(ev) {
1917            Err(error::resolve_error(ev as *mut _, &self.ext_data).into())
1918        } else {
1919            Ok(Some(event::resolve_event(ev, &self.ext_data)))
1920        }
1921    }
1922
1923    unsafe fn handle_reply_checked<C>(
1924        &self,
1925        reply: *mut c_void,
1926        error: *mut xcb_generic_error_t,
1927    ) -> Result<C::Reply>
1928    where
1929        C: CookieWithReplyChecked,
1930    {
1931        match (reply.is_null(), error.is_null()) {
1932            (true, true) => {
1933                self.has_error()?;
1934                unreachable!("xcb_wait_for_reply64 returned null without I/O error");
1935            }
1936            (true, false) => {
1937                let error = error::resolve_error(error, &self.ext_data);
1938                Err(error.into())
1939            }
1940            (false, true) => Ok(C::Reply::from_raw(reply as *const u8)),
1941            (false, false) => unreachable!("xcb_wait_for_reply64 returned two pointers"),
1942        }
1943    }
1944
1945    unsafe fn handle_reply_unchecked<C>(&self, reply: *mut c_void) -> ConnResult<Option<C::Reply>>
1946    where
1947        C: CookieWithReplyUnchecked,
1948    {
1949        if reply.is_null() {
1950            self.has_error()?;
1951            Ok(None)
1952        } else {
1953            Ok(Some(C::Reply::from_raw(reply as *const u8)))
1954        }
1955    }
1956}
1957
1958impl AsRef<Connection> for Connection {
1959    fn as_ref(&self) -> &Connection {
1960        self
1961    }
1962}
1963
1964impl AsRawFd for Connection {
1965    fn as_raw_fd(&self) -> RawFd {
1966        unsafe { xcb_get_file_descriptor(self.c) }
1967    }
1968}
1969
1970// SAFETY: We provide a valid xcb_connection_t that is valid for as long as required by the trait.
1971#[cfg(feature = "as-raw-xcb-connection")]
1972unsafe impl as_raw_xcb_connection::AsRawXcbConnection for Connection {
1973    fn as_raw_xcb_connection(&self) -> *mut as_raw_xcb_connection::xcb_connection_t {
1974        self.get_raw_conn().cast()
1975    }
1976}
1977
1978impl Drop for Connection {
1979    fn drop(&mut self) {
1980        #[cfg(feature = "debug_atom_names")]
1981        if self.dbg_atom_names {
1982            unsafe {
1983                dan::DAN_CONN = ptr::null_mut();
1984            }
1985        }
1986
1987        #[cfg(not(feature = "xlib_xcb"))]
1988        unsafe {
1989            xcb_disconnect(self.c);
1990        }
1991
1992        #[cfg(feature = "xlib_xcb")]
1993        unsafe {
1994            if self.dpy.is_null() {
1995                xcb_disconnect(self.c);
1996            } else {
1997                xlib::XCloseDisplay(self.dpy);
1998            }
1999        }
2000    }
2001}
2002
2003#[cfg(feature = "debug_atom_names")]
2004mod dan {
2005    use super::{Connection, Xid};
2006    use crate::ffi::base::xcb_connection_t;
2007    use crate::x;
2008
2009    use std::fmt;
2010    use std::mem;
2011    use std::ptr;
2012    use std::str;
2013
2014    pub(crate) static mut DAN_CONN: *mut xcb_connection_t = ptr::null_mut();
2015
2016    impl fmt::Debug for x::Atom {
2017        #[allow(clippy::print_in_format_impl)]
2018        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2019            if self.resource_id() == 0 {
2020                return f.write_str("ATOM_NONE");
2021            }
2022
2023            let conn = unsafe { Connection::from_raw_conn(DAN_CONN) };
2024
2025            let cookie = conn.send_request(&x::GetAtomName { atom: *self });
2026            let reply = conn.wait_for_reply(cookie).map_err(|err| {
2027                eprintln!(
2028                    "Error during fmt::Debug of x::Atom (fetching atom name): {:#?}",
2029                    err
2030                );
2031                fmt::Error
2032            })?;
2033
2034            let name = reply.name().to_utf8();
2035            f.write_fmt(format_args!("Atom(\"{}\" ; {})", name, self.resource_id()))?;
2036
2037            mem::forget(conn);
2038            Ok(())
2039        }
2040    }
2041}
2042
2043unsafe fn check_connection_error(conn: *mut xcb_connection_t) -> ConnResult<()> {
2044    match xcb_connection_has_error(conn) {
2045        0 => Ok(()),
2046        XCB_CONN_ERROR => Err(ConnError::Connection),
2047        XCB_CONN_CLOSED_EXT_NOTSUPPORTED => Err(ConnError::ClosedExtNotSupported),
2048        XCB_CONN_CLOSED_MEM_INSUFFICIENT => Err(ConnError::ClosedMemInsufficient),
2049        XCB_CONN_CLOSED_REQ_LEN_EXCEED => Err(ConnError::ClosedReqLenExceed),
2050        XCB_CONN_CLOSED_PARSE_ERR => Err(ConnError::ClosedParseErr),
2051        XCB_CONN_CLOSED_INVALID_SCREEN => Err(ConnError::ClosedInvalidScreen),
2052        XCB_CONN_CLOSED_FDPASSING_FAILED => Err(ConnError::ClosedFdPassingFailed),
2053        code => unreachable!("unexpected error code from XCB: {}", code),
2054    }
2055}
2056
2057unsafe fn is_error(ev: *mut xcb_generic_event_t) -> bool {
2058    debug_assert!(!ev.is_null());
2059    (*ev).response_type == 0
2060}
2061
2062bitflags! {
2063    pub(crate) struct RequestFlags: u32 {
2064        const NONE = 0;
2065        const CHECKED = 1;
2066        const RAW = 2;
2067        const DISCARD_REPLY = 4;
2068        const REPLY_FDS = 8;
2069    }
2070}
2071
2072/// Compute the necessary padding after `base` to have `align` alignment
2073pub(crate) fn align_pad(base: usize, align: usize) -> usize {
2074    debug_assert!(align.is_power_of_two(), "`align` must be a power of two");
2075
2076    let base = base as isize;
2077    let align = align as isize;
2078    (-base & (align - 1)) as usize
2079}
2080
2081#[test]
2082fn test_align_pad() {
2083    // align 1
2084    assert_eq!(align_pad(0, 1), 0);
2085    assert_eq!(align_pad(1234, 1), 0);
2086    assert_eq!(align_pad(1235, 1), 0);
2087    // align 2
2088    assert_eq!(align_pad(0, 2), 0);
2089    assert_eq!(align_pad(1233, 2), 1);
2090    assert_eq!(align_pad(1234, 2), 0);
2091    // align 4
2092    assert_eq!(align_pad(0, 4), 0);
2093    assert_eq!(align_pad(12, 4), 0);
2094    assert_eq!(align_pad(13, 4), 3);
2095    assert_eq!(align_pad(14, 4), 2);
2096    assert_eq!(align_pad(15, 4), 1);
2097    assert_eq!(align_pad(16, 4), 0);
2098}