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