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}