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