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