1 /*
2  * Copyright (C) 2013 James Miller <james@aatch.net>
3  * Copyright (c) 2016
4  *         Remi Thebault <remi.thebault@gmail.com>
5  *         Thomas Bracht Laumann Jespersen <laumann.thomas@gmail.com>
6  *
7  * Permission is hereby granted, free of charge, to any
8  * person obtaining a copy of this software and associated
9  * documentation files (the "Software"), to deal in the
10  * Software without restriction, including without
11  * limitation the rights to use, copy, modify, merge,
12  * publish, distribute, sublicense, and/or sell copies of
13  * the Software, and to permit persons to whom the Software
14  * is furnished to do so, subject to the following
15  * conditions:
16  *
17  * The above copyright notice and this permission notice
18  * shall be included in all copies or substantial portions
19  * of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22  * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
23  * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
24  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
25  * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
28  * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  */
31 
32 
33 use xproto::*;
34 use ffi::base::*;
35 use ffi::xproto::*;
36 #[cfg(feature="xlib_xcb")]
37 use ffi::xlib_xcb::*;
38 
39 #[cfg(feature="xlib_xcb")]
40 use x11::xlib;
41 
42 use libc::{self, c_int, c_char, c_void};
43 use std::option::Option;
44 
45 use std::error;
46 use std::fmt;
47 use std::mem;
48 use std::ptr::{null, null_mut};
49 use std::marker::PhantomData;
50 // std::num::Zero is unstable in rustc 1.5 => remove the Zero defined
51 // hereunder as soon as Zero gets stabilized (or replaced by something else)
52 //use std::num::Zero;
53 use std::cmp::Ordering;
54 use std::ops::{BitAnd, BitOr};
55 use std::ffi::CString;
56 use std::os::unix::io::{AsRawFd, RawFd};
57 
58 
59 /// Current protocol version
60 pub const X_PROTOCOL: u32 = 11;
61 /// Current minor version
62 pub const X_PROTOCOL_REVISION: u32 = 0;
63 /// X_TCP_PORT + display number = server port for TCP transport
64 pub const X_TCP_PORT: u32 = 6000;
65 
66 
67 /// Opaque type used as key for `Connection::get_extension_data`
68 pub type Extension = xcb_extension_t;
69 
70 
71 /// `xcb::NONE` is the universal null resource or null atom parameter value
72 /// for many core X requests
73 pub const NONE: u32 = 0;
74 /// `xcb::COPY_FROM_PARENT` can be used for many `xcb::create_window` parameters
75 pub const COPY_FROM_PARENT: u32 = 0;
76 /// `xcb::CURRENT_TIME` can be used in most requests that take an `xcb::Timestamp`
77 pub const CURRENT_TIME: u32 = 0;
78 /// `xcb::NO_SYMBOL` fills in unused entries in `xcb::Keysym` tables
79 pub const NO_SYMBOL: u32 = 0;
80 
81 
82 
83 
84 /// `StructPtr` is a wrapper for pointer to struct owned by XCB
85 /// that must not be freed
86 /// it is instead bound to the lifetime of its parent that it borrows immutably
87 pub struct StructPtr<'a, T: 'a> {
88     pub ptr: *mut T,
89     phantom: PhantomData<&'a T>
90 }
91 
92 
93 /// `Event` wraps a pointer to `xcb_*_event_t`
94 /// this pointer will be freed when the `Event` goes out of scope
95 pub struct Event<T> {
96    pub ptr: *mut T
97 }
98 
99 impl<T> Event<T> {
response_type(&self) -> u8100     pub fn response_type(&self) -> u8 {
101         unsafe {
102             let gev : *mut xcb_generic_event_t = mem::transmute(self.ptr);
103             (*gev).response_type
104         }
105     }
106 }
107 
108 impl<T> Drop for Event<T> {
drop(&mut self)109     fn drop(&mut self) {
110         unsafe {
111             libc::free(self.ptr as *mut c_void);
112         }
113     }
114 }
115 
116 #[cfg(feature="thread")]
117 unsafe impl<T> Send for Event<T> {}
118 #[cfg(feature="thread")]
119 unsafe impl<T> Sync for Event<T> {}
120 
121 /// Casts the generic event to the right event. Assumes that the given
122 /// event is really the correct type.
cast_event<'r, T>(event : &'r GenericEvent) -> &'r T123 pub unsafe fn cast_event<'r, T>(event : &'r GenericEvent) -> &'r T {
124     mem::transmute(event)
125 }
126 
127 
128 
129 
130 /// `Error` wraps a pointer to `xcb_*_error_t`
131 /// this pointer will be freed when the `Error` goes out of scope
132 #[derive(Debug)]
133 pub struct Error<T> {
134     pub ptr: *mut T
135 }
136 
137 impl<T> Error<T> {
response_type(&self) -> u8138     pub fn response_type(&self) -> u8 {
139         unsafe {
140             let ger : *mut xcb_generic_error_t = mem::transmute(self.ptr);
141             (*ger).response_type
142         }
143     }
error_code(&self) -> u8144     pub fn error_code(&self) -> u8 {
145         unsafe {
146             let ger : *mut xcb_generic_error_t = mem::transmute(self.ptr);
147             (*ger).error_code
148         }
149     }
150 }
151 
152 impl<T> Drop for Error<T> {
drop(&mut self)153     fn drop(&mut self) {
154         unsafe {
155             libc::free(self.ptr as *mut c_void);
156         }
157     }
158 }
159 
160 impl<T> fmt::Display for Error<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result161     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162         write!(f, "xcb::Error {{ response_type: {}, error_code: {} }}",
163                self.response_type(),
164                self.error_code())
165     }
166 }
167 impl<T: fmt::Debug> error::Error for Error<T> {
description(&self) -> &str168     fn description(&self) -> &str {
169         "xcb::Error"
170     }
171 }
172 
173 // Error are readonly and can be safely sent and shared with other threads
174 unsafe impl<T> Send for Error<T> {}
175 unsafe impl<T> Sync for Error<T> {}
176 
177 /// Casts the generic error to the right error. Assumes that the given
178 /// error is really the correct type.
cast_error<'r, T>(error : &'r GenericError) -> &'r T179 pub unsafe fn cast_error<'r, T>(error : &'r GenericError) -> &'r T {
180     mem::transmute(error)
181 }
182 
183 
184 
185 
186 /// wraps a cookie as returned by a request function.
187 /// Instantiations of `Cookie` that are not `VoidCookie`
188 /// should provide a `get_reply` method to return a `Reply`
189 pub struct Cookie<'a, T: Copy> {
190     pub cookie: T,
191     pub conn: &'a Connection,
192     pub checked: bool
193 }
194 
195 pub type VoidCookie<'a> = Cookie<'a, xcb_void_cookie_t>;
196 
197 impl<'a> VoidCookie<'a> {
request_check(&self) -> Result<(), GenericError>198     pub fn request_check(&self) -> Result<(), GenericError> {
199         unsafe {
200             let c : xcb_void_cookie_t = mem::transmute(self.cookie);
201             let err = xcb_request_check(self.conn.get_raw_conn(), c);
202 
203             if err.is_null() {
204                 Ok(())
205             } else {
206                 Err(GenericError{ ptr: err })
207             }
208         }
209     }
210 }
211 
212 #[cfg(feature="thread")]
213 unsafe impl<'a, T: Copy> Send for Cookie<'a, T> {}
214 #[cfg(feature="thread")]
215 unsafe impl<'a, T: Copy> Sync for Cookie<'a, T> {}
216 
217 
218 
219 /// Wraps a pointer to a `xcb_*_reply_t`
220 /// the pointer is freed when the `Reply` goes out of scope
221 pub struct Reply<T> {
222     pub ptr: *mut T
223 }
224 
225 impl<T> Drop for Reply<T> {
drop(&mut self)226     fn drop(&mut self) {
227         unsafe {
228             libc::free(self.ptr as *mut c_void);
229         }
230     }
231 }
232 
233 #[cfg(feature="thread")]
234 unsafe impl<T> Send for Reply<T> {}
235 #[cfg(feature="thread")]
236 unsafe impl<T> Sync for Reply<T> {}
237 
238 
239 pub type GenericEvent = Event<xcb_generic_event_t>;
240 pub type GenericError = Error<xcb_generic_error_t>;
241 pub type GenericReply = Reply<xcb_generic_reply_t>;
242 
243 
244 
245 
246 //TODO: Implement wrapper functions for constructing auth_info
247 pub type AuthInfo = xcb_auth_info_t;
248 
249 
250 
251 #[cfg(feature="xlib_xcb")]
252 pub enum EventQueueOwner {
253     Xcb,
254     Xlib
255 }
256 
257 
258 /// Error type that is returned by `Connection::has_error`
259 #[derive(Debug)]
260 pub enum ConnError {
261     /// xcb connection errors because of socket, pipe and other stream errors.
262     Connection,
263     /// xcb connection shutdown because of extension not supported
264     ClosedExtNotSupported,
265     /// malloc(), calloc() and realloc() error upon failure, for eg ENOMEM
266     ClosedMemInsufficient,
267     /// Connection closed, exceeding request length that server accepts.
268     ClosedReqLenExceed,
269     /// Connection closed, error during parsing display string.
270     ClosedParseErr,
271     /// Connection closed because the server does not have a screen
272     /// matching the display.
273     ClosedInvalidScreen,
274     /// Connection closed because some FD passing operation failed
275     ClosedFdPassingFailed,
276 }
277 
278 impl ConnError {
to_str(&self) -> &str279     fn to_str(&self) -> &str {
280         match *self {
281             ConnError::Connection => "Connection error, possible I/O error",
282             ConnError::ClosedExtNotSupported => "Connection closed, X extension not supported",
283             ConnError::ClosedMemInsufficient => "Connection closed, insufficient memory",
284             ConnError::ClosedReqLenExceed => "Connection closed, exceeded request length that server accepts.",
285             ConnError::ClosedParseErr => "Connection closed, error during parsing display string",
286             ConnError::ClosedInvalidScreen => "Connection closed, the server does not have a screen matching the display",
287             ConnError::ClosedFdPassingFailed => "Connection closed, file-descriptor passing operation failed",
288         }
289     }
290 }
291 
292 impl fmt::Display for ConnError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result293     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294         self.to_str().fmt(f)
295     }
296 }
297 
298 impl error::Error for ConnError {
description(&self) -> &str299     fn description(&self) -> &str {
300         self.to_str()
301     }
302 }
303 
304 pub type ConnResult<T> = Result<T, ConnError>;
305 
306 
307 /// xcb::Connection handles communication with the X server.
308 /// It wraps an `xcb_connection_t` object and
309 /// will call `xcb_disconnect` when the `Connection` goes out of scope
310 pub struct Connection {
311     c:   *mut xcb_connection_t,
312     #[cfg(feature="xlib_xcb")]
313     dpy: *mut xlib::Display,
314 }
315 
316 #[cfg(feature="thread")]
317 unsafe impl Send for Connection {}
318 #[cfg(feature="thread")]
319 unsafe impl Sync for Connection {}
320 
321 
322 impl Connection {
323 
324     /// Forces any buffered output to be written to the server. Blocks
325     /// until the write is complete.
326     ///
327     /// Return `true` on success, `false` otherwise.
flush(&self) -> bool328     pub fn flush(&self) -> bool {
329         unsafe {
330             xcb_flush(self.c) > 0
331         }
332     }
333 
334     /// Returns the maximum request length that this server accepts.
335     ///
336     /// In the absence of the BIG-REQUESTS extension, returns the
337     /// maximum request length field from the connection setup data, which
338     /// may be as much as 65535. If the server supports BIG-REQUESTS, then
339     /// the maximum request length field from the reply to the
340     /// BigRequestsEnable request will be returned instead.
341     ///
342     /// Note that this length is measured in four-byte units, making the
343     /// theoretical maximum lengths roughly 256kB without BIG-REQUESTS and
344     /// 16GB with.
get_maximum_request_length(&self) -> u32345     pub fn get_maximum_request_length(&self) -> u32 {
346         unsafe {
347             xcb_get_maximum_request_length(self.c)
348         }
349     }
350 
351     /// Prefetch the maximum request length without blocking.
352     ///
353     /// Without blocking, does as much work as possible toward computing
354     /// the maximum request length accepted by the X server.
355     ///
356     /// Invoking this function may cause a call to xcb_big_requests_enable,
357     /// but will not block waiting for the reply.
358     /// xcb_get_maximum_request_length will return the prefetched data
359     /// after possibly blocking while the reply is retrieved.
360     ///
361     /// Note that in order for this function to be fully non-blocking, the
362     /// application must previously have called
363     /// `c.prefetch_extension_data(xcb::big_requests::id())` and the reply
364     /// must have already arrived.
prefetch_maximum_request_length(&self)365     pub fn prefetch_maximum_request_length(&self) {
366         unsafe {
367             xcb_prefetch_maximum_request_length(self.c);
368         }
369     }
370 
371     /// Returns the next event or error from the server.
372     ///
373     /// Returns the next event or error from the server, or returns `None` in
374     /// the event of an I/O error. Blocks until either an event or error
375     /// arrive, or an I/O error occurs.
wait_for_event(&self) -> Option<GenericEvent>376     pub fn wait_for_event(&self) -> Option<GenericEvent> {
377         unsafe {
378             let event = xcb_wait_for_event(self.c);
379             if event.is_null() {
380                 None
381             } else {
382                 Some(GenericEvent { ptr: event })
383             }
384         }
385     }
386 
387     /// Returns the next event or error from the server.
388     ///
389     /// Returns the next event or error from the server, if one is
390     /// available, or returns `None` otherwise. If no event is available, that
391     /// might be because an I/O error like connection close occurred while
392     /// attempting to read the next event, in which case the connection is
393     /// shut down when this function returns.
poll_for_event(&self) -> Option<GenericEvent>394     pub fn poll_for_event(&self) -> Option<GenericEvent> {
395         unsafe {
396             let event = xcb_poll_for_event(self.c);
397             if event.is_null() {
398                 None
399             } else {
400                 Some(GenericEvent { ptr: event })
401             }
402         }
403     }
404 
405     /// Returns the next event without reading from the connection.
406     ///
407     /// This is a version of `poll_for_event` that only examines the
408     /// event queue for new events. The function doesn't try to read new
409     /// events from the connection if no queued events are found.
410     ///
411     /// This function is useful for callers that know in advance that all
412     /// interesting events have already been read from the connection. For
413     /// example, callers might use `wait_for_reply` and be interested
414     /// only of events that preceded a specific reply.
poll_for_queued_event(&self) -> Option<GenericEvent>415     pub fn poll_for_queued_event(&self) -> Option<GenericEvent> {
416         unsafe {
417             let event = xcb_poll_for_queued_event(self.c);
418             if event.is_null() {
419                 None
420             } else {
421                 Some(GenericEvent { ptr: event })
422             }
423         }
424     }
425 
426     /// Access the data returned by the server.
427     ///
428     /// Accessor for the data returned by the server when the `Connection`
429     /// was initialized. This data includes
430     /// - the server's required format for images,
431     /// - a list of available visuals,
432     /// - a list of available screens,
433     /// - the server's maximum request length (in the absence of the
434     /// BIG-REQUESTS extension),
435     /// - and other assorted information.
436     ///
437     /// See the X protocol specification for more details.
get_setup(&self) -> Setup438     pub fn get_setup(&self) -> Setup {
439         unsafe {
440 
441             let setup = xcb_get_setup(self.c);
442             if setup.is_null() {
443                 panic!("NULL setup on connection")
444             }
445             mem::transmute(setup)
446         }
447     }
448 
449     /// Test whether the connection has shut down due to a fatal error.
450     ///
451     /// Some errors that occur in the context of a `Connection`
452     /// are unrecoverable. When such an error occurs, the
453     /// connection is shut down and further operations on the
454     /// `Connection` have no effect, but memory will not be freed until
455     /// the `Connection` is dropped.
has_error(&self) -> ConnResult<()>456     pub fn has_error(&self) -> ConnResult<()> {
457         unsafe {
458             match xcb_connection_has_error(self.c) {
459                 0 => { Ok(()) },
460                 XCB_CONN_ERROR => { Err(ConnError::Connection) },
461                 XCB_CONN_CLOSED_EXT_NOTSUPPORTED =>
462                         { Err(ConnError::ClosedExtNotSupported) },
463                 XCB_CONN_CLOSED_MEM_INSUFFICIENT =>
464                         { Err(ConnError::ClosedMemInsufficient) },
465                 XCB_CONN_CLOSED_REQ_LEN_EXCEED =>
466                         { Err(ConnError::ClosedReqLenExceed) },
467                 XCB_CONN_CLOSED_PARSE_ERR =>
468                         { Err(ConnError::ClosedParseErr) },
469                 XCB_CONN_CLOSED_INVALID_SCREEN =>
470                         { Err(ConnError::ClosedInvalidScreen) },
471                 XCB_CONN_CLOSED_FDPASSING_FAILED =>
472                         { Err(ConnError::ClosedFdPassingFailed) },
473                 _ => {
474                     warn!("XCB: unexpected error code from xcb_connection_has_error");
475                     warn!("XCB: Default to ConnError::Connection");
476                     Err(ConnError::Connection)
477                 },
478             }
479         }
480     }
481 
482     /// Allocates an XID for a new object.
483     ///
484     /// Allocates an XID for a new object. Typically used just prior to
485     /// various object creation functions, such as `xcb::create_window`.
generate_id(&self) -> u32486     pub fn generate_id(&self) -> u32 {
487         unsafe {
488             xcb_generate_id(self.c)
489         }
490     }
491 
492     /// Returns the inner ffi `xcb_connection_t` pointer
get_raw_conn(&self) -> *mut xcb_connection_t493     pub fn get_raw_conn(&self) -> *mut xcb_connection_t {
494         self.c
495     }
496 
497     /// Consumes this object, returning the inner ffi `xcb_connection_t` pointer
into_raw_conn(self) -> *mut xcb_connection_t498     pub fn into_raw_conn(self) -> *mut xcb_connection_t {
499         let c = self.c;
500         mem::forget(self);
501         c
502     }
503 
504     /// Returns the inner ffi `xlib::Display` pointer.
505     #[cfg(feature="xlib_xcb")]
get_raw_dpy(&self) -> *mut xlib::Display506     pub fn get_raw_dpy(&self) -> *mut xlib::Display {
507         self.dpy
508     }
509 
510     /// Prefetch of extension data into the extension cache
511     ///
512     /// This function allows a "prefetch" of extension data into the
513     /// extension cache. Invoking the function may cause a call to
514     /// xcb_query_extension, but will not block waiting for the
515     /// reply. xcb_get_extension_data will return the prefetched data after
516     /// possibly blocking while it is retrieved.
prefetch_extension_data(&self, ext: &mut Extension)517     pub fn prefetch_extension_data(&self, ext: &mut Extension) {
518         unsafe {
519             xcb_prefetch_extension_data(self.c, ext);
520         }
521     }
522 
523     /// Caches reply information from QueryExtension requests.
524     ///
525     /// This function is the primary interface to the "extension cache",
526     /// which caches reply information from QueryExtension
527     /// requests. Invoking this function may cause a call to
528     /// xcb_query_extension to retrieve extension information from the
529     /// server, and may block until extension data is received from the
530     /// server.
get_extension_data<'a>(&'a self, ext: &mut Extension) -> Option<QueryExtensionData<'a>>531     pub fn get_extension_data<'a>(&'a self, ext: &mut Extension)
532             -> Option<QueryExtensionData<'a>> {
533         unsafe {
534             let ptr = xcb_get_extension_data(self.c, ext);
535             if !ptr.is_null() { Some(QueryExtensionData { ptr: ptr, _marker: PhantomData }) }
536             else { None }
537         }
538     }
539 
540     /// Sets the owner of the event queue in the case if the connection is opened
541     /// with the XLib interface. the default owner is XLib.
542     #[cfg(feature="xlib_xcb")]
set_event_queue_owner(&self, owner: EventQueueOwner)543     pub fn set_event_queue_owner(&self, owner: EventQueueOwner) {
544         debug_assert!(!self.dpy.is_null());
545         unsafe {
546             XSetEventQueueOwner(self.dpy, match owner {
547                 EventQueueOwner::Xcb => XCBOwnsEventQueue,
548                 EventQueueOwner::Xlib => XlibOwnsEventQueue
549             });
550         }
551     }
552 
553 
554 
555     /// Connects to the X server.
556     /// `displayname:` The name of the display.
557     ///
558     /// Connects to the X server specified by `displayname.` If
559     /// `displayname` is `None,` uses the value of the DISPLAY environment
560     /// variable.
561     ///
562     /// Returns Ok(connection object, preferred screen) in case of success, or
563     /// Err(ConnError) in case of error. If no screen is preferred, the second
564     /// member of the tuple is set to 0.
connect(displayname: Option<&str>) -> ConnResult<(Connection, i32)>565     pub fn connect(displayname: Option<&str>) -> ConnResult<(Connection, i32)> {
566         unsafe {
567             let display = displayname.map(|s| CString::new(s).unwrap());
568             let mut screen_num : c_int = 0;
569             let cconn = xcb_connect(
570                 display.map_or(null(), |s| s.as_ptr()),
571                 &mut screen_num
572             );
573 
574             // xcb doc says that a valid object is always returned
575             // so we simply assert without handling this in the return
576             assert!(!cconn.is_null(), "had incorrect pointer");
577 
578             let conn = Self::from_raw_conn(cconn);
579 
580             conn.has_error().map(|_| {
581                 (conn, screen_num as i32)
582             })
583         }
584     }
585 
586     /// Open a new connection with XLib.
587     /// The event queue owner defaults to XLib
588     /// One would need to open an XCB connection with Xlib in order to use
589     /// OpenGL.
590     #[cfg(feature="xlib_xcb")]
connect_with_xlib_display() -> ConnResult<(Connection, i32)>591     pub fn connect_with_xlib_display() -> ConnResult<(Connection, i32)> {
592         unsafe {
593             let dpy = xlib::XOpenDisplay(null());
594             let cconn = XGetXCBConnection(dpy);
595             assert!(!dpy.is_null() && !cconn.is_null(),
596                 "XLib could not connect to the X server");
597 
598             let conn = Connection { c: cconn, dpy: dpy };
599 
600             conn.has_error().map(|_| {
601                 (conn, xlib::XDefaultScreen(dpy) as i32)
602             })
603         }
604     }
605 
606     /// wraps a `xlib::Display` and get an XCB connection from an exisiting object
607     /// `xlib::XCloseDisplay` will be called when the returned object is dropped
608     #[cfg(feature="xlib_xcb")]
new_from_xlib_display(dpy: *mut xlib::Display) -> Connection609     pub unsafe fn new_from_xlib_display(dpy: *mut xlib::Display) -> Connection {
610         assert!(!dpy.is_null(), "attempt connect with null display");
611         Connection {
612             c: XGetXCBConnection(dpy),
613             dpy: dpy
614         }
615     }
616 
617 
618 
619     /// Connects to the X server, using an authorization information.
620     /// display: The name of the display.
621     /// auth_info: The authorization information.
622     /// screen: A pointer to a preferred screen number.
623     /// Returns A newly allocated `Connection` structure.
624     ///
625     /// Connects to the X server specified by displayname, using the
626     /// authorization auth.
627     /// The second member of the returned tuple is the preferred screen, or 0
connect_with_auth_info(display: Option<&str>, auth_info: &AuthInfo) -> ConnResult<(Connection, i32)>628     pub fn connect_with_auth_info(display: Option<&str>, auth_info: &AuthInfo)
629     -> ConnResult<(Connection, i32)> {
630         unsafe {
631             let display = display.map(|s| CString::new(s).unwrap());
632             let mut screen_num : c_int = 0;
633             let cconn = xcb_connect_to_display_with_auth_info(
634                 display.map_or(null(), |s| s.as_ptr()),
635                 mem::transmute(auth_info),
636                 &mut screen_num
637             );
638 
639             // xcb doc says that a valid object is always returned
640             // so we simply assert without handling this in the return
641             assert!(!cconn.is_null(), "had incorrect pointer");
642 
643             let conn = Self::from_raw_conn(cconn);
644 
645             conn.has_error().map(|_| {
646                 (conn, screen_num as i32)
647             })
648         }
649     }
650 
651     /// builds a new Connection object from an available connection
from_raw_conn(conn: *mut xcb_connection_t) -> Connection652     pub unsafe fn from_raw_conn(conn: *mut xcb_connection_t) -> Connection {
653         assert!(!conn.is_null());
654 
655         #[cfg(not(feature="xlib_xcb"))]
656         return Connection {
657             c:  conn,
658         };
659 
660         #[cfg(feature="xlib_xcb")]
661         return Connection {
662             c:  conn,
663             dpy: null_mut(),
664         };
665     }
666 }
667 
668 impl AsRawFd for Connection {
as_raw_fd(&self) -> RawFd669     fn as_raw_fd(&self) -> RawFd {
670         unsafe {
671             xcb_get_file_descriptor(self.c)
672         }
673     }
674 }
675 
676 impl Drop for Connection {
drop(&mut self)677     fn drop(&mut self) {
678         #[cfg(not(feature="xlib_xcb"))]
679         unsafe {
680             xcb_disconnect(self.c);
681         }
682 
683         #[cfg(feature="xlib_xcb")]
684         unsafe {
685             if self.dpy.is_null() {
686                 xcb_disconnect(self.c);
687             }
688             else {
689                 xlib::XCloseDisplay(self.dpy);
690             }
691         }
692     }
693 }
694 
695 
696 // Mimics xproto::QueryExtensionReply, but without the Drop trait.
697 // Used for Connection::get_extension_data whose returned value
698 // must not be freed.
699 // Named QueryExtensionData to avoid name collision
700 pub struct QueryExtensionData<'a> {
701     ptr: *const xcb_query_extension_reply_t,
702     _marker: PhantomData<&'a ()>,
703 }
704 
705 impl<'a> QueryExtensionData<'a> {
present(&self) -> bool706     pub fn present(&self) -> bool {
707         unsafe {
708             (*self.ptr).present != 0
709         }
710     }
major_opcode(&self) -> u8711     pub fn major_opcode(&self) -> u8 {
712         unsafe {
713             (*self.ptr).major_opcode
714         }
715     }
first_event(&self) -> u8716     pub fn first_event(&self) -> u8 {
717         unsafe {
718             (*self.ptr).first_event
719         }
720     }
first_error(&self) -> u8721     pub fn first_error(&self) -> u8 {
722         unsafe {
723             (*self.ptr).first_error
724         }
725     }
726 }
727 
728 
729 pub trait Zero {
zero() -> Self730     fn zero() -> Self;
731 }
732 
zero() -> u8733 impl Zero for u8    { fn zero() -> u8    {0} }
zero() -> u16734 impl Zero for u16   { fn zero() -> u16   {0} }
zero() -> u32735 impl Zero for u32   { fn zero() -> u32   {0} }
zero() -> u64736 impl Zero for u64   { fn zero() -> u64   {0} }
zero() -> usize737 impl Zero for usize { fn zero() -> usize {0} }
zero() -> i8738 impl Zero for i8    { fn zero() -> i8    {0} }
zero() -> i16739 impl Zero for i16   { fn zero() -> i16   {0} }
zero() -> i32740 impl Zero for i32   { fn zero() -> i32   {0} }
zero() -> i64741 impl Zero for i64   { fn zero() -> i64   {0} }
zero() -> isize742 impl Zero for isize { fn zero() -> isize {0} }
zero() -> f32743 impl Zero for f32   { fn zero() -> f32   {0f32} }
zero() -> f64744 impl Zero for f64   { fn zero() -> f64   {0f64} }
745 
746 /// pack bitfields tuples into vector usable for FFI requests
747 /// ```
748 ///     let values = [
749 ///         (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS),
750 ///         (xcb::CW_BACK_PIXEL, 0xffffffff),
751 ///     ];
752 ///     let ffi_values = (
753 ///         xcb::CW_BACK_PIXEL | xcb::CW_EVENT_MASK,
754 ///         [
755 ///             Oxffffffff,
756 ///             xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS,
757 ///             0
758 ///         ]
759 ///     );
760 ///     assert_eq!(pack_bitfield(&mut values), ffi_values);
761 /// ```
762 
pack_bitfield<T, L>(bf : &mut Vec<(T,L)>) -> (T, Vec<L>) where T: Ord + Zero + Copy + BitAnd<Output=T> + BitOr<Output=T>, L: Copy763 pub fn pack_bitfield<T, L>(bf : &mut Vec<(T,L)>) -> (T, Vec<L>)
764     where T: Ord + Zero + Copy + BitAnd<Output=T> + BitOr<Output=T>,
765           L: Copy {
766 	bf.sort_by(|a,b| {
767         let &(a, _) = a;
768         let &(b, _) = b;
769         if a < b {
770             Ordering::Less
771         }
772         else if a > b {
773             Ordering::Greater
774         }
775         else {
776             Ordering::Equal
777         }
778     });
779 
780     let mut mask = T::zero();
781     let mut list: Vec<L> = Vec::new();
782 
783     for el in bf.iter() {
784         let &(f, v) = el;
785         if mask & f > T::zero() {
786             continue;
787         } else {
788             mask = mask|f;
789             list.push(v);
790         }
791     }
792 
793     (mask, list)
794 }
795