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 + CookieSeq> {
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             std::mem::forget(self);
204             if err.is_null() {
205                 Ok(())
206             } else {
207                 Err(GenericError { ptr: err })
208             }
209         }
210     }
211 }
212 
213 impl CookieSeq for xcb_void_cookie_t {
sequence(&self) -> libc::c_uint214     fn sequence(&self) -> libc::c_uint {
215         self.sequence
216     }
217 }
218 
219 pub trait CookieSeq {
sequence(&self) -> libc::c_uint220     fn sequence(&self) -> libc::c_uint;
221 }
222 
223 impl<'a, T: Copy + CookieSeq> Drop for Cookie<'a, T> {
drop(&mut self)224     fn drop(&mut self) {
225         unsafe { xcb_discard_reply(self.conn.get_raw_conn(), self.cookie.sequence()) };
226     }
227 }
228 
229 #[cfg(feature="thread")]
230 unsafe impl<'a, T: Copy + CookieSeq> Send for Cookie<'a, T> {}
231 #[cfg(feature="thread")]
232 unsafe impl<'a, T: Copy + CookieSeq> Sync for Cookie<'a, T> {}
233 
234 
235 
236 /// Wraps a pointer to a `xcb_*_reply_t`
237 /// the pointer is freed when the `Reply` goes out of scope
238 pub struct Reply<T> {
239     pub ptr: *mut T
240 }
241 
242 impl<T> Drop for Reply<T> {
drop(&mut self)243     fn drop(&mut self) {
244         unsafe {
245             libc::free(self.ptr as *mut c_void);
246         }
247     }
248 }
249 
250 #[cfg(feature="thread")]
251 unsafe impl<T> Send for Reply<T> {}
252 #[cfg(feature="thread")]
253 unsafe impl<T> Sync for Reply<T> {}
254 
255 
256 pub type GenericEvent = Event<xcb_generic_event_t>;
257 pub type GenericError = Error<xcb_generic_error_t>;
258 pub type GenericReply = Reply<xcb_generic_reply_t>;
259 
260 
261 
262 
263 //TODO: Implement wrapper functions for constructing auth_info
264 pub type AuthInfo = xcb_auth_info_t;
265 
266 
267 
268 #[cfg(feature="xlib_xcb")]
269 pub enum EventQueueOwner {
270     Xcb,
271     Xlib
272 }
273 
274 
275 /// Error type that is returned by `Connection::has_error`
276 #[derive(Debug)]
277 pub enum ConnError {
278     /// xcb connection errors because of socket, pipe and other stream errors.
279     Connection,
280     /// xcb connection shutdown because of extension not supported
281     ClosedExtNotSupported,
282     /// malloc(), calloc() and realloc() error upon failure, for eg ENOMEM
283     ClosedMemInsufficient,
284     /// Connection closed, exceeding request length that server accepts.
285     ClosedReqLenExceed,
286     /// Connection closed, error during parsing display string.
287     ClosedParseErr,
288     /// Connection closed because the server does not have a screen
289     /// matching the display.
290     ClosedInvalidScreen,
291     /// Connection closed because some FD passing operation failed
292     ClosedFdPassingFailed,
293 }
294 
295 impl ConnError {
to_str(&self) -> &str296     fn to_str(&self) -> &str {
297         match *self {
298             ConnError::Connection => "Connection error, possible I/O error",
299             ConnError::ClosedExtNotSupported => "Connection closed, X extension not supported",
300             ConnError::ClosedMemInsufficient => "Connection closed, insufficient memory",
301             ConnError::ClosedReqLenExceed => "Connection closed, exceeded request length that server accepts.",
302             ConnError::ClosedParseErr => "Connection closed, error during parsing display string",
303             ConnError::ClosedInvalidScreen => "Connection closed, the server does not have a screen matching the display",
304             ConnError::ClosedFdPassingFailed => "Connection closed, file-descriptor passing operation failed",
305         }
306     }
307 }
308 
309 impl fmt::Display for ConnError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result310     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
311         self.to_str().fmt(f)
312     }
313 }
314 
315 impl error::Error for ConnError {
description(&self) -> &str316     fn description(&self) -> &str {
317         self.to_str()
318     }
319 }
320 
321 pub type ConnResult<T> = Result<T, ConnError>;
322 
323 
324 /// xcb::Connection handles communication with the X server.
325 /// It wraps an `xcb_connection_t` object and
326 /// will call `xcb_disconnect` when the `Connection` goes out of scope
327 pub struct Connection {
328     c:   *mut xcb_connection_t,
329     #[cfg(feature="xlib_xcb")]
330     dpy: *mut xlib::Display,
331 }
332 
333 #[cfg(feature="thread")]
334 unsafe impl Send for Connection {}
335 #[cfg(feature="thread")]
336 unsafe impl Sync for Connection {}
337 
338 
339 impl Connection {
340 
341     /// Forces any buffered output to be written to the server. Blocks
342     /// until the write is complete.
343     ///
344     /// Return `true` on success, `false` otherwise.
flush(&self) -> bool345     pub fn flush(&self) -> bool {
346         unsafe {
347             xcb_flush(self.c) > 0
348         }
349     }
350 
351     /// Returns the maximum request length that this server accepts.
352     ///
353     /// In the absence of the BIG-REQUESTS extension, returns the
354     /// maximum request length field from the connection setup data, which
355     /// may be as much as 65535. If the server supports BIG-REQUESTS, then
356     /// the maximum request length field from the reply to the
357     /// BigRequestsEnable request will be returned instead.
358     ///
359     /// Note that this length is measured in four-byte units, making the
360     /// theoretical maximum lengths roughly 256kB without BIG-REQUESTS and
361     /// 16GB with.
get_maximum_request_length(&self) -> u32362     pub fn get_maximum_request_length(&self) -> u32 {
363         unsafe {
364             xcb_get_maximum_request_length(self.c)
365         }
366     }
367 
368     /// Prefetch the maximum request length without blocking.
369     ///
370     /// Without blocking, does as much work as possible toward computing
371     /// the maximum request length accepted by the X server.
372     ///
373     /// Invoking this function may cause a call to xcb_big_requests_enable,
374     /// but will not block waiting for the reply.
375     /// xcb_get_maximum_request_length will return the prefetched data
376     /// after possibly blocking while the reply is retrieved.
377     ///
378     /// Note that in order for this function to be fully non-blocking, the
379     /// application must previously have called
380     /// `c.prefetch_extension_data(xcb::big_requests::id())` and the reply
381     /// must have already arrived.
prefetch_maximum_request_length(&self)382     pub fn prefetch_maximum_request_length(&self) {
383         unsafe {
384             xcb_prefetch_maximum_request_length(self.c);
385         }
386     }
387 
388     /// Returns the next event or error from the server.
389     ///
390     /// Returns the next event or error from the server, or returns `None` in
391     /// the event of an I/O error. Blocks until either an event or error
392     /// arrive, or an I/O error occurs.
wait_for_event(&self) -> Option<GenericEvent>393     pub fn wait_for_event(&self) -> Option<GenericEvent> {
394         unsafe {
395             let event = xcb_wait_for_event(self.c);
396             if event.is_null() {
397                 None
398             } else {
399                 Some(GenericEvent { ptr: event })
400             }
401         }
402     }
403 
404     /// Returns the next event or error from the server.
405     ///
406     /// Returns the next event or error from the server, if one is
407     /// available, or returns `None` otherwise. If no event is available, that
408     /// might be because an I/O error like connection close occurred while
409     /// attempting to read the next event, in which case the connection is
410     /// shut down when this function returns.
poll_for_event(&self) -> Option<GenericEvent>411     pub fn poll_for_event(&self) -> Option<GenericEvent> {
412         unsafe {
413             let event = xcb_poll_for_event(self.c);
414             if event.is_null() {
415                 None
416             } else {
417                 Some(GenericEvent { ptr: event })
418             }
419         }
420     }
421 
422     /// Returns the next event without reading from the connection.
423     ///
424     /// This is a version of `poll_for_event` that only examines the
425     /// event queue for new events. The function doesn't try to read new
426     /// events from the connection if no queued events are found.
427     ///
428     /// This function is useful for callers that know in advance that all
429     /// interesting events have already been read from the connection. For
430     /// example, callers might use `wait_for_reply` and be interested
431     /// only of events that preceded a specific reply.
poll_for_queued_event(&self) -> Option<GenericEvent>432     pub fn poll_for_queued_event(&self) -> Option<GenericEvent> {
433         unsafe {
434             let event = xcb_poll_for_queued_event(self.c);
435             if event.is_null() {
436                 None
437             } else {
438                 Some(GenericEvent { ptr: event })
439             }
440         }
441     }
442 
443     /// Access the data returned by the server.
444     ///
445     /// Accessor for the data returned by the server when the `Connection`
446     /// was initialized. This data includes
447     /// - the server's required format for images,
448     /// - a list of available visuals,
449     /// - a list of available screens,
450     /// - the server's maximum request length (in the absence of the
451     /// BIG-REQUESTS extension),
452     /// - and other assorted information.
453     ///
454     /// See the X protocol specification for more details.
get_setup(&self) -> Setup455     pub fn get_setup(&self) -> Setup {
456         unsafe {
457 
458             let setup = xcb_get_setup(self.c);
459             if setup.is_null() {
460                 panic!("NULL setup on connection")
461             }
462             mem::transmute(setup)
463         }
464     }
465 
466     /// Test whether the connection has shut down due to a fatal error.
467     ///
468     /// Some errors that occur in the context of a `Connection`
469     /// are unrecoverable. When such an error occurs, the
470     /// connection is shut down and further operations on the
471     /// `Connection` have no effect, but memory will not be freed until
472     /// the `Connection` is dropped.
has_error(&self) -> ConnResult<()>473     pub fn has_error(&self) -> ConnResult<()> {
474         unsafe {
475             match xcb_connection_has_error(self.c) {
476                 0 => { Ok(()) },
477                 XCB_CONN_ERROR => { Err(ConnError::Connection) },
478                 XCB_CONN_CLOSED_EXT_NOTSUPPORTED =>
479                         { Err(ConnError::ClosedExtNotSupported) },
480                 XCB_CONN_CLOSED_MEM_INSUFFICIENT =>
481                         { Err(ConnError::ClosedMemInsufficient) },
482                 XCB_CONN_CLOSED_REQ_LEN_EXCEED =>
483                         { Err(ConnError::ClosedReqLenExceed) },
484                 XCB_CONN_CLOSED_PARSE_ERR =>
485                         { Err(ConnError::ClosedParseErr) },
486                 XCB_CONN_CLOSED_INVALID_SCREEN =>
487                         { Err(ConnError::ClosedInvalidScreen) },
488                 XCB_CONN_CLOSED_FDPASSING_FAILED =>
489                         { Err(ConnError::ClosedFdPassingFailed) },
490                 _ => {
491                     warn!("XCB: unexpected error code from xcb_connection_has_error");
492                     warn!("XCB: Default to ConnError::Connection");
493                     Err(ConnError::Connection)
494                 },
495             }
496         }
497     }
498 
499     /// Allocates an XID for a new object.
500     ///
501     /// Allocates an XID for a new object. Typically used just prior to
502     /// various object creation functions, such as `xcb::create_window`.
generate_id(&self) -> u32503     pub fn generate_id(&self) -> u32 {
504         unsafe {
505             xcb_generate_id(self.c)
506         }
507     }
508 
509     /// Returns the inner ffi `xcb_connection_t` pointer
get_raw_conn(&self) -> *mut xcb_connection_t510     pub fn get_raw_conn(&self) -> *mut xcb_connection_t {
511         self.c
512     }
513 
514     /// Consumes this object, returning the inner ffi `xcb_connection_t` pointer
into_raw_conn(self) -> *mut xcb_connection_t515     pub fn into_raw_conn(self) -> *mut xcb_connection_t {
516         let c = self.c;
517         mem::forget(self);
518         c
519     }
520 
521     /// Returns the inner ffi `xlib::Display` pointer.
522     #[cfg(feature="xlib_xcb")]
get_raw_dpy(&self) -> *mut xlib::Display523     pub fn get_raw_dpy(&self) -> *mut xlib::Display {
524         self.dpy
525     }
526 
527     /// Prefetch of extension data into the extension cache
528     ///
529     /// This function allows a "prefetch" of extension data into the
530     /// extension cache. Invoking the function may cause a call to
531     /// xcb_query_extension, but will not block waiting for the
532     /// reply. xcb_get_extension_data will return the prefetched data after
533     /// possibly blocking while it is retrieved.
prefetch_extension_data(&self, ext: &mut Extension)534     pub fn prefetch_extension_data(&self, ext: &mut Extension) {
535         unsafe {
536             xcb_prefetch_extension_data(self.c, ext);
537         }
538     }
539 
540     /// Caches reply information from QueryExtension requests.
541     ///
542     /// This function is the primary interface to the "extension cache",
543     /// which caches reply information from QueryExtension
544     /// requests. Invoking this function may cause a call to
545     /// xcb_query_extension to retrieve extension information from the
546     /// server, and may block until extension data is received from the
547     /// server.
get_extension_data<'a>(&'a self, ext: &mut Extension) -> Option<QueryExtensionData<'a>>548     pub fn get_extension_data<'a>(&'a self, ext: &mut Extension)
549             -> Option<QueryExtensionData<'a>> {
550         unsafe {
551             let ptr = xcb_get_extension_data(self.c, ext);
552             if !ptr.is_null() { Some(QueryExtensionData { ptr: ptr, _marker: PhantomData }) }
553             else { None }
554         }
555     }
556 
557     /// Sets the owner of the event queue in the case if the connection is opened
558     /// with the XLib interface. the default owner is XLib.
559     #[cfg(feature="xlib_xcb")]
set_event_queue_owner(&self, owner: EventQueueOwner)560     pub fn set_event_queue_owner(&self, owner: EventQueueOwner) {
561         debug_assert!(!self.dpy.is_null());
562         unsafe {
563             XSetEventQueueOwner(self.dpy, match owner {
564                 EventQueueOwner::Xcb => XCBOwnsEventQueue,
565                 EventQueueOwner::Xlib => XlibOwnsEventQueue
566             });
567         }
568     }
569 
570 
571 
572     /// Connects to the X server.
573     /// `displayname:` The name of the display.
574     ///
575     /// Connects to the X server specified by `displayname.` If
576     /// `displayname` is `None,` uses the value of the DISPLAY environment
577     /// variable.
578     ///
579     /// Returns Ok(connection object, preferred screen) in case of success, or
580     /// Err(ConnError) in case of error. If no screen is preferred, the second
581     /// member of the tuple is set to 0.
connect(displayname: Option<&str>) -> ConnResult<(Connection, i32)>582     pub fn connect(displayname: Option<&str>) -> ConnResult<(Connection, i32)> {
583         let mut screen_num : c_int = 0;
584         let displayname = displayname.map(|s| CString::new(s).unwrap());
585         unsafe {
586             let cconn = if let Some(display) = displayname {
587                 xcb_connect(
588                     display.as_ptr(),
589                     &mut screen_num
590                 )
591             } else {
592                 xcb_connect(
593                 null(),
594                 &mut screen_num
595                )
596             };
597 
598 
599             // xcb doc says that a valid object is always returned
600             // so we simply assert without handling this in the return
601             assert!(!cconn.is_null(), "had incorrect pointer");
602 
603             let conn = Self::from_raw_conn(cconn);
604 
605             conn.has_error().map(|_| {
606                 (conn, screen_num as i32)
607             })
608         }
609     }
610 
611     /// Open a new connection with XLib.
612     /// The event queue owner defaults to XLib
613     /// One would need to open an XCB connection with Xlib in order to use
614     /// OpenGL.
615     #[cfg(feature="xlib_xcb")]
connect_with_xlib_display() -> ConnResult<(Connection, i32)>616     pub fn connect_with_xlib_display() -> ConnResult<(Connection, i32)> {
617         unsafe {
618             let dpy = xlib::XOpenDisplay(null());
619             let cconn = XGetXCBConnection(dpy);
620             assert!(!dpy.is_null() && !cconn.is_null(),
621                 "XLib could not connect to the X server");
622 
623             let conn = Connection { c: cconn, dpy: dpy };
624 
625             conn.has_error().map(|_| {
626                 (conn, xlib::XDefaultScreen(dpy) as i32)
627             })
628         }
629     }
630 
631     /// wraps a `xlib::Display` and get an XCB connection from an exisiting object
632     /// `xlib::XCloseDisplay` will be called when the returned object is dropped
633     #[cfg(feature="xlib_xcb")]
new_from_xlib_display(dpy: *mut xlib::Display) -> Connection634     pub unsafe fn new_from_xlib_display(dpy: *mut xlib::Display) -> Connection {
635         assert!(!dpy.is_null(), "attempt connect with null display");
636         Connection {
637             c: XGetXCBConnection(dpy),
638             dpy: dpy
639         }
640     }
641 
642 
643 
644     /// Connects to the X server, using an authorization information.
645     /// display: The name of the display.
646     /// auth_info: The authorization information.
647     /// screen: A pointer to a preferred screen number.
648     /// Returns A newly allocated `Connection` structure.
649     ///
650     /// Connects to the X server specified by displayname, using the
651     /// authorization auth.
652     /// The second member of the returned tuple is the preferred screen, or 0
connect_with_auth_info(displayname: Option<&str>, auth_info: &AuthInfo) -> ConnResult<(Connection, i32)>653     pub fn connect_with_auth_info(displayname: Option<&str>, auth_info: &AuthInfo)
654     -> ConnResult<(Connection, i32)> {
655         unsafe {
656             let mut screen_num : c_int = 0;
657             let displayname = displayname.map(|s| CString::new(s).unwrap());
658             let cconn = if let Some(display) = displayname {
659                 xcb_connect_to_display_with_auth_info(
660                     display.as_ptr(),
661                     mem::transmute(auth_info),
662                     &mut screen_num
663                 )
664             } else {
665                 xcb_connect_to_display_with_auth_info(
666                     null(),
667                     mem::transmute(auth_info),
668                     &mut screen_num
669                 )
670             };
671 
672             // xcb doc says that a valid object is always returned
673             // so we simply assert without handling this in the return
674             assert!(!cconn.is_null(), "had incorrect pointer");
675 
676             let conn = Self::from_raw_conn(cconn);
677 
678             conn.has_error().map(|_| {
679                 (conn, screen_num as i32)
680             })
681         }
682     }
683 
684     /// builds a new Connection object from an available connection
from_raw_conn(conn: *mut xcb_connection_t) -> Connection685     pub unsafe fn from_raw_conn(conn: *mut xcb_connection_t) -> Connection {
686         assert!(!conn.is_null());
687 
688         #[cfg(not(feature="xlib_xcb"))]
689         return Connection {
690             c:  conn,
691         };
692 
693         #[cfg(feature="xlib_xcb")]
694         return Connection {
695             c:  conn,
696             dpy: null_mut(),
697         };
698     }
699 }
700 
701 impl AsRawFd for Connection {
as_raw_fd(&self) -> RawFd702     fn as_raw_fd(&self) -> RawFd {
703         unsafe {
704             xcb_get_file_descriptor(self.c)
705         }
706     }
707 }
708 
709 impl Drop for Connection {
drop(&mut self)710     fn drop(&mut self) {
711         #[cfg(not(feature="xlib_xcb"))]
712         unsafe {
713             xcb_disconnect(self.c);
714         }
715 
716         #[cfg(feature="xlib_xcb")]
717         unsafe {
718             if self.dpy.is_null() {
719                 xcb_disconnect(self.c);
720             }
721             else {
722                 xlib::XCloseDisplay(self.dpy);
723             }
724         }
725     }
726 }
727 
728 
729 // Mimics xproto::QueryExtensionReply, but without the Drop trait.
730 // Used for Connection::get_extension_data whose returned value
731 // must not be freed.
732 // Named QueryExtensionData to avoid name collision
733 pub struct QueryExtensionData<'a> {
734     ptr: *const xcb_query_extension_reply_t,
735     _marker: PhantomData<&'a ()>,
736 }
737 
738 impl<'a> QueryExtensionData<'a> {
present(&self) -> bool739     pub fn present(&self) -> bool {
740         unsafe {
741             (*self.ptr).present != 0
742         }
743     }
major_opcode(&self) -> u8744     pub fn major_opcode(&self) -> u8 {
745         unsafe {
746             (*self.ptr).major_opcode
747         }
748     }
first_event(&self) -> u8749     pub fn first_event(&self) -> u8 {
750         unsafe {
751             (*self.ptr).first_event
752         }
753     }
first_error(&self) -> u8754     pub fn first_error(&self) -> u8 {
755         unsafe {
756             (*self.ptr).first_error
757         }
758     }
759 }
760 
761 
762 pub trait Zero {
zero() -> Self763     fn zero() -> Self;
764 }
765 
zero() -> u8766 impl Zero for u8    { fn zero() -> u8    {0} }
zero() -> u16767 impl Zero for u16   { fn zero() -> u16   {0} }
zero() -> u32768 impl Zero for u32   { fn zero() -> u32   {0} }
zero() -> u64769 impl Zero for u64   { fn zero() -> u64   {0} }
zero() -> usize770 impl Zero for usize { fn zero() -> usize {0} }
zero() -> i8771 impl Zero for i8    { fn zero() -> i8    {0} }
zero() -> i16772 impl Zero for i16   { fn zero() -> i16   {0} }
zero() -> i32773 impl Zero for i32   { fn zero() -> i32   {0} }
zero() -> i64774 impl Zero for i64   { fn zero() -> i64   {0} }
zero() -> isize775 impl Zero for isize { fn zero() -> isize {0} }
zero() -> f32776 impl Zero for f32   { fn zero() -> f32   {0f32} }
zero() -> f64777 impl Zero for f64   { fn zero() -> f64   {0f64} }
778 
779 /// pack bitfields tuples into vector usable for FFI requests
780 /// ```
781 ///     let values = [
782 ///         (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS),
783 ///         (xcb::CW_BACK_PIXEL, 0xffffffff),
784 ///     ];
785 ///     let ffi_values = (
786 ///         xcb::CW_BACK_PIXEL | xcb::CW_EVENT_MASK,
787 ///         [
788 ///             Oxffffffff,
789 ///             xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS,
790 ///             0
791 ///         ]
792 ///     );
793 ///     assert_eq!(pack_bitfield(&mut values), ffi_values);
794 /// ```
795 
pack_bitfield<T, L>(bf : &mut Vec<(T,L)>) -> (T, Vec<L>) where T: Ord + Zero + Copy + BitAnd<Output=T> + BitOr<Output=T>, L: Copy796 pub fn pack_bitfield<T, L>(bf : &mut Vec<(T,L)>) -> (T, Vec<L>)
797     where T: Ord + Zero + Copy + BitAnd<Output=T> + BitOr<Output=T>,
798           L: Copy {
799 	bf.sort_by(|a,b| {
800         let &(a, _) = a;
801         let &(b, _) = b;
802         if a < b {
803             Ordering::Less
804         }
805         else if a > b {
806             Ordering::Greater
807         }
808         else {
809             Ordering::Equal
810         }
811     });
812 
813     let mut mask = T::zero();
814     let mut list: Vec<L> = Vec::new();
815 
816     for el in bf.iter() {
817         let &(f, v) = el;
818         if mask & f > T::zero() {
819             continue;
820         } else {
821             mask = mask|f;
822             list.push(v);
823         }
824     }
825 
826     (mask, list)
827 }
828