xcb-0.9.0/.gitignore010064400017500001750000000000621356254216600125150ustar0000000000000000*.o *.so .*.sw* *.pyc target/ Cargo.lock .vscode/ xcb-0.9.0/.travis.yml010064400017500001750000000004231356037634500126410ustar0000000000000000language: rust rust: - nightly - beta - stable before_install: - sudo apt-get update -qq - sudo apt-get install -y libx11-xcb-dev python3 - scripts/install_xcb.sh script: - cargo build --verbose --features debug_all - scripts/test_examples.sh xcb-0.9.0/CHANGELOG.md010064400017500001750000000053431356254422400123420ustar0000000000000000 * 0.9.0 Lompik - 12/11/2019 - get_reply consume cookies and impl Drop on Cookies (#57) * 0.8.3 Lompik - 12/11/2019 - fix use after free when connecting with display names (#65) * 0.8.2 chrisduerr/myfreeweb/yamnikov-oleg/eigebong/rtbo - 13/02/2018 - move to log 0.4 (#55) - improve missing python error in build.rs (#49) - add Connection.into_raw_conn - make source generation deterministic (#43) * 0.8.1 rtbo/main--/chrisduerr - 15/08/2017 - fix lifetime inconsistency (#40) - impl AsRawFd for Connection (#39) * 0.8.0 mjkillough/eduardosm/rtbo - 11/07/2017 - error trait and unsafe cast_error (#32) - mjkillough - unsafe cast_event - rtbo - allow xcb::connect without xlib_xcb feature (fixes also doc generation) (#35) - eduardosm * 0.7.8 Lompik - 12/11/2019 - fix use after free when connecting with display names (#65) (backporting from 0.8) * 0.7.7 rtbo/mjkillough - 15/08/2017 - branch 0.7.x to support servo - implement Error/Display for GenericError and ConnError - fix lifetime inconsistencies (#40) - Send and Sync implemented regardless of thread feature * 0.7.6 rtbo/ibabushkin - 14/11/2016 - much better handling of union accessors (#27) Credits to Inokentiy Babushkin - other minor fixes * 0.7.5 rtbo - xx/08/2016 - multi-threading support (#23) - other bug fixes * 0.7.4 rtbo - xx/06/2016 - templating send_event* to take event obj instead of str - correct iterator attribute lifetime (#16) * 0.7.3 rtbo - 10/04/2016 - templating some accessors * 0.7.2 rtbo - 02/04/2016 - fix #14 * 0.7.1 rtbo - 29/03/2016 - module names closer to ffi - fix #13 * 0.7.0 rtbo - 28/03/2016 - fix connection with strings (#9) - assign response_type in *Event::new (#10) - Connection::connect returns Result (#11) - Some documentation (#12) * 0.6.2 rtbo - 04/03/2016 - fix: correct names for DRI2 and 3 FFI constants * 0.6.1 rtbo - 02/03/2016 - fix: correct names for 'xtest' extension * 0.6.0 rtbo - 22/02/2016 - xlib_xcb: Connection owns the xlib::Display and calls XCloseDisplay - requests accept template slices - POD types distinction * 0.5.0 rtbo - 07/02/2016 - adding xlib_xcb - show how to create an opengl enabled window * 0.4.1 rtbo - 07/02/2016 - generating union accessors - handling of bool parameters in the wrapper API - rewrite of wrappers structures (pub type instead of struct with base field) - module clean-up and export - Travis CI * 0.4.0 rtbo/laumann - 03/02/2016 - first fully functional wrappers - rewritten rs_client.py - new examples - made ffi very close to C - fixed wrappers segfaults * 0.3.0 Aatch - 2013 xcb-0.9.0/Cargo.toml.orig010064400017500001750000000031441356254422400134150ustar0000000000000000[package] name = "xcb" version = "0.9.0" authors = [ "Remi Thebault " ] description = "Rust bindings and wrappers for XCB" repository = "https://github.com/rtbo/rust-xcb" documentation = "http://rtbo.github.io/rust-xcb/xcb/" readme = "README.md" keywords = ["xcb", "window", "xlib", "x11", "opengl"] license = "MIT" exclude = [ "examples/*", "scripts/*" ] build = "build.rs" [build-dependencies] libc = "0.2" [dependencies] libc = "0.2" log = "0.4" [dependencies.x11] version = "2.3" optional = true features = ["xlib"] [features] xlib_xcb = ["x11/xlib"] thread = [] composite = [ "xfixes" ] damage = [ "xfixes" ] dpms = [] dri2 = [] dri3 = [] ge = [] glx = [] present = [ "render", "xfixes", "sync" ] randr = [ "render" ] record = [] render = [] res = [] screensaver = [] shape = [] shm = [] sync = [] xevie = [] xf86dri = [] xf86vidmode = [] xfixes = [ "render", "shape" ] xinerama = [] xinput = [ "xfixes" ] xkb = [] xprint = [] xselinux = [] xtest = [] xvmc = [ "xv" ] xv = [ "shm" ] # ge and xf86vidmode are apparently nor built neither installed by libxcb C project # extension xinput is broken # all others are in debug_all whose purpose is to check build of extensions debug_all = [ "thread", "composite", "damage", "dpms", "dri2", "dri3", "glx", "randr", "record", "render", "res", "screensaver", "shape", "shm", "xevie", "xf86dri", "xfixes", "xinerama", "xkb", "xprint", "xselinux", "xtest", "xvmc", "xv", "xlib_xcb" ] # cargo does not seam to support example.features yet. # That is addressed in cargo/#1570 #[[example]] #name = "randr_crtc_info" #features = "randr" xcb-0.9.0/Cargo.toml0000644000000034220000000000000076540ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "xcb" version = "0.9.0" authors = ["Remi Thebault "] build = "build.rs" exclude = ["examples/*", "scripts/*"] description = "Rust bindings and wrappers for XCB" documentation = "http://rtbo.github.io/rust-xcb/xcb/" readme = "README.md" keywords = ["xcb", "window", "xlib", "x11", "opengl"] license = "MIT" repository = "https://github.com/rtbo/rust-xcb" [dependencies.libc] version = "0.2" [dependencies.log] version = "0.4" [dependencies.x11] version = "2.3" features = ["xlib"] optional = true [build-dependencies.libc] version = "0.2" [features] composite = ["xfixes"] damage = ["xfixes"] debug_all = ["thread", "composite", "damage", "dpms", "dri2", "dri3", "glx", "randr", "record", "render", "res", "screensaver", "shape", "shm", "xevie", "xf86dri", "xfixes", "xinerama", "xkb", "xprint", "xselinux", "xtest", "xvmc", "xv", "xlib_xcb"] dpms = [] dri2 = [] dri3 = [] ge = [] glx = [] present = ["render", "xfixes", "sync"] randr = ["render"] record = [] render = [] res = [] screensaver = [] shape = [] shm = [] sync = [] thread = [] xevie = [] xf86dri = [] xf86vidmode = [] xfixes = ["render", "shape"] xinerama = [] xinput = ["xfixes"] xkb = [] xlib_xcb = ["x11/xlib"] xprint = [] xselinux = [] xtest = [] xv = ["shm"] xvmc = ["xv"] xcb-0.9.0/LICENSE010064400017500001750000000022701356037634500115370ustar0000000000000000Copyright (c) 2013 James Miller Copyright (c) 2016 Remi Thebault Thomas Bracht Laumann Jespersen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xcb-0.9.0/README.md010064400017500001750000000105301356254422400120020ustar0000000000000000# Rust XCB [![Build Status](https://travis-ci.org/rtbo/rust-xcb.svg?branch=master)](https://travis-ci.org/rtbo/rust-xcb) Rust-XCB is a set of bindings and wrappers for [XCB](http://xcb.freedesktop.org). It uses the XML protocol descriptions from XCB to generate the bindings and the wrappers. Rust-XCB is only intended as an interface to XCB, so provides nothing above and beyond that. ```toml [dependencies] xcb = "0.8" ``` __Documentation__: http://rtbo.github.io/rust-xcb/xcb/index.html ## The bindings The bindings are generated from the `rs_client.py` script with help from the `xcbgen` library (also from XCB). The bindings are inside the `ffi` module, which also contains the hand-written bindings to the core library. Bindings reflect the C API almost one for one. ## The wrapper The wrappers are generated from the same files, and provide a safe and more convenient wrapper over the low-level bindings by having automatic destructors for returned data, trait implementations for object "types" and other safe helpers. ## Example Drawing example (checkout for more [here](https://github.com/rtbo/rust-xcb/tree/master/examples) and also [here](https://github.com/rtbo/toy_xcb)) ```rust extern crate xcb; fn main() { let points: &[xcb::Point] = &[ xcb::Point::new(10, 10), xcb::Point::new(10, 20), xcb::Point::new(20, 10), xcb::Point::new(20, 20), ]; let polyline: &[xcb::Point] = &[ xcb::Point::new(50, 10 ), xcb::Point::new( 5, 20 ), /* rest of points are relative */ xcb::Point::new(25, -20), xcb::Point::new(10, 10 ) ]; let segments: &[xcb::Segment] = &[ xcb::Segment::new(100, 10, 140, 30), xcb::Segment::new(110, 25, 130, 60) ]; let rectangles: &[xcb::Rectangle] = &[ xcb::Rectangle::new(10, 50, 40, 20), xcb::Rectangle::new(80, 50, 10, 40) ]; let arcs: &[xcb::Arc] = &[ xcb::Arc::new(10, 100, 60, 40, 0, 90 << 6), xcb::Arc::new(90, 100, 55, 40, 0, 270 << 6) ]; let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); let setup = conn.get_setup(); let screen = setup.roots().nth(screen_num as usize).unwrap(); let foreground = conn.generate_id(); xcb::create_gc(&conn, foreground, screen.root(), &[ (xcb::GC_FOREGROUND, screen.black_pixel()), (xcb::GC_GRAPHICS_EXPOSURES, 0), ]); let win = conn.generate_id(); xcb::create_window(&conn, xcb::COPY_FROM_PARENT as u8, win, screen.root(), 0, 0, 150, 150, 10, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, screen.root_visual(), &[ (xcb::CW_BACK_PIXEL, screen.white_pixel()), (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS), ] ); xcb::map_window(&conn, win); conn.flush(); loop { let event = conn.wait_for_event(); match event { None => { break; } Some(event) => { let r = event.response_type() & !0x80; match r { xcb::EXPOSE => { /* We draw the points */ xcb::poly_point(&conn, xcb::COORD_MODE_ORIGIN as u8, win, foreground, &points); /* We draw the polygonal line */ xcb::poly_line(&conn, xcb::COORD_MODE_PREVIOUS as u8, win, foreground, &polyline); /* We draw the segements */ xcb::poly_segment(&conn, win, foreground, &segments); /* We draw the rectangles */ xcb::poly_rectangle(&conn, win, foreground, &rectangles); /* We draw the arcs */ xcb::poly_arc(&conn, win, foreground, &arcs); /* We flush the request */ conn.flush(); }, xcb::KEY_PRESS => { let key_press : &xcb::KeyPressEvent = unsafe { xcb::cast_event(&event) }; println!("Key '{}' pressed", key_press.detail()); break; }, _ => {} } } } } } ``` xcb-0.9.0/build.rs010064400017500001750000000056711356254422400122020ustar0000000000000000 extern crate libc; use std::io; use std::env; use std::cmp; use std::path::{Path, PathBuf}; use std::fs; use std::os::unix::fs::MetadataExt; use std::process::Command; fn visit_xml(xml_dir: &Path, cb: F) -> io::Result<()> where F: Fn(&Path) -> io::Result<()> { if try!(fs::metadata(xml_dir)).is_dir() { for entry in try!(fs::read_dir(xml_dir)) { let path = try!(entry).path(); if try!(fs::metadata(&path)).is_file() { if let Some(ext) = path.extension() { if ext == "xml" { try!(cb(&path)); } } } } } Ok(()) } fn xml_to_rs (rs_dir: &Path, xml_file: &Path) -> PathBuf { let mut path = PathBuf::from(&rs_dir); path.push(xml_file.file_stem().unwrap()); path.set_extension("rs"); path } fn optional_mtime (path: &Path, default: i64) -> i64 { if let Ok(md) = fs::metadata(&path) { md.mtime() } else { default } } fn main() { let root = env::var("CARGO_MANIFEST_DIR").unwrap(); let r_client = Path::new(&root).join("rs_client.py"); let build_rs = Path::new(&root).join("build.rs"); let xml_dir = Path::new(&root).join("xml"); let src_dir = Path::new(&root).join("src"); let src_ffi_dir = Path::new(&src_dir).join("ffi"); let out_dir = env::var("OUT_DIR").unwrap(); let r_client_mtime = fs::metadata(&r_client).unwrap().mtime(); let build_rs_mtime = fs::metadata(&build_rs).unwrap().mtime(); let ref_mtime = cmp::max(r_client_mtime, build_rs_mtime); visit_xml(&xml_dir, |xml_file: &Path| -> io::Result<()> { let src_file = xml_to_rs(&src_dir, &xml_file); let ffi_file = xml_to_rs(&src_ffi_dir, &xml_file); let xml_file_mtime = try!(fs::metadata(&xml_file)).mtime(); let src_file_mtime = optional_mtime(&src_file, 0); let ffi_file_mtime = optional_mtime(&ffi_file, 0); let ref_mtime = cmp::max(ref_mtime, xml_file_mtime); if ref_mtime > src_file_mtime || ref_mtime > ffi_file_mtime { let status = Command::new("python3") .arg("-B") // disable __pycache__ dir that messes with cargo .arg(&r_client) .arg("-o").arg(&out_dir) .arg(&xml_file) .env("PYTHONHASHSEED", "0") .status() .expect("Unable to find build dependency python3"); if !status.success() { panic!("processing of {} returned non-zero ({})", xml_file.display(), status.code().unwrap()); } } Ok(()) }).unwrap(); let xcbgen_dir = Path::new(&root).join("xcbgen"); println!("cargo:rerun-if-changed={}", &build_rs.display()); println!("cargo:rerun-if-changed={}", &r_client.display()); println!("cargo:rerun-if-changed={}", &xml_dir.display()); println!("cargo:rerun-if-changed={}", &xcbgen_dir.display()); } xcb-0.9.0/rs_client.py010075500017500001750000002374671356254422400131060ustar0000000000000000#!/usr/bin/env python3 # Copyright (c) 2016 Remi Thebault # # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated # documentation files (the "Software"), to deal in the # Software without restriction, including without # limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software # is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice # shall be included in all copies or substantial portions # of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF # ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED # TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR # IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. ''' script that generates rust code from xcb xml definitions Each invokation of this script generates one ffi file and one rust file for an extension or the main X Protocol. Usage: ./rs_client.py -o src xml/xproto.xml ''' import sys import os import re class SourceFile(object): ''' buffer to append code in various sections of a file in any order ''' _one_indent_level = ' ' def __init__(self): self._section = 0 self._lines = [] self._indents = [] def getsection(self): return self._section def section(self, section): ''' Set the section of the file where to append code. Allows to make different sections in the file to append to in any order ''' while len(self._lines) <= section: self._lines.append([]) while len(self._indents) <= section: self._indents.append(0) self._section = section def getindent(self): ''' returns indentation of the current section ''' return self._indents[self._section] def setindent(self, indent): ''' sets indentation of the current section ''' self._indents[self._section] = indent; def indent_block(self): class Indenter(object): def __init__(self, sf): self.sf = sf def __enter__(self): self.sf.indent() def __exit__(self, type, value, traceback): self.sf.unindent() return Indenter(self) def indent(self): ''' adds one level of indentation to the current section ''' self._indents[self._section] += 1 def unindent(self): ''' removes one level of indentation to the current section ''' assert self.getindent() > 0, "negative indent" self._indents[self._section] -= 1 def __call__(self, fmt, *args): ''' Append a line to the file at in its current section and indentation of the current section ''' indent = SourceFile._one_indent_level * self._indents[self._section] self._lines[self._section].append(indent + (fmt % args)) def writeout(self, path): os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, 'w') as f: for section in self._lines: for line in section: print(line.rstrip(), file=f) # FFI source file _f = SourceFile() # Rust interface file _r = SourceFile() # utility to add same code in both files def _rf(fmt, *args): _f(fmt, *args) _r(fmt, *args) _ns = None _ext_names = {} # global variable to keep track of serializers and # switch data types due to weird dependencies finished_serializers = [] finished_sizeof = [] finished_switch = [] _types_uneligible_to_copy = [] # current handler is used for error reporting current_handler = None # Keep tracks of types that have lifetime parameter # Initialized with types that are defined in one module and used in other modules types_with_lifetime = [ "xcb_str_iterator_t", # defined in xproto, used in render "xcb_xv_image_format_info_iterator_t" # defined in xv, used in xvmc ] # link exceptions link_exceptions = { "bigreq": "xcb", "xc_misc": "xcb" } #type translation _ffi_type_translation = { 'BOOL': 'u8' } _rs_type_translation = { 'BOOL': 'bool' } # struct with only simple fields are defined as typedef to the ffi struct (issue #7) # this list adds exception to this behavior _rs_typedef_exceptions = [ # not strictly necessary has Setup has complex fields # however intent is clear: 'xproto::Setup' MUST use StructPtr 'xproto::Setup' ] # exported functions to xcbgen start by 'rs_' # starting with opening and closing def rs_open(module): ''' Handles module open. module is a xcbgen.state.Module object ''' global _ns _ns = module.namespace linklib = "xcb" if _ns.is_ext: linklib = 'xcb-' + _ns.header _ext_names[_ns.ext_name.lower()] = _ns.header for (n, h) in module.direct_imports: if h != 'xproto': _ext_names[n.lower()] = h if _ns.header in link_exceptions: linklib = link_exceptions[_ns.header] ext_id_name = _ffi_name(_ns.prefix + ('id',)) _r.section(0) _f.section(0) _rf('// Generated automatically from %s by rs_client.py version %s.', _ns.file, os.getenv('CARGO_PKG_VERSION', 'undefined')) _rf('// Do not edit!') _rf('') _f('') _f('use ffi::base::*;') if _ns.is_ext: for (n, h) in module.imports: _f('use ffi::%s::*;', _module_name(n)) _f('') _f('use libc::{c_char, c_int, c_uint, c_void};') _f('use std;') _f('') _f.section(1) _f('') _f('') _f('#[link(name="%s")]', linklib) _f('extern {') _f.indent() if _ns.is_ext: _f('') _f('pub static mut %s: xcb_extension_t;', ext_id_name) _r('use base;') if _ns.is_ext: for (n, h) in module.imports: _r('use %s;', _module_name(n)) _r('use ffi::base::*;') _r('use ffi::%s::*;', _module_name(_ns.ext_name)) if _ns.is_ext: for (n, h) in module.imports: _r('use ffi::%s::*;', _module_name(n)) _r('use libc::{self, c_char, c_int, c_uint, c_void};') _r('use std;') _r('use std::iter::Iterator;') _r('') if _ns.is_ext: _r('') _r("pub fn id() -> &'static mut base::Extension {") _r(' unsafe {') _r(' &mut %s', ext_id_name) _r(' }') _r('}') _r.section(1) _r('') _r('') if _ns.is_ext: _f.section(0) _f('') _f('pub const %s: u32 = %s;', _ffi_const_name(('xcb', _ns.ext_name, 'major', 'version')), _ns.major_version) _f('pub const %s: u32 = %s;', _ffi_const_name(('xcb', _ns.ext_name, 'minor', 'version')), _ns.minor_version) _r.section(0) _r('') _r('pub const MAJOR_VERSION: u32 = %s;', _ns.major_version) _r('pub const MINOR_VERSION: u32 = %s;', _ns.minor_version) EnumCodegen.build_collision_table(module) def rs_close(module): ''' Handles module close. module is a xcbgen.state.Module object. main task is to write the files out ''' _f.section(1) _f('') _f.unindent() _f('} // extern') _f.writeout(os.path.join(module.rs_srcdir, "ffi", "%s.rs" % _module_name(_ns.ext_name))) _r.writeout(os.path.join(module.rs_srcdir, "%s.rs" % _module_name(_ns.ext_name))) # transformation of name tuples _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)') _rs_keywords = ['type', 'str', 'match', 'new'] def _tit_split(string): ''' splits string with '_' on each titlecase letter >>> _tit_split('SomeString') Some_String >>> _tit_split('WINDOW') WINDOW ''' split = _cname_re.finditer(string) name_parts = [match.group(0) for match in split] return '_'.join(name_parts) def _tit_cap(string): ''' capitalize each substring beggining by a titlecase letter >>> _tit_cap('SomeString') SomeString >>> _tit_cap('WINDOW') Window ''' split = _cname_re.finditer(string) name_parts = [match.group(0) for match in split] name_parts = [i[0].upper() + i[1:].lower() for i in name_parts] return ''.join(name_parts) _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests'] def _module_name(name): if len(name): if name in _extension_special_cases: return _tit_split(name).lower() else: return name.lower() else: return 'xproto' def _symbol(string): if string in _rs_keywords: string += '_' return string def _upper_1st(string): ''' return copy of string with first letter turned into upper. Other letters are untouched. ''' if len(string) == 0: return '' if len(string) == 1: return string.upper() return string[0].upper() + string[1:] def _upper_name(nametup): ''' return a string made from a nametuple with all upper case joined with underscore >>> _upper_name(('xcb', 'constant', 'AwesomeValue')) XCB_CONSTANT_AWESOME_VALUE ''' return '_'.join(tuple(_tit_split(name) for name in nametup)).upper() def _cap_name(nametup): ''' return a string made from a nametuple with joined title case >>> _cap_name(('xcb', 'Type', 'Name')) XcbTypeName >>> _cap_name(('xcb', 'TypeName')) XcbTypeName >>> _cap_name(('xcb', 'TYPENAME')) XcbTypename ''' return ''.join(tuple(_upper_1st(name) for name in nametup)) def _lower_name(nametup): ''' return a string made from a nametuple with all lower case joined with underscore >>> _upper_name(('xcb', 'Ext', 'RequestName')) xcb_ext_request_name ''' return '_'.join(tuple(_tit_split(name) for name in nametup)).lower() def _ext_nametup(nametup): ''' return the nametup with 2nd name lowered if module is an extension >>> _ext_nametup(('u32',)) ('u32',) >>> _ext_nametup(('xcb', 'XprotoType')) ('xcb', 'XprotoType') >>> _ext_nametup(('xcb', 'RandR', 'SuperType')) ('xcb', 'randr', 'SuperType') ''' if len(nametup) > 2 and nametup[1].lower() in _ext_names: #nametup = tuple(_ext_names[name.lower()] if i == 1 else name # for (i, name) in enumerate(nametup)) # lowers extension to avoid '_' split with title letters nametup = tuple(_module_name(name) if i == 1 else name for (i, name) in enumerate(nametup)) return nametup def _ffi_type_name(nametup): ''' turns the nametup into a FFI type >>> _ffi_type_name(('u32',)) u32 >>> _ffi_type_name(('xcb', 'XprotoType')) xcb_xproto_type_t >>> _ffi_type_name(('xcb', 'RandR', 'SuperType')) xcb_randr_super_type_t ''' if len(nametup) == 1: # handles SimpleType if nametup[0] in _ffi_type_translation: return _ffi_type_translation[nametup[0]] return nametup[0] return _ffi_name(nametup + ('t',)) def _ffi_name(nametup): ''' turns the nametup into a FFI name >>> _ffi_type_name(('u32',)) u32 >>> _ffi_type_name(('xcb', 'XprotoType', 't')) xcb_xproto_type_t >>> _ffi_type_name(('xcb', 'RandR', 'SuperType', 't')) xcb_randr_super_type_t ''' secondIsExt = (len(nametup) > 2 and nametup[1].lower() in _ext_names) nametup = _ext_nametup(nametup) if secondIsExt: return '_'.join(tuple(name if i==1 else _tit_split(name) for (i, name) in enumerate(nametup))).lower() else: return '_'.join(tuple(_tit_split(name) for name in nametup)).lower() def _ffi_const_name(nametup): return _ffi_name(_ext_nametup(nametup)).upper() def _rs_extract_module(nametup): ''' returns the module extracted from nametup along with the nametup without the module parts if module is local module, an empty module is returned >>> _rs_extract_module(('u32',)) ("", "u32") >>> _rs_extract_module(('xcb', 'Type')) ("", ("Type")) >>> _rs_extract_module(('xcb', 'RandR', 'SuperType')) ("randr::", ("SuperType")) ''' # handles SimpleType if len(nametup) == 1: return ("", nametup[0]) # remove 'xcb' if nametup[0].lower() == 'xcb': nametup = nametup[1:] module = '' # handle extension type if nametup[0].lower() in _ext_names: ext = _ext_names[nametup[0].lower()] if (not _ns.is_ext or ext != _ns.header): module = ext + '::' nametup = nametup[1:] # handle xproto type for extensions else: if _ns.is_ext: module = 'xproto::' return (module, nametup) def _rs_type_name(nametup): ''' turns the nametup into a Rust type name foreign rust type names include module prefix >>> _rs_type_name(('u32',)) u32 >>> _rs_type_name(('xcb', 'Type')) xproto::Type >>> _rs_type_name(('xcb', 'RandR', 'SuperType')) randr::SuperType ''' if len(nametup) == 1: if nametup[0] in _rs_type_translation: return _rs_type_translation[nametup[0]] return nametup[0] (module, nametup) = _rs_extract_module(nametup) return module + ''.join([_tit_cap(n) for n in nametup]) def _rs_name(nametup): (module, nametup) = _rs_extract_module(nametup) return module + '_'.join([_tit_split(n) for n in nametup]).lower() def _rs_const_name(nametup): return _upper_name(_rs_extract_module(nametup)[1]) def _rs_field_name(string): res = '' for c in string: if c.isupper(): res = res + '_' + c.lower() else: res = res + c return res def _set_type_lifetime(typeobj, has_lifetime): typeobj.has_lifetime = has_lifetime # handle successive calls to _set_type_lifetime on the same object def ensure_in(val): if not val in types_with_lifetime: types_with_lifetime.append(val) def ensure_out(val): while val in types_with_lifetime: types_with_lifetime.remove(val) if has_lifetime: ensure_in(typeobj.ffi_iterator_type) ensure_in(typeobj.rs_type) ensure_in(typeobj.rs_iterator_type) else: ensure_out(typeobj.ffi_iterator_type) ensure_out(typeobj.rs_type) ensure_out(typeobj.rs_iterator_type) # FFI codegen functions def _ffi_type_setup(typeobj, nametup, suffix=()): ''' Sets up all the C-related state by adding additional data fields to all Field and Type objects. Here is where we figure out most of our variable and function names. Recurses into child fields and list member types. ''' # Do all the various names in advance typeobj.ffi_type = _ffi_type_name(nametup + suffix) typeobj.ffi_iterator_type = _ffi_type_name(nametup + ('iterator',)) typeobj.ffi_next_fn = _ffi_name(nametup + ('next',)) typeobj.ffi_end_fn = _ffi_name(nametup + ('end',)) typeobj.ffi_request_fn = _ffi_name(nametup) typeobj.ffi_checked_fn = _ffi_name(nametup + ('checked',)) typeobj.ffi_unchecked_fn = _ffi_name(nametup + ('unchecked',)) typeobj.ffi_reply_fn = _ffi_name(nametup + ('reply',)) typeobj.ffi_reply_type = _ffi_type_name(nametup + ('reply',)) typeobj.ffi_cookie_type = _ffi_type_name(nametup + ('cookie',)) typeobj.ffi_reply_fds_fn = _ffi_name(nametup + ('reply_fds',)) typeobj.ffi_need_aux = False typeobj.ffi_need_serialize = False typeobj.ffi_need_sizeof = False typeobj.ffi_aux_fn = _ffi_name(nametup + ('aux',)) typeobj.ffi_aux_checked_fn = _ffi_name(nametup + ('aux', 'checked')) typeobj.ffi_aux_unchecked_fn = _ffi_name(nametup + ('aux', 'unchecked')) typeobj.ffi_serialize_fn = _ffi_name(nametup + ('serialize',)) typeobj.ffi_unserialize_fn = _ffi_name(nametup + ('unserialize',)) typeobj.ffi_unpack_fn = _ffi_name(nametup + ('unpack',)) typeobj.ffi_sizeof_fn = _ffi_name(nametup + ('sizeof',)) # special case: structs where variable size fields are followed # by fixed size fields typeobj.ffi_var_followed_by_fixed_fields = False if not typeobj.fixed_size(): if not typeobj in _types_uneligible_to_copy: _types_uneligible_to_copy.append(typeobj) if hasattr(typeobj, 'parents'): for p in typeobj.parents: _types_uneligible_to_copy.append(p) if typeobj.is_container: prev_varsized_field = None prev_varsized_offset = 0 first_field_after_varsized = None for field in typeobj.fields: _ffi_type_setup(field.type, field.field_type, ()) if field.type.is_list: _ffi_type_setup(field.type.member, field.field_type, ()) if (field.type.nmemb is None): typeobj.ffi_need_sizeof = True field.ffi_field_type = _ffi_type_name(field.field_type) field.ffi_field_name = _symbol(field.field_name) field.has_subscript = (field.type.nmemb and field.type.nmemb > 1) field.ffi_need_const = (field.type.nmemb != 1) field.ffi_need_pointer = (field.type.nmemb != 1) # correct the need_pointer field for variable size non-list types if not field.type.fixed_size(): field.ffi_need_pointer = True if field.type.is_list and not field.type.member.fixed_size(): field.ffi_need_pointer = True if field.type.is_switch: field.ffi_need_const = True field.ffi_need_pointer = True field.ffi_need_aux = True elif not field.type.fixed_size() and not field.type.is_bitcase: typeobj.ffi_need_sizeof = True field.ffi_iterator_type = _ffi_type_name( field.field_type + ('iterator',)) field.ffi_iterator_fn = _ffi_name( nametup + (field.field_name, 'iterator')) field.ffi_accessor_fn = _ffi_name( nametup + (field.field_name,)) field.ffi_length_fn = _ffi_name( nametup + (field.field_name, 'length')) field.ffi_end_fn = _ffi_name( nametup + (field.field_name, 'end')) field.prev_varsized_field = prev_varsized_field field.prev_varsized_offset = prev_varsized_offset if prev_varsized_offset == 0: first_field_after_varsized = field field.first_field_after_varsized = first_field_after_varsized if field.type.fixed_size(): prev_varsized_offset += field.type.size # special case: intermixed fixed and variable size fields if (prev_varsized_field is not None and not field.type.is_pad and field.wire): if not typeobj.is_union: typeobj.ffi_need_serialize = True typeobj.ffi_var_followed_by_fixed_fields = True else: typeobj.last_varsized_field = field prev_varsized_field = field prev_varsized_offset = 0 if typeobj.ffi_var_followed_by_fixed_fields: if field.type.fixed_size(): field.prev_varsized_field = None if typeobj.ffi_need_serialize: # when _unserialize() is wanted, create _sizeof() as well # for consistency reasons typeobj.ffi_need_sizeof = True if not typeobj.is_bitcase: if typeobj.ffi_need_serialize: if typeobj.ffi_serialize_fn not in finished_serializers: finished_serializers.append(typeobj.ffi_serialize_fn) #_ffi_serialize('serialize', typeobj) # _unpack() and _unserialize() are only needed # for special cases: # switch -> unpack # special cases -> unserialize if (typeobj.is_switch or typeobj.ffi_var_followed_by_fixed_fields): pass #_ffi_serialize('unserialize', typeobj) if typeobj.ffi_need_sizeof: if typeobj.ffi_sizeof_fn not in finished_sizeof: if not _ns.is_ext or typeobj.name[:2] == _ns.prefix: finished_sizeof.append(typeobj.ffi_sizeof_fn) #_ffi_serialize('sizeof', typeobj) def _ffi_bitcase_name(switch, bitcase): assert switch.is_switch and bitcase.type.has_name switch_name = _lower_name(_ext_nametup(switch.name)) return '_%s__%s' % (switch_name, bitcase.ffi_field_name) def _ffi_struct(typeobj, must_pack=False): ''' Helper function for handling all structure types. Called for structs, requests, replies, events, errors... ''' struct_fields = [] for field in typeobj.fields: if (not field.type.fixed_size() and not typeobj.is_switch and not typeobj.is_union): continue if field.wire: struct_fields.append(field) _f.section(0) _f('') _write_doc_brief_desc(_f, typeobj.doc) _f('#[repr(C%s)]', ', packed' if must_pack else '') _f('pub struct %s {', typeobj.ffi_type) _f.indent() maxfieldlen = 0 if not typeobj.is_switch: for field in typeobj.fields: maxfieldlen = max(maxfieldlen, len(field.ffi_field_name)) else: for b in typeobj.bitcases: if b.type.has_name: maxfieldlen = max(maxfieldlen, len(b.ffi_field_name)) else: for field in b.type.fields: maxfieldlen = max(maxfieldlen, len(field.ffi_field_name)) def _ffi_struct_field(field): ftype = field.ffi_field_type space = ' '* (maxfieldlen - len(field.ffi_field_name)) if (field.type.fixed_size() or typeobj.is_union or # in case of switch with switch children, # don't make the field a pointer # necessary for unserialize to work (typeobj.is_switch and field.type.is_switch)): if field.has_subscript: ftype = '[%s; %d]' % (ftype, field.type.nmemb) _f('pub %s: %s%s,', field.ffi_field_name, space, ftype) else: assert not field.has_subscript _f('pub %s: %s*mut %s,', field.ffi_field_name, space, ftype) named_bitcases = [] if not typeobj.is_switch: for field in struct_fields: for d in typeobj.doc.fields[field.field_name]: _f('/// %s', d) _ffi_struct_field(field) else: for b in typeobj.bitcases: if b.type.has_name: named_bitcases.append(b) space = ' ' * (maxfieldlen - len(b.ffi_field_name)) _f('pub %s: %s%s,', b.ffi_field_name, space, _ffi_bitcase_name(typeobj, b)) else: for field in b.type.fields: _ffi_struct_field(field) _f.unindent() _f('}') if not typeobj in _types_uneligible_to_copy: _f('') _f('impl Copy for %s {}', typeobj.ffi_type) _f('impl Clone for %s {', typeobj.ffi_type) _f(' fn clone(&self) -> %s { *self }', typeobj.ffi_type) _f('}') for b in named_bitcases: _f('') _f('#[repr(C)]') _f('pub struct %s {', _ffi_bitcase_name(typeobj, b)) _f.indent() maxfieldlen = 0 for field in b.type.fields: maxfieldlen = max(maxfieldlen, len(field.ffi_field_name)) for field in b.type.fields: _ffi_struct_field(field) _f.unindent() _f('}') def _ffi_accessors_list(typeobj, field): ''' Declares the accessor functions for a list field. Declares a direct-accessor function only if the list members are fixed size. Declares length and get-iterator functions always. ''' list = field.type ffi_type = typeobj.ffi_type # special case: switch # in case of switch, 2 params have to be supplied to certain # accessor functions: # 1. the anchestor object (request or reply) # 2. the (anchestor) switch object # the reason is that switch is either a child of a request/reply # or nested in another switch, # so whenever we need to access a length field, we might need to # refer to some anchestor type switch_obj = typeobj if typeobj.is_switch else None if typeobj.is_bitcase: switch_obj = typeobj.parents[-1] if switch_obj is not None: ffi_type = switch_obj.ffi_type params = [] parents = typeobj.parents if hasattr(typeobj, 'parents') else [typeobj] # 'R': parents[0] is always the 'toplevel' container type params.append(('R: *const %s' % parents[0].ffi_type, parents[0])) # auxiliary object for 'R' parameters R_obj = parents[0] if switch_obj is not None: # now look where the fields are defined that are needed to evaluate # the switch expr, and store the parent objects in accessor_params and # the fields in switch_fields # 'S': name for the 'toplevel' switch toplevel_switch = parents[1] params.append(('S: *const %s' % toplevel_switch.ffi_type, toplevel_switch)) # auxiliary object for 'S' parameter S_obj = parents[1] _f.section(1) if list.member.fixed_size(): idx = 1 if switch_obj is not None else 0 _f('') _f('pub fn %s (%s)', field.ffi_accessor_fn, params[idx][0]) _f(' -> *mut %s;', field.ffi_field_type) def _may_switch_fn(fn_name, return_type): _f('') has_lifetime = return_type in types_with_lifetime lifetime = "<'a>" if has_lifetime else "" if switch_obj is not None: fn_start = 'pub fn %s%s (' % (fn_name, lifetime) spacing = ' '*len(fn_start) _f('%sR: *const %s,', fn_start, R_obj.ffi_type) _f('%sS: *const %s)', spacing, S_obj.ffi_type) _f(' -> %s%s;', return_type, lifetime) else: _f('pub fn %s%s (R: *const %s)', fn_name, lifetime, ffi_type) _f(' -> %s%s;', return_type, lifetime) _may_switch_fn(field.ffi_length_fn, 'c_int') if field.type.member.is_simple: _may_switch_fn(field.ffi_end_fn, 'xcb_generic_iterator_t') else: _may_switch_fn(field.ffi_iterator_fn, field.ffi_iterator_type) def _ffi_accessors_field(typeobj, field): ''' Declares the accessor functions for a non-list field that follows a variable-length field. ''' ffi_type = typeobj.ffi_type # special case: switch switch_obj = typeobj if typeobj.is_switch else None if typeobj.is_bitcase: switch_obj = typeobj.parents[-1] if switch_obj is not None: ffi_type = switch_obj.ffi_type _f.section(1) if field.type.is_simple: _f('') _f('pub fn %s (R: *const %s)', field.ffi_accessor_fn, ffi_type) _f(' -> %s;', field.ffi_field_type) else: if field.type.is_switch and switch_obj is None: return_type = '*mut c_void' else: return_type = '*mut %s' % field.ffi_field_type _f('') _f('pub fn %s (R: *const %s)', field.ffi_accessor_fn, ffi_type) _f(' -> %s;', return_type) def _ffi_accessors(typeobj, nametup): for field in typeobj.fields: if not field.type.is_pad: if field.type.is_list and not field.type.fixed_size(): _ffi_accessors_list(typeobj, field) elif (field.prev_varsized_field is not None or not field.type.fixed_size()): _ffi_accessors_field(typeobj, field) def _ffi_iterator(typeobj, nametup): has_lifetime = typeobj.ffi_iterator_type in types_with_lifetime lifetime = "<'a>" if has_lifetime else "" _f.section(0) _f('') _f('#[repr(C)]') _f("pub struct %s%s {", typeobj.ffi_iterator_type, lifetime) _f(' pub data: *mut %s,', typeobj.ffi_type) _f(' pub rem: c_int,') _f(' pub index: c_int,') if has_lifetime: _f(" _phantom: std::marker::PhantomData<&'a %s>,", typeobj.ffi_type) _f('}') _f.section(1) _f('') _f('pub fn %s (i: *mut %s);', typeobj.ffi_next_fn, typeobj.ffi_iterator_type) _f('') _f('pub fn %s (i: *mut %s)', typeobj.ffi_end_fn, typeobj.ffi_iterator_type) _f(' -> xcb_generic_iterator_t;') def _ffi_reply(request): ''' Declares the function that returns the reply structure. ''' _f.section(1) _f('') _f('/// the returned value must be freed by the caller using ' + 'libc::free().') fn_start = 'pub fn %s (' % request.ffi_reply_fn spacing = ' ' * len(fn_start) _f('%sc: *mut xcb_connection_t,', fn_start) _f('%scookie: %s,', spacing, request.ffi_cookie_type) _f('%serror: *mut *mut xcb_generic_error_t)', spacing) _f(' -> *mut %s;', request.ffi_reply_type) def _ffi_reply_has_fds(self): for field in self.fields: if field.isfd: return True return False def _ffi_reply_fds(request, name): ''' Declares the function that returns fds related to the reply. ''' _f.section(1) _f('') _f('/// the returned value must be freed by the caller using ' + 'libc::free().') fn_start = 'pub fn %s (' % request.ffi_reply_fds_fn spacing = ' ' * len(fn_start) _f('%sc: *mut xcb_connection_t,', fn_start) _f('%sreply: *mut %s)', spacing, request.ffi_reply_type) _f(' -> *mut c_int;') # Rust codegen function def _rs_type_setup(typeobj, nametup, suffix=()): #assert typeobj.hasattr('ffi_type') typeobj.rs_type = _rs_type_name(nametup + suffix) if len(nametup) == 1: typeobj.rs_qualified_type = typeobj.rs_type else: module = _ns.ext_name.lower() if _ns.is_ext else 'xproto' typeobj.rs_qualified_type = '%s::%s' % (module, typeobj.rs_type) typeobj.rs_iterator_type = _rs_type_name(nametup+('iterator',)) typeobj.rs_request_fn = _rs_name(nametup) typeobj.rs_checked_fn = _rs_name(nametup+('checked',)) typeobj.rs_unchecked_fn = _rs_name(nametup+('unchecked',)) typeobj.rs_aux_fn = _rs_name(nametup+('aux',)) typeobj.rs_aux_checked_fn = _rs_name(nametup+('aux', 'checked')) typeobj.rs_aux_unchecked_fn = _rs_name(nametup+('aux', 'unchecked')) typeobj.rs_reply_type = _rs_type_name(nametup + ('reply',)) typeobj.rs_cookie_type = _rs_type_name(nametup + ('cookie',)) typeobj.rs_is_pod = False if typeobj.is_container: has_complex = False for field in typeobj.fields: _rs_type_setup(field.type, field.field_type) if field.type.is_list: _rs_type_setup(field.type.member, field.field_type) field.rs_field_name = _symbol(_rs_field_name(field.field_name)) field.rs_field_type = _rs_type_name(field.field_type) field.rs_iterator_type = _rs_type_name( field.field_type + ('iterator',)) if not field.type.is_simple and not field.type.rs_is_pod \ and not field.type.is_pad: has_complex = True typeobj.rs_only_has_simple = not has_complex # we restrict POD a little typeobj.rs_is_pod = ( (not has_complex) and (not typeobj.rs_qualified_type in _rs_typedef_exceptions) and (not typeobj.is_reply and not typeobj.is_union) and (not typeobj.is_switch)) if typeobj.rs_is_pod: _set_type_lifetime(typeobj, False) def _rs_struct(typeobj): _r.section(1) _r('') _write_doc_brief_desc(_r, typeobj.doc) if typeobj.rs_is_pod: _r('#[derive(Copy, Clone)]') _r('pub struct %s {', typeobj.rs_type) _r(' pub base: %s,', typeobj.ffi_type) _r('}') else: has_lifetime = typeobj.rs_type in types_with_lifetime lifetime1 = "<'a>" if has_lifetime else "" lifetime2 = "'a, " if has_lifetime else "" _r("pub type %s%s = base::StructPtr<%s%s>;", typeobj.rs_type, lifetime1, lifetime2, typeobj.ffi_type) def _rs_accessors(typeobj): has_lifetime = typeobj.rs_type in types_with_lifetime lifetime = "<'a>" if has_lifetime else "" _r.section(1) _r('') _r('impl%s %s%s {', lifetime, typeobj.rs_type, lifetime) with _r.indent_block(): if typeobj.rs_is_pod: # POD structs have a new method fnstart = 'pub fn new(' fnspace = ' '*len(fnstart) argfields = [] for f in typeobj.fields: if not f.type.is_pad: argfields.append(f) maxfieldlen = 0 for f in typeobj.fields: maxfieldlen = max(maxfieldlen, len(f.rs_field_name)) if len(argfields): eol = ',' if len(argfields) > 1 else ')' f1 = argfields[0] space1 = ' '*(maxfieldlen - len(f1.rs_field_name)) _r('#[allow(unused_unsafe)]') _r('%s%s: %s%s%s', fnstart, f1.rs_field_name, space1, f1.rs_field_type, eol) for (i, f) in enumerate(argfields[1:]): argspace = ' '*(maxfieldlen-len(f.rs_field_name)) eol = ',' if i < len(argfields)-2 else ')' _r('%s%s: %s%s%s', fnspace, f.rs_field_name, argspace, f.rs_field_type, eol) _r(' -> %s {', typeobj.rs_type) else: _r('#[allow(unused_unsafe)]') _r('%s) -> %s {', fnstart, typeobj.rs_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('%s {', typeobj.rs_type) with _r.indent_block(): _r('base: %s {', typeobj.ffi_type) with _r.indent_block(): for f in typeobj.fields: space = ' '*(maxfieldlen-len(f.rs_field_name)) if f.type.rs_is_pod: _r('%s: %sstd::mem::transmute(%s),', f.rs_field_name, space, f.rs_field_name) elif f.type.is_pad: fval = '0' if f.has_subscript: fval = '[0; %d]' % f.type.nmemb _r('%s: %s%s,', f.rs_field_name, space, fval) else: assignment = f.rs_field_name if f.rs_field_type == 'bool': assignment = 'if %s { 1 } else { 0 }' % f.rs_field_name _r('%s: %s%s,', f.ffi_field_name, space, assignment) _r('}') _r('}') _r('}') _r('}') for (i, field) in enumerate(typeobj.fields): if field.visible and not field.type.is_switch: for d in typeobj.doc.fields[field.field_name]: _r('/// %s', d) if typeobj.is_union: _rs_union_accessor(typeobj, field) else: _rs_accessor(typeobj, field) _r('}') def _rs_reply_accessors(reply): ''' same as _rs_accessors but handles fds special case ''' has_lifetime = reply.rs_type in types_with_lifetime lifetime = "<'a>" if has_lifetime else "" fd_field = None nfd_field = None for f in reply.fields: if f.rs_field_name == 'nfd': nfd_field = f if f.isfd: fd_field = f reply_fields = [] for f in reply.fields: if f.rs_field_name == 'nfd': # writing nfd field only if fds is not written if not fd_field or not nfd_field: reply_fields.append(f) elif not f.isfd: reply_fields.append(f) _r.section(1) _r('') _r('impl%s %s%s {', lifetime, reply.rs_type, lifetime) with _r.indent_block(): # regular fields for field in reply_fields: if field.visible and not field.type.is_switch: _rs_accessor(reply, field) # fds field if any if nfd_field and fd_field: getter = reply.request.ffi_reply_fds_fn # adding 's' fname = fd_field.rs_field_name if not fname.endswith('s'): fname += 's' _r('pub fn %s(&self, c: &base::Connection) -> &[i32] {', fname) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('let nfd = (*self.ptr).nfd as usize;') _r('let ptr = %s(c.get_raw_conn(), self.ptr);', getter) _r('') _r('std::slice::from_raw_parts(ptr, nfd)') _r('}') _r('}') _r('}') def _rs_union_accessor(typeobj, field): if field.type.is_simple or field.type.rs_is_pod: _r('pub fn %s(&self) -> %s {', field.rs_field_name, field.rs_field_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): convert = '' if field.rs_field_type == 'bool': convert = ' != 0' _r('let _ptr = self.data.as_ptr() as *const %s;', field.rs_field_type) _r('*_ptr%s', convert) _r('}') _r('}') _r('pub fn from_%s(%s: %s) -> %s {', field.rs_field_name, field.rs_field_name, field.rs_field_type, typeobj.rs_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): if field.rs_field_type == 'bool': _r('let %s: %s = %s != 0;', field.rs_field_name, field.ffi_field_type, field.rs_field_name) _r('let mut res = %s { data: [0; %d] };', typeobj.rs_type, typeobj.union_num_bytes) _r('let res_ptr = res.data.as_mut_ptr() as *mut %s;', field.rs_field_type) _r('*res_ptr = %s;', field.rs_field_name) _r('res') _r('}') _r('}') elif field.type.is_list and field.type.fixed_size(): assert (typeobj.union_num_bytes % field.type.size) == 0 _r('pub fn %s(&self) -> &[%s] {', field.rs_field_name, field.rs_field_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('let ptr = self.data.as_ptr() as *const %s;', field.rs_field_type) _r('std::slice::from_raw_parts(ptr, %d)', typeobj.union_num_bytes / field.type.size) _r('}') _r('}') _r('pub fn from_%s(%s: [%s; %d]) -> %s {', field.rs_field_name, field.rs_field_name, field.rs_field_type, typeobj.union_num_bytes / field.type.size, typeobj.rs_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('%s { data: std::mem::transmute(%s) }', typeobj.rs_type, field.rs_field_name) _r('}') _r('}') elif field.type.is_container: if not field.type.rs_is_pod: _r('pub fn %s<\'a>(&\'a self) -> %s<\'a> {', field.rs_field_name, field.rs_field_type) else: _r('pub fn %s(&self) -> %s {', field.rs_field_name, field.rs_field_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): if not field.type.rs_is_pod: _r('std::mem::transmute(self)') else: _r('let _ptr = self.data.as_ptr() as *const %s;', field.rs_field_type) _r('*_ptr') _r('}') _r('}') def _rs_accessor(typeobj, field, disable_pod_acc=False): if field.type.is_simple or field.type.rs_is_pod: _r('pub fn %s(&self) -> %s {', field.rs_field_name, field.rs_field_type) acc = '(*self.ptr)' if typeobj.rs_is_pod and not disable_pod_acc: acc = 'self.base' with _r.indent_block(): convert = '' if field.rs_field_type == 'bool': convert = ' != 0' _r('unsafe {') with _r.indent_block(): if field.type.rs_is_pod: _r('std::mem::transmute(%s.%s)', acc, field.ffi_field_name) else: _r('%s.%s%s', acc, field.ffi_field_name, convert) _r('}') _r('}') elif field.type.is_union: # do we already have a lifetime declared? has_lifetime = typeobj.rs_type in types_with_lifetime lifetime = "<'a>" if not has_lifetime else "" _r("pub fn %s%s(&'a self) -> &'a %s {", field.rs_field_name, lifetime, field.rs_field_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('&(*self.ptr).%s', field.ffi_field_name) _r('}') _r('}') elif field.type.is_list and not field.type.fixed_size(): if field.type.member.rs_type == 'bool': # special case for bool: we need to convert all elements into an owned vec _r('pub fn %s(&self) -> Vec {', field.rs_field_name) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('let field = self.ptr;') _r('let len = %s(field);', field.ffi_length_fn) _r('let data = %s(field);', field.ffi_accessor_fn) _r('let slice = std::slice::from_raw_parts(data, len as usize);') _r('slice.iter().map(|el| if *el == 0 {false} else{true}).collect()') _r('}') _r('}') elif field.type.member.is_simple: field_type = field.type.member.rs_type is_template = False if field_type == 'c_char': return_type = '&str' elif field_type == 'c_void': is_template = True return_type = '&[T]' else: return_type = '&[%s]' % field_type _r('pub fn %s%s(&self) -> %s {', field.rs_field_name, '' if is_template else '', return_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('let field = self.ptr;') _r('let len = %s(field) as usize;', field.ffi_length_fn) _r('let data = %s(field);', field.ffi_accessor_fn) if field_type == 'c_char': _r('let slice = ' + 'std::slice::from_raw_parts(' + 'data as *const u8, len);') _r('// should we check what comes from X?') _r('std::str::from_utf8_unchecked(&slice)') elif is_template: _r('debug_assert_eq!(len %% std::mem::size_of::(), 0);') _r('std::slice::from_raw_parts(data as *const T, ' + 'len / std::mem::size_of::())') else: _r('std::slice::from_raw_parts(data, len)') _r('}') _r('}') else: lifetime = "" if field.rs_iterator_type in types_with_lifetime and \ typeobj.rs_type in types_with_lifetime: lifetime = "<'a>" _r('pub fn %s(&self) -> %s%s {', field.rs_field_name, field.rs_iterator_type, lifetime) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('%s(self.ptr)', field.ffi_iterator_fn) _r('}') _r('}') pass elif field.type.is_list: _r('pub fn %s(&self) -> &[%s] {', field.rs_field_name, field.rs_field_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('&(*self.ptr).%s', field.ffi_field_name) _r('}') _r('}') elif field.type.is_container: _r('pub fn %s(&self) -> %s {', field.rs_field_name, field.rs_field_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('std::mem::transmute(&(*self.ptr).%s)', field.ffi_field_name) _r('}') _r('}') elif not field.type.is_pad: raise Exception('did not treat accessor %s.%s' % (typeobj.ffi_type, field.ffi_field_name)) def _rs_iterator(typeobj): has_lifetime = typeobj.rs_iterator_type in types_with_lifetime lifetime1 = "<'a>" if has_lifetime else "" lifetime2 = "'a, " if has_lifetime else "" return_expr = '*data' if typeobj.rs_is_pod: return_expr = 'std::mem::transmute(*data)' elif typeobj.is_container and not typeobj.is_union: return_expr = 'std::mem::transmute(data)' _r.section(1) _r('') _r("pub type %s%s = %s%s;", typeobj.rs_iterator_type, lifetime1, typeobj.ffi_iterator_type, lifetime1) _r('') _r("impl%s Iterator for %s%s {", lifetime1, typeobj.rs_iterator_type, lifetime1) _r(" type Item = %s%s;", typeobj.rs_type, lifetime1) _r(" fn next(&mut self) -> std::option::Option<%s%s> {", typeobj.rs_type, lifetime1) _r(' if self.rem == 0 { None }') _r(' else {') _r(' unsafe {') _r(' let iter = self as *mut %s;', typeobj.ffi_iterator_type) _r(' let data = (*iter).data;') _r(' %s(iter);', typeobj.ffi_next_fn) _r(' Some(%s)', return_expr) _r(' }') _r(' }') _r(' }') _r('}') def _rs_reply(request): _r.section(1) _r('') _r('pub type %s = base::Reply<%s>;', request.rs_reply_type, request.ffi_reply_type); # Common codegen utilities def _prepare_doc(typeobj): # preparing doc for easier handling # each typeobj must have a doc attribute with brief, description and fields def rework_phrase(phrase): # having 'unknown start of token' error by rustdoc sometimes. # This silents it # return phrase.replace('`', '') # Edit: not necessary anymore return phrase if hasattr(typeobj, "doc_prepared"): assert typeobj.doc_prepared == True return if hasattr(typeobj, "doc") and typeobj.doc: if typeobj.doc.brief: typeobj.doc.brief = [rework_phrase(p) for p in typeobj.doc.brief.split('\n')] else: typeobj.doc.brief = [] if typeobj.doc.description: typeobj.doc.description = [rework_phrase(p) for p in typeobj.doc.description.split('\n')] else: typeobj.doc.description = [] if hasattr(typeobj, "fields"): if not hasattr(typeobj.doc, "fields"): typeobj.doc.fields = {} for f in typeobj.fields: if f.field_name in typeobj.doc.fields: typeobj.doc.fields[f.field_name] = \ [rework_phrase(p) for p in typeobj.doc.fields[f.field_name].split('\n')] else: typeobj.doc.fields[f.field_name] = [] else: class Doc(object): pass typeobj.doc = Doc() typeobj.doc.brief = [] typeobj.doc.description = [] typeobj.doc.fields = {} if hasattr(typeobj, "fields"): for f in typeobj.fields: typeobj.doc.fields[f.field_name] = [] typeobj.doc_prepared = True def _write_docs(sf, doclist): for s in doclist: sf('/// %s', s) def _write_doc_brief_desc(sf, doc): _write_docs(sf, doc.brief) if len(doc.brief) and len(doc.description): sf('///') _write_docs(sf, doc.description) class EnumCodegen(object): namecount = {} def build_collision_table(module): for v in module.types.values(): key = _ffi_type_name(v[0]) EnumCodegen.namecount[key] = ( (EnumCodegen.namecount.get(key) or 0) + 1 ) def __init__(self, nametup, doc): self._nametup = nametup self._doc = doc self.done_vals = {} self.unique_discriminants = [] self.conflicts = [] self.all_discriminants = [] key = _ffi_type_name(nametup) if EnumCodegen.namecount[key] > 1: nametup = nametup + ('enum',) self.ffi_name = _ffi_type_name(nametup) self.rs_name = _rs_type_name(nametup) def add_discriminant(self, name, val): class Discriminant: pass d = Discriminant() #d.rs_name = name d.rs_name = _rs_const_name(self._nametup+(name,)) d.ffi_name = _ffi_const_name(self._nametup+(name,)) d.valstr = '0x%02x' % val d.val = val d.doc = None if self._doc and name in self._doc.fields: d.doc = self._doc.fields[name] self.all_discriminants.append(d) if val in self.done_vals: self.conflicts.append(d) else: self.done_vals[val] = d self.unique_discriminants.append(d) def maxlen(self, name_field): maxnamelen = 0 maxvallen = 0 for d in self.unique_discriminants: maxvallen = max(maxvallen, len(d.valstr)) maxnamelen = max(maxnamelen, len(getattr(d, name_field))) return (maxnamelen, maxvallen) def write_ffi(self): (maxnamelen, maxvallen) = self.maxlen('ffi_name') type_name = self.ffi_name _f.section(0) _f('') _write_doc_brief_desc(_f, self._doc) _f('pub type %s = u32;', type_name) for d in self.all_discriminants: d_name = d.ffi_name namespace = ' ' * (maxnamelen-len(d_name)) valspace = ' ' * (maxvallen-len(d.valstr)) if d.doc: ddocs = d.doc.split('\n') for dd in ddocs: _f('/// %s', dd) _f('pub const %s%s: %s =%s %s;', d_name, namespace, type_name, valspace, d.valstr) def write_rs(self): (maxnamelen, maxvallen) = self.maxlen("rs_name") _r.section(0) _r('') _write_doc_brief_desc(_r, self._doc) _r('pub type %s = u32;', self.rs_name) for d in self.all_discriminants: namespace = ' ' * (maxnamelen-len(d.rs_name)) valspace = ' ' * (maxvallen-len(d.valstr)) if d.doc: ddocs = d.doc.split('\n') for dd in ddocs: _r('/// %s', dd) _r('pub const %s%s: %s =%s %s;', d.rs_name, namespace, self.rs_name, valspace, d.valstr) class RequestCodegen(object): def __init__(self, request): self.request = request self.void = False if self.request.reply else True self.ffi_cookie_type = ('xcb_void_cookie_t' if self.void else self.request.ffi_cookie_type) self.rs_cookie_type = ('base::VoidCookie' if self.void else self.request.rs_cookie_type) self.visible_fields = [] for field in self.request.fields: if field.visible: self.visible_fields.append(field) # for, we do not filter out any visible field, # but we must find out if it is pointer, const ... self.ffi_params = [] for field in self.visible_fields: self.ffi_params.append(field) # Rust is more complicated because of lists # here we pack lists in slices # there's basically 3 cases: # 1. regular fields, passed as-is to the ffi func # 2. masked lists (such as create_window event mask) # given to rs slice of tuple (mask, value) and unpacked # into int and pointer to ffi func # 3. regular lists, for which a length and a pointer # must be passed to the ffi_func. these are given to # rs by a slice # it happens to have 2 or more lists for same length field. # in this case, we will make 2 slices and runtime assert same length # eg: take a look at render::create_conical_gradient rs_num_template = 0 template_letters = ['T', 'U', 'V', 'W'] # xproto::send_event is special. # the FFI takes an event argument casted to a char* # here we are going to require an &Event for the rs func self.rs_send_event = False if _ns.header == "xproto" and \ self.request.rs_request_fn.startswith("send_event"): self.rs_send_event = True for f in self.visible_fields: f.rs_is_slice = False f.rs_template_let = '' f.rs_lenfield = None f.rs_is_mask_slice = False f.rs_maskfield = None f.rs_skip = False for (ffi_index, field) in enumerate(self.visible_fields): field.ffi_index = ffi_index if self.rs_send_event and field.rs_field_name == "event": field.rs_template_let = template_letters[rs_num_template] rs_num_template += 1 elif field.type.is_list: if field.type.expr.bitfield: # field associated with a mask # eg. create_window last field field.rs_is_mask_slice = True else: # regular list with length and ptr field.rs_is_slice = True if field.type.member.rs_type == 'c_void': field.rs_template_let = template_letters[rs_num_template] rs_num_template += 1 field.rs_lenfield = field.type.expr.lenfield if not field.rs_lenfield: len_name = field.type.expr.lenfield_name for f in self.visible_fields: if f.field_name == len_name: field.rs_lenfield = f # the mask is mandatory, but not the length (eg c strings) if field.rs_is_mask_slice: assert field.rs_lenfield if field.rs_lenfield: field.rs_lenfield.rs_skip = True self.rs_params = [] for field in self.visible_fields: if not field.rs_skip: self.rs_params.append(field) self.rs_template = "<'a>" if rs_num_template: self.rs_template = "<'a" for i in range(rs_num_template): self.rs_template += ', ' + template_letters[i] self.rs_template += '>' def ffi_func_name(self, regular, aux): checked = self.void and not regular unchecked = not self.void and not regular if checked: func_name = (self.request.ffi_checked_fn if not aux else self.request.ffi_aux_checked_fn) elif unchecked: func_name = (self.request.ffi_unchecked_fn if not aux else self.request.ffi_aux_unchecked_fn) else: func_name = (self.request.ffi_request_fn if not aux else self.request.ffi_aux_fn) return func_name def rs_func_name(self, regular, aux): checked = self.void and not regular unchecked = not self.void and not regular if checked: func_name = (self.request.rs_checked_fn if not aux else self.request.rs_aux_checked_fn) elif unchecked: func_name = (self.request.rs_unchecked_fn if not aux else self.request.rs_aux_unchecked_fn) else: func_name = (self.request.rs_request_fn if not aux else self.request.rs_aux_fn) return func_name def ffi_rq_type(self, field, aux): ffi_rq_type = field.ffi_field_type if field.ffi_need_pointer: pointer = '*const ' if field.ffi_need_const else '*mut ' ffi_rq_type = pointer + ffi_rq_type if field.type.ffi_need_serialize and not aux: ffi_rq_type = '*const c_void' return ffi_rq_type def write_ffi_rs(self, regular, aux=False): self.write_ffi(regular, aux) self.write_rs(regular, aux) def write_ffi(self, regular, aux=False): ffi_func_name = self.ffi_func_name(regular, aux) maxnamelen = 1 for p in self.ffi_params: maxnamelen = max(maxnamelen, len(p.ffi_field_name)) _f.section(1) _f("") _write_doc_brief_desc(_f, self.request.doc) fn_start = "pub fn %s (" % ffi_func_name func_spacing = ' ' * len(fn_start) spacing = " " * (maxnamelen-len('c')) eol = ',' if len(self.ffi_params) else ')' _f("%sc: %s*mut xcb_connection_t%s", fn_start, spacing, eol) for (i, p) in enumerate(self.ffi_params): ffi_rq_type = self.ffi_rq_type(p, aux) spacing = ' '*(maxnamelen-len(p.ffi_field_name)) eol = ')' if i == (len(self.ffi_params)-1) else ',' _f('%s%s: %s%s%s', func_spacing, p.ffi_field_name, spacing, ffi_rq_type, eol) _f(" -> %s;", self.ffi_cookie_type) def write_rs(self, regular, aux=False): checked = (self.void and not regular) \ or ((not self.void) and regular) rs_func_name = self.rs_func_name(regular, aux) ffi_func_name = self.ffi_func_name(regular, aux) maxnamelen = len('c') for p in self.rs_params: maxnamelen = max(maxnamelen, len(p.rs_field_name)) let_lines = [] call_params = [] _r.section(1) _r('') _write_doc_brief_desc(_r, self.request.doc) doc_params = False for f in self.rs_params: if len(self.request.doc.fields[f.field_name]): doc_params = True break if doc_params: _r('///') _r('/// parameters:') _r('///') _r('/// - __c__:') _r('/// The connection object to the server') for f in self.rs_params: _r('///') _r('/// - __%s__:', f.field_name) for fd in self.request.doc.fields[f.field_name]: _r('/// %s', fd) fn_start = "pub fn %s%s(" % (rs_func_name, self.rs_template) func_spacing = ' ' * len(fn_start) eol = ',' if len(self.rs_params) else ')' spacing = ' ' * (maxnamelen-len('c')) _r("%sc%s: &'a base::Connection%s", fn_start, spacing, eol) for (i, p) in enumerate(self.rs_params): ffi_rq_type = self.ffi_rq_type(p, aux) rs_typestr = p.rs_field_type if self.rs_send_event and p.rs_field_name == "event": rs_typestr = "&base::Event<%s>" % p.rs_template_let let_lines.append("let event_ptr = " + "std::mem::transmute(event.ptr);") call_params.append((p.ffi_index, "event_ptr")) pass elif p.rs_is_mask_slice: maskfield = p.rs_lenfield rs_typestr = '&[(%s, %s)]' % (maskfield.rs_field_type, p.rs_field_type) let_lines.append('let mut %s_copy = %s.to_vec();' % (p.rs_field_name, p.rs_field_name)) let_lines.append(('let (%s_mask, %s_vec) = ' + 'base::pack_bitfield(&mut %s_copy);') % (p.rs_field_name, p.rs_field_name, p.rs_field_name)) let_lines.append("let %s_ptr = %s_vec.as_ptr();" % (p.rs_field_name, p.rs_field_name)) # adding mask field if not already done # (already done should not happen with masks) if not next((cp for cp in call_params if cp[0] == maskfield.ffi_index), None): call_params.append((maskfield.ffi_index, "%s_mask as %s" % (p.rs_field_name, maskfield.ffi_field_type))) # adding actual field call_params.append((p.ffi_index, '%s_ptr as %s' % (p.rs_field_name, ffi_rq_type))) elif p.rs_is_slice: if p.type.member.rs_type == 'c_char': rs_typestr = '&str' let_lines.append('let %s = %s.as_bytes();' % (p.rs_field_name, p.rs_field_name)) elif p.type.member.rs_type == 'c_void': rs_typestr = '&[%s]' % p.rs_template_let else: rs_typestr = '&[%s]' % rs_typestr if p.rs_lenfield: lenfield = p.rs_lenfield # adding len field if not already done # (already done can happen with lists) if not next((cp for cp in call_params if cp[0] == lenfield.ffi_index), None): let_lines.append('let %s_len = %s.len();' % (p.rs_field_name, p.rs_field_name)) call_params.append((lenfield.ffi_index, "%s_len as %s" % (p.rs_field_name, lenfield.ffi_field_type))) let_lines.append('let %s_ptr = %s.as_ptr();' % (p.rs_field_name, p.rs_field_name)) # adding actual field call_params.append((p.ffi_index, '%s_ptr as %s' % (p.rs_field_name, ffi_rq_type))) elif p.type.is_container and p.ffi_need_pointer: rs_typestr = 'std::option::Option<%s>' % rs_typestr let_lines.append('let %s_ptr = match %s {' % (p.rs_field_name, p.rs_field_name)) let_lines.append(' Some(p) => p.ptr as %s,' % ffi_rq_type) let_lines.append(' None => std::ptr::null()') let_lines.append('};') call_params.append((p.ffi_index, '%s_ptr' % p.rs_field_name)) elif p.type.is_container and not p.type.rs_is_pod: call_params.append((p.ffi_index, '*(%s.ptr)' % p.rs_field_name)) elif p.type.rs_is_pod: call_params.append((p.ffi_index, '%s.base' % p.rs_field_name)) else: call_params.append((p.ffi_index, '%s as %s' % (p.rs_field_name, ffi_rq_type))) spacing = ' ' * (maxnamelen-len(p.rs_field_name)) eol = ',' if i < (len(self.rs_params)-1) else ')' _r('%s%s%s: %s%s', func_spacing, p.rs_field_name, spacing, rs_typestr, eol) _r(" -> %s<'a> {", self.rs_cookie_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): for l in let_lines: _r(l) call_start = 'let cookie = %s(' % ffi_func_name eol = ',' if len(call_params) else ');' spacing = ' ' * len(call_start) _r('%sc.get_raw_conn()%s', call_start, eol) call_params.sort(key=lambda x: x[0]) for (i, (ffi_ind, p)) in enumerate(call_params): eol = ',' if i < (len(call_params)-1) else ');' _r('%s%s%s // %d', spacing, p, eol, ffi_ind) _r("%s {", self.rs_cookie_type) _r(" cookie: cookie,") _r(" conn: c,") _r(" checked: %s", 'true' if checked else 'false') _r("}") _r('}') _r('}') def _opcode(nametup, opcode): # handle GLX with -1 opcode optype = 'u8' if int(opcode) >= 0 else 'i8' ffi_name = _ffi_const_name(nametup) _f.section(0) _f('') _f('pub const %s: %s = %s;', ffi_name, optype, opcode) rs_name = _rs_const_name(nametup) _r.section(1) _r('') _r('pub const %s: %s = %s;', rs_name, optype, opcode) def _cookie(request): _f.section(0) _f('') _f('#[derive(Copy, Clone)]') _f('#[repr(C)]') _f('pub struct %s {', request.ffi_cookie_type) _f(' pub(crate) sequence: c_uint') _f('}') _r("impl base::CookieSeq for %s {", request.ffi_cookie_type) with _r.indent_block(): _r("fn sequence(&self) -> c_uint { self.sequence }") _r("}") _r.section(1) _r("") _r("pub type %s<'a> = base::Cookie<'a, %s>;", request.rs_cookie_type, request.ffi_cookie_type) cookie = request.rs_cookie_type reply = request.rs_reply_type func = request.ffi_reply_fn _r.section(1) _r('') _r("impl<'a> %s<'a> {", cookie) with _r.indent_block(): _r("pub fn get_reply(self) -> Result<%s, base::GenericError> {", reply) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r("if self.checked {") _r(" let mut err: *mut xcb_generic_error_t = " + "std::ptr::null_mut();") _r(" let reply = %s {", reply) _r(" ptr: %s (self.conn.get_raw_conn(), self.cookie, &mut err)", func) _r(" };") _r(" std::mem::forget(self);") _r(" if err.is_null() { Ok (reply) }") _r(" else { Err(base::GenericError { ptr: err }) }") _r("} else {") _r(" let res = %s {", reply) _r(" ptr: %s (self.conn.get_raw_conn(), self.cookie, ", func) _r(" std::ptr::null_mut())") _r(" };") _r(" std::mem::forget(self);") _r(" Ok(res)") _r("}") _r('}') _r('}') _r('}') def _must_pack_event(event, nametup): # The generic event structure xcb_ge_event_t has the full_sequence field # at the 32byte boundary. That's why we've to inject this field into GE # events while generating the structure for them. Otherwise we would read # garbage (the internal full_sequence) when accessing normal event fields # there. must_pack = False if (hasattr(event, 'is_ge_event') and event.is_ge_event and event.name == nametup): event_size = 0 for field in event.fields: if field.type.size != None and field.type.nmemb != None: event_size += field.type.size * field.type.nmemb if event_size == 32: full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True) idx = event.fields.index(field) event.fields.insert(idx + 1, full_sequence) # If the event contains any 64-bit extended fields, they need # to remain aligned on a 64-bit boundary. Adding full_sequence # would normally break that; force the struct to be packed. must_pack = any(f.type.size == 8 and f.type.is_simple for f in event.fields[(idx+1):]) break return must_pack def _handle_switch(typeobj, nametup): if typeobj.is_switch and typeobj.ffi_type not in finished_switch: finished_switch.append(typeobj.ffi_type) for bitcase in typeobj.bitcases: fname = _symbol(bitcase.field_name) bitcase.ffi_field_name = fname bitcase.rs_field_name = fname bitcase.nametup = (bitcase.field_type if bitcase.type.has_name else nametup) _ffi_type_setup(bitcase.type, bitcase.nametup, ()) _rs_type_setup(bitcase.type, bitcase.nametup, ()) _set_type_lifetime(typeobj, True) _ffi_struct(typeobj) _rs_struct(typeobj) for bitcase in typeobj.bitcases: _ffi_accessors(bitcase.type, bitcase.nametup) # TODO: rs accessors if typeobj.is_container: for f in typeobj.fields: _prepare_doc(f.type) _handle_switch(f.type, f.field_type) # codegen drivers def rs_simple(simple, nametup): ''' simple is SimpleType object nametup is a name tuple ''' global current_handler current_handler = ('simple: ', nametup) _prepare_doc(simple) simple.has_lifetime = False _ffi_type_setup(simple, nametup) _f.section(0) assert len(simple.name) == 1 _f('') _write_doc_brief_desc(_f, simple.doc) _f('pub type %s = %s;', simple.ffi_type, simple.name[0]) _ffi_iterator(simple, nametup) _rs_type_setup(simple, nametup) _r.section(0) _r('') _write_doc_brief_desc(_r, simple.doc) _r('pub type %s = %s;', simple.rs_type, simple.ffi_type) def rs_enum(typeobj, nametup): ''' typeobj is xcbgen.xtypes.Enum object nametup is a name tuple ''' global current_handler current_handler = ('enum: ', nametup) _prepare_doc(typeobj) ecg = EnumCodegen(nametup, typeobj.doc) val = -1 for (enam, eval) in typeobj.values: val = int(eval) if eval != '' else val+1 ecg.add_discriminant(enam, val) ecg.write_ffi() ecg.write_rs() def rs_struct(struct, nametup): ''' struct is Struct object nametup is a name tuple ''' global current_handler current_handler = ('struct: ', nametup) _prepare_doc(struct) struct.has_lifetime = True _ffi_type_setup(struct, nametup) _rs_type_setup(struct, nametup) _handle_switch(struct, nametup) _set_type_lifetime(struct, struct.has_lifetime) _ffi_struct(struct) _ffi_accessors(struct, nametup) _ffi_iterator(struct, nametup) _rs_struct(struct) _rs_accessors(struct) _rs_iterator(struct) def rs_union(union, nametup): ''' union is Union object nametup is a name tuple ''' global current_handler current_handler = ('union: ', nametup) _prepare_doc(union) union.has_lifetime = False _ffi_type_setup(union, nametup) _rs_type_setup(union, nametup) biggest = 1 most_aligned = 1 ptr_size = 8 if sys.maxsize > 2**32 else 4 for field in union.fields: fs = ptr_size fa = ptr_size if field.type.size: fs = field.type.size fa = field.type.size if field.type.nmemb: fs = fa * field.type.nmemb biggest = max(biggest, fs) most_aligned = max(most_aligned, fa) assert biggest >= most_aligned num_aligned = int(biggest / most_aligned) if biggest % most_aligned: num_aligned += 1 num_bytes = num_aligned * most_aligned union.union_num_bytes = num_bytes _f.section(0) _f('') _write_doc_brief_desc(_f, union.doc) _f('// union') _f('#[repr(C)]') _f('pub struct %s {', union.ffi_type) _f(' pub data: [u8; %d]', num_bytes) _f('}') _f('') _f('impl Copy for %s {}', union.ffi_type) _f('impl Clone for %s {', union.ffi_type) _f(' fn clone(&self) -> %s { *self }', union.ffi_type) _f('}') _ffi_iterator(union, nametup) _r.section(1) _r('') _r('pub type %s = %s;', union.rs_type, union.ffi_type) _rs_accessors(union) _rs_iterator(union) def rs_request(request, nametup): ''' request is Request object nametup is a name tuple ''' global current_handler current_handler = ('request: ', nametup) _prepare_doc(request) request.has_lifetime = False _ffi_type_setup(request, nametup, ('request',)) _rs_type_setup(request, nametup, ('request',)) _handle_switch(request, nametup) _set_type_lifetime(request, request.has_lifetime) rcg = RequestCodegen(request) _opcode(nametup, request.opcode) _ffi_struct(request) if request.reply: _prepare_doc(request.reply) # enable getting the request from the reply request.reply.request = request request.reply.has_lifetime = False _cookie(request) _ffi_type_setup(request.reply, nametup, ('reply',)) _rs_type_setup(request.reply, nametup, ('reply',)) _handle_switch(request.reply, nametup) _set_type_lifetime(request.reply, request.reply.has_lifetime) _ffi_struct(request.reply) _ffi_accessors(request.reply, nametup + ('reply',)) _ffi_reply(request) if _ffi_reply_has_fds(request.reply): _ffi_reply_fds(request, nametup) _rs_reply(request) _rs_reply_accessors(request.reply) # regular call 'request_name' rcg.write_ffi_rs(True, False) # unregular call 'request_name_checked' or 'request_name_unchecked' # depending on cookie type rcg.write_ffi_rs(False, False) if request.ffi_need_aux: rcg.write_ffi_rs(True, True) rcg.write_ffi_rs(False, True) def rs_event(event, nametup): ''' event is Event object nametup is a name tuple ''' global current_handler current_handler = ('event: ', nametup) must_pack = _must_pack_event(event, nametup) # _must_pack_event may insert fields, # therefore must be called before _prepare_doc _prepare_doc(event) if must_pack: print('event ', nametup, ' is packed') event.has_lifetime = False _ffi_type_setup(event, nametup, ('event',)) _rs_type_setup(event, nametup, ('event',)) _set_type_lifetime(event, event.has_lifetime) _opcode(nametup, event.opcodes[nametup]) _r.section(1) _r('') _write_doc_brief_desc(_r, event.doc) _r('pub type %s = base::Event<%s>;', event.rs_type, event.ffi_type) if event.name == nametup: _ffi_struct(event, must_pack) accessor_fields = [] for f in event.fields: if not f.visible: continue accessor_fields.append(f) if f.type.is_list or f.type.is_switch or f.type.is_bitcase: try: accessor_fields.remove(f.type.expr.lenfield) except: pass new_params = [] if len(event.opcodes) > 1: new_params.append('response_type: u8') _r.section(1) _r('') _r('impl %s {', event.rs_type) with _r.indent_block(): for f in accessor_fields: for fd in event.doc.fields[f.field_name]: _r('/// %s', fd) _rs_accessor(event, f, True) rs_ftype = f.rs_field_type if f.has_subscript: rs_ftype = "[%s; %d]" % (rs_ftype, f.type.nmemb) new_params.append("%s: %s" % (f.rs_field_name, rs_ftype)) _r('/// Constructs a new %s', event.rs_type) if len(event.opcodes) > 1: _r('/// `response_type` must be set to one of:') for opname in event.opcodes: _r('/// - `%s`', _rs_const_name(opname)) else: _r('/// `response_type` will be set automatically to %s', _rs_const_name(nametup)) fn_start = "pub fn new(" fn_space = ' ' * len(fn_start) p = new_params[0] if len(new_params) else '' eol = ',' if len(new_params)>1 else ')' _r('%s%s%s', fn_start, p, eol) for (i, p) in enumerate(new_params[1:]): eol = ',' if i != len(new_params)-2 else ')' _r("%s%s%s", fn_space, p, eol) _r(' -> %s {', event.rs_type) with _r.indent_block(): _r('unsafe {') with _r.indent_block(): _r('let raw = libc::malloc(32 as usize) as *mut %s;', event.ffi_type) if len(event.opcodes) > 1: # build list of possible opcodes orlist = ' ||\n '.join( [('response_type == %s' % _rs_const_name(opname)) for opname in event.opcodes]) _r('assert!(%s,', orlist) _r(' "wrong response_type supplied to %s::new");', event.rs_type) _r('(*raw).response_type = response_type;') else: _r('(*raw).response_type = %s;', _rs_const_name(nametup)) for f in event.fields: if not f.visible: continue if f.type.is_container and not f.type.is_union \ and not f.type.rs_is_pod: _r('(*raw).%s = *%s.ptr;', f.ffi_field_name, f.rs_field_name) elif f.type.rs_is_pod: _r('(*raw).%s = %s.base;', f.ffi_field_name, f.rs_field_name) else: assignment = f.rs_field_name if f.rs_field_type == 'bool': assignment = ('if %s { 1 } else { 0 }' % f.rs_field_name) _r('(*raw).%s = %s;', f.ffi_field_name, assignment) _r('%s {', event.rs_type) _r(' ptr: raw') _r('}') _r('}') _r('}') _r('}') else: _f.section(0) _f('') _f('pub type %s = %s;', _ffi_type_name(nametup+('event',)), _ffi_type_name(event.name+('event',))) def rs_error(error, nametup): ''' error is Error object nametup is a name tuple ''' global current_handler current_handler = ('error: ', nametup) _prepare_doc(error) _ffi_type_setup(error, nametup, ('error',)) _opcode(nametup, error.opcodes[nametup]) if error.name == nametup: _ffi_struct(error) else: _f.section(0) _f('') _f('pub type %s = %s;', _ffi_type_name(nametup+('error',)), _ffi_type_name(error.name+('error',))) _rs_type_setup(error, nametup, ('error',)) _r.section(0) _r('') _r('pub struct %s {', error.rs_type) _r(' pub base: base::Error<%s>', error.ffi_type) _r('}') def usage(program): print('Usage: {} -o SRCDIR file.xml', program, file=sys.stderr) if __name__ == '__main__': from optparse import OptionParser parser = OptionParser(usage="Usage: %prog -o SRCDIR file.xml") parser.add_option('-o', '--output', dest='srcdir', metavar='SRCDIR', help='specifies rust src dir where to generate files') (options, args) = parser.parse_args(sys.argv) if options.srcdir == None: parser.error('-o SRCDIR is mandatory') if not os.path.isdir(options.srcdir): parser.error('-o SRCDIR must be a directory') if len(args) < 2: parser.error('input XML file must be supplied') output = { 'open' : rs_open, 'close' : rs_close, 'simple' : rs_simple, 'enum' : rs_enum, 'struct' : rs_struct, 'union' : rs_union, 'request' : rs_request, 'event' : rs_event, 'error' : rs_error } try: from xcbgen.state import Module from xcbgen.xtypes import * except ImportError: print('failed to load xcbgen', file=sys.stderr) raise # Parse the xml header module = Module(args[1], output) module.rs_srcdir = options.srcdir # Build type-registry and resolve type dependencies module.register() module.resolve() # Output the code try: module.generate() except: print('error occured in handler: ', current_handler, file=sys.stderr) raise xcb-0.9.0/src/base.rs010064400017500001750000000630201356254422400125740ustar0000000000000000/* * Copyright (C) 2013 James Miller * Copyright (c) 2016 * Remi Thebault * Thomas Bracht Laumann Jespersen * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without * limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software * is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ use xproto::*; use ffi::base::*; use ffi::xproto::*; #[cfg(feature="xlib_xcb")] use ffi::xlib_xcb::*; #[cfg(feature="xlib_xcb")] use x11::xlib; use libc::{self, c_int, c_char, c_void}; use std::option::Option; use std::error; use std::fmt; use std::mem; use std::ptr::{null, null_mut}; use std::marker::PhantomData; // std::num::Zero is unstable in rustc 1.5 => remove the Zero defined // hereunder as soon as Zero gets stabilized (or replaced by something else) //use std::num::Zero; use std::cmp::Ordering; use std::ops::{BitAnd, BitOr}; use std::ffi::CString; use std::os::unix::io::{AsRawFd, RawFd}; /// Current protocol version pub const X_PROTOCOL: u32 = 11; /// Current minor version pub const X_PROTOCOL_REVISION: u32 = 0; /// X_TCP_PORT + display number = server port for TCP transport pub const X_TCP_PORT: u32 = 6000; /// Opaque type used as key for `Connection::get_extension_data` pub type Extension = xcb_extension_t; /// `xcb::NONE` is the universal null resource or null atom parameter value /// for many core X requests pub const NONE: u32 = 0; /// `xcb::COPY_FROM_PARENT` can be used for many `xcb::create_window` parameters pub const COPY_FROM_PARENT: u32 = 0; /// `xcb::CURRENT_TIME` can be used in most requests that take an `xcb::Timestamp` pub const CURRENT_TIME: u32 = 0; /// `xcb::NO_SYMBOL` fills in unused entries in `xcb::Keysym` tables pub const NO_SYMBOL: u32 = 0; /// `StructPtr` is a wrapper for pointer to struct owned by XCB /// that must not be freed /// it is instead bound to the lifetime of its parent that it borrows immutably pub struct StructPtr<'a, T: 'a> { pub ptr: *mut T, phantom: PhantomData<&'a T> } /// `Event` wraps a pointer to `xcb_*_event_t` /// this pointer will be freed when the `Event` goes out of scope pub struct Event { pub ptr: *mut T } impl Event { pub fn response_type(&self) -> u8 { unsafe { let gev : *mut xcb_generic_event_t = mem::transmute(self.ptr); (*gev).response_type } } } impl Drop for Event { fn drop(&mut self) { unsafe { libc::free(self.ptr as *mut c_void); } } } #[cfg(feature="thread")] unsafe impl Send for Event {} #[cfg(feature="thread")] unsafe impl Sync for Event {} /// Casts the generic event to the right event. Assumes that the given /// event is really the correct type. pub unsafe fn cast_event<'r, T>(event : &'r GenericEvent) -> &'r T { mem::transmute(event) } /// `Error` wraps a pointer to `xcb_*_error_t` /// this pointer will be freed when the `Error` goes out of scope #[derive(Debug)] pub struct Error { pub ptr: *mut T } impl Error { pub fn response_type(&self) -> u8 { unsafe { let ger : *mut xcb_generic_error_t = mem::transmute(self.ptr); (*ger).response_type } } pub fn error_code(&self) -> u8 { unsafe { let ger : *mut xcb_generic_error_t = mem::transmute(self.ptr); (*ger).error_code } } } impl Drop for Error { fn drop(&mut self) { unsafe { libc::free(self.ptr as *mut c_void); } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "xcb::Error {{ response_type: {}, error_code: {} }}", self.response_type(), self.error_code()) } } impl error::Error for Error { fn description(&self) -> &str { "xcb::Error" } } // Error are readonly and can be safely sent and shared with other threads unsafe impl Send for Error {} unsafe impl Sync for Error {} /// Casts the generic error to the right error. Assumes that the given /// error is really the correct type. pub unsafe fn cast_error<'r, T>(error : &'r GenericError) -> &'r T { mem::transmute(error) } /// wraps a cookie as returned by a request function. /// Instantiations of `Cookie` that are not `VoidCookie` /// should provide a `get_reply` method to return a `Reply` pub struct Cookie<'a, T: Copy + CookieSeq> { pub cookie: T, pub conn: &'a Connection, pub checked: bool, } pub type VoidCookie<'a> = Cookie<'a, xcb_void_cookie_t>; impl<'a> VoidCookie<'a> { pub fn request_check(self) -> Result<(), GenericError> { unsafe { let c: xcb_void_cookie_t = mem::transmute(self.cookie); let err = xcb_request_check(self.conn.get_raw_conn(), c); std::mem::forget(self); if err.is_null() { Ok(()) } else { Err(GenericError { ptr: err }) } } } } impl CookieSeq for xcb_void_cookie_t { fn sequence(&self) -> libc::c_uint { self.sequence } } pub trait CookieSeq { fn sequence(&self) -> libc::c_uint; } impl<'a, T: Copy + CookieSeq> Drop for Cookie<'a, T> { fn drop(&mut self) { unsafe { xcb_discard_reply(self.conn.get_raw_conn(), self.cookie.sequence()) }; } } #[cfg(feature="thread")] unsafe impl<'a, T: Copy + CookieSeq> Send for Cookie<'a, T> {} #[cfg(feature="thread")] unsafe impl<'a, T: Copy + CookieSeq> Sync for Cookie<'a, T> {} /// Wraps a pointer to a `xcb_*_reply_t` /// the pointer is freed when the `Reply` goes out of scope pub struct Reply { pub ptr: *mut T } impl Drop for Reply { fn drop(&mut self) { unsafe { libc::free(self.ptr as *mut c_void); } } } #[cfg(feature="thread")] unsafe impl Send for Reply {} #[cfg(feature="thread")] unsafe impl Sync for Reply {} pub type GenericEvent = Event; pub type GenericError = Error; pub type GenericReply = Reply; //TODO: Implement wrapper functions for constructing auth_info pub type AuthInfo = xcb_auth_info_t; #[cfg(feature="xlib_xcb")] pub enum EventQueueOwner { Xcb, Xlib } /// Error type that is returned by `Connection::has_error` #[derive(Debug)] pub enum ConnError { /// xcb connection errors because of socket, pipe and other stream errors. Connection, /// xcb connection shutdown because of extension not supported ClosedExtNotSupported, /// malloc(), calloc() and realloc() error upon failure, for eg ENOMEM ClosedMemInsufficient, /// Connection closed, exceeding request length that server accepts. ClosedReqLenExceed, /// Connection closed, error during parsing display string. ClosedParseErr, /// Connection closed because the server does not have a screen /// matching the display. ClosedInvalidScreen, /// Connection closed because some FD passing operation failed ClosedFdPassingFailed, } impl ConnError { fn to_str(&self) -> &str { match *self { ConnError::Connection => "Connection error, possible I/O error", ConnError::ClosedExtNotSupported => "Connection closed, X extension not supported", ConnError::ClosedMemInsufficient => "Connection closed, insufficient memory", ConnError::ClosedReqLenExceed => "Connection closed, exceeded request length that server accepts.", ConnError::ClosedParseErr => "Connection closed, error during parsing display string", ConnError::ClosedInvalidScreen => "Connection closed, the server does not have a screen matching the display", ConnError::ClosedFdPassingFailed => "Connection closed, file-descriptor passing operation failed", } } } impl fmt::Display for ConnError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_str().fmt(f) } } impl error::Error for ConnError { fn description(&self) -> &str { self.to_str() } } pub type ConnResult = Result; /// xcb::Connection handles communication with the X server. /// It wraps an `xcb_connection_t` object and /// will call `xcb_disconnect` when the `Connection` goes out of scope pub struct Connection { c: *mut xcb_connection_t, #[cfg(feature="xlib_xcb")] dpy: *mut xlib::Display, } #[cfg(feature="thread")] unsafe impl Send for Connection {} #[cfg(feature="thread")] unsafe impl Sync for Connection {} impl Connection { /// Forces any buffered output to be written to the server. Blocks /// until the write is complete. /// /// Return `true` on success, `false` otherwise. pub fn flush(&self) -> bool { unsafe { xcb_flush(self.c) > 0 } } /// Returns the maximum request length that this server accepts. /// /// In the absence of the BIG-REQUESTS extension, returns the /// maximum request length field from the connection setup data, which /// may be as much as 65535. If the server supports BIG-REQUESTS, then /// the maximum request length field from the reply to the /// BigRequestsEnable request will be returned instead. /// /// Note that this length is measured in four-byte units, making the /// theoretical maximum lengths roughly 256kB without BIG-REQUESTS and /// 16GB with. pub fn get_maximum_request_length(&self) -> u32 { unsafe { xcb_get_maximum_request_length(self.c) } } /// Prefetch the maximum request length without blocking. /// /// Without blocking, does as much work as possible toward computing /// the maximum request length accepted by the X server. /// /// Invoking this function may cause a call to xcb_big_requests_enable, /// but will not block waiting for the reply. /// xcb_get_maximum_request_length will return the prefetched data /// after possibly blocking while the reply is retrieved. /// /// Note that in order for this function to be fully non-blocking, the /// application must previously have called /// `c.prefetch_extension_data(xcb::big_requests::id())` and the reply /// must have already arrived. pub fn prefetch_maximum_request_length(&self) { unsafe { xcb_prefetch_maximum_request_length(self.c); } } /// Returns the next event or error from the server. /// /// Returns the next event or error from the server, or returns `None` in /// the event of an I/O error. Blocks until either an event or error /// arrive, or an I/O error occurs. pub fn wait_for_event(&self) -> Option { unsafe { let event = xcb_wait_for_event(self.c); if event.is_null() { None } else { Some(GenericEvent { ptr: event }) } } } /// Returns the next event or error from the server. /// /// Returns the next event or error from the server, if one is /// available, or returns `None` otherwise. If no event is available, that /// might be because an I/O error like connection close occurred while /// attempting to read the next event, in which case the connection is /// shut down when this function returns. pub fn poll_for_event(&self) -> Option { unsafe { let event = xcb_poll_for_event(self.c); if event.is_null() { None } else { Some(GenericEvent { ptr: event }) } } } /// Returns the next event without reading from the connection. /// /// This is a version of `poll_for_event` that only examines the /// event queue for new events. The function doesn't try to read new /// events from the connection if no queued events are found. /// /// This function is useful for callers that know in advance that all /// interesting events have already been read from the connection. For /// example, callers might use `wait_for_reply` and be interested /// only of events that preceded a specific reply. pub fn poll_for_queued_event(&self) -> Option { unsafe { let event = xcb_poll_for_queued_event(self.c); if event.is_null() { None } else { Some(GenericEvent { ptr: event }) } } } /// Access the data returned by the server. /// /// Accessor for the data returned by the server when the `Connection` /// was initialized. This data includes /// - the server's required format for images, /// - a list of available visuals, /// - a list of available screens, /// - the server's maximum request length (in the absence of the /// BIG-REQUESTS extension), /// - and other assorted information. /// /// See the X protocol specification for more details. pub fn get_setup(&self) -> Setup { unsafe { let setup = xcb_get_setup(self.c); if setup.is_null() { panic!("NULL setup on connection") } mem::transmute(setup) } } /// Test whether the connection has shut down due to a fatal error. /// /// Some errors that occur in the context of a `Connection` /// are unrecoverable. When such an error occurs, the /// connection is shut down and further operations on the /// `Connection` have no effect, but memory will not be freed until /// the `Connection` is dropped. pub fn has_error(&self) -> ConnResult<()> { unsafe { match xcb_connection_has_error(self.c) { 0 => { Ok(()) }, XCB_CONN_ERROR => { Err(ConnError::Connection) }, XCB_CONN_CLOSED_EXT_NOTSUPPORTED => { Err(ConnError::ClosedExtNotSupported) }, XCB_CONN_CLOSED_MEM_INSUFFICIENT => { Err(ConnError::ClosedMemInsufficient) }, XCB_CONN_CLOSED_REQ_LEN_EXCEED => { Err(ConnError::ClosedReqLenExceed) }, XCB_CONN_CLOSED_PARSE_ERR => { Err(ConnError::ClosedParseErr) }, XCB_CONN_CLOSED_INVALID_SCREEN => { Err(ConnError::ClosedInvalidScreen) }, XCB_CONN_CLOSED_FDPASSING_FAILED => { Err(ConnError::ClosedFdPassingFailed) }, _ => { warn!("XCB: unexpected error code from xcb_connection_has_error"); warn!("XCB: Default to ConnError::Connection"); Err(ConnError::Connection) }, } } } /// Allocates an XID for a new object. /// /// Allocates an XID for a new object. Typically used just prior to /// various object creation functions, such as `xcb::create_window`. pub fn generate_id(&self) -> u32 { unsafe { xcb_generate_id(self.c) } } /// Returns the inner ffi `xcb_connection_t` pointer pub fn get_raw_conn(&self) -> *mut xcb_connection_t { self.c } /// Consumes this object, returning the inner ffi `xcb_connection_t` pointer pub fn into_raw_conn(self) -> *mut xcb_connection_t { let c = self.c; mem::forget(self); c } /// Returns the inner ffi `xlib::Display` pointer. #[cfg(feature="xlib_xcb")] pub fn get_raw_dpy(&self) -> *mut xlib::Display { self.dpy } /// Prefetch of extension data into the extension cache /// /// This function allows a "prefetch" of extension data into the /// extension cache. Invoking the function may cause a call to /// xcb_query_extension, but will not block waiting for the /// reply. xcb_get_extension_data will return the prefetched data after /// possibly blocking while it is retrieved. pub fn prefetch_extension_data(&self, ext: &mut Extension) { unsafe { xcb_prefetch_extension_data(self.c, ext); } } /// Caches reply information from QueryExtension requests. /// /// This function is the primary interface to the "extension cache", /// which caches reply information from QueryExtension /// requests. Invoking this function may cause a call to /// xcb_query_extension to retrieve extension information from the /// server, and may block until extension data is received from the /// server. pub fn get_extension_data<'a>(&'a self, ext: &mut Extension) -> Option> { unsafe { let ptr = xcb_get_extension_data(self.c, ext); if !ptr.is_null() { Some(QueryExtensionData { ptr: ptr, _marker: PhantomData }) } else { None } } } /// Sets the owner of the event queue in the case if the connection is opened /// with the XLib interface. the default owner is XLib. #[cfg(feature="xlib_xcb")] pub fn set_event_queue_owner(&self, owner: EventQueueOwner) { debug_assert!(!self.dpy.is_null()); unsafe { XSetEventQueueOwner(self.dpy, match owner { EventQueueOwner::Xcb => XCBOwnsEventQueue, EventQueueOwner::Xlib => XlibOwnsEventQueue }); } } /// Connects to the X server. /// `displayname:` The name of the display. /// /// Connects to the X server specified by `displayname.` If /// `displayname` is `None,` uses the value of the DISPLAY environment /// variable. /// /// Returns Ok(connection object, preferred screen) in case of success, or /// Err(ConnError) in case of error. If no screen is preferred, the second /// member of the tuple is set to 0. pub fn connect(displayname: Option<&str>) -> ConnResult<(Connection, i32)> { let mut screen_num : c_int = 0; let displayname = displayname.map(|s| CString::new(s).unwrap()); unsafe { let cconn = if let Some(display) = displayname { xcb_connect( display.as_ptr(), &mut screen_num ) } else { xcb_connect( null(), &mut screen_num ) }; // xcb doc says that a valid object is always returned // so we simply assert without handling this in the return assert!(!cconn.is_null(), "had incorrect pointer"); let conn = Self::from_raw_conn(cconn); conn.has_error().map(|_| { (conn, screen_num as i32) }) } } /// Open a new connection with XLib. /// The event queue owner defaults to XLib /// One would need to open an XCB connection with Xlib in order to use /// OpenGL. #[cfg(feature="xlib_xcb")] pub fn connect_with_xlib_display() -> ConnResult<(Connection, i32)> { unsafe { let dpy = xlib::XOpenDisplay(null()); let cconn = XGetXCBConnection(dpy); assert!(!dpy.is_null() && !cconn.is_null(), "XLib could not connect to the X server"); let conn = Connection { c: cconn, dpy: dpy }; conn.has_error().map(|_| { (conn, xlib::XDefaultScreen(dpy) as i32) }) } } /// wraps a `xlib::Display` and get an XCB connection from an exisiting object /// `xlib::XCloseDisplay` will be called when the returned object is dropped #[cfg(feature="xlib_xcb")] pub unsafe fn new_from_xlib_display(dpy: *mut xlib::Display) -> Connection { assert!(!dpy.is_null(), "attempt connect with null display"); Connection { c: XGetXCBConnection(dpy), dpy: dpy } } /// Connects to the X server, using an authorization information. /// display: The name of the display. /// auth_info: The authorization information. /// screen: A pointer to a preferred screen number. /// Returns A newly allocated `Connection` structure. /// /// Connects to the X server specified by displayname, using the /// authorization auth. /// The second member of the returned tuple is the preferred screen, or 0 pub fn connect_with_auth_info(displayname: Option<&str>, auth_info: &AuthInfo) -> ConnResult<(Connection, i32)> { unsafe { let mut screen_num : c_int = 0; let displayname = displayname.map(|s| CString::new(s).unwrap()); let cconn = if let Some(display) = displayname { xcb_connect_to_display_with_auth_info( display.as_ptr(), mem::transmute(auth_info), &mut screen_num ) } else { xcb_connect_to_display_with_auth_info( null(), mem::transmute(auth_info), &mut screen_num ) }; // xcb doc says that a valid object is always returned // so we simply assert without handling this in the return assert!(!cconn.is_null(), "had incorrect pointer"); let conn = Self::from_raw_conn(cconn); conn.has_error().map(|_| { (conn, screen_num as i32) }) } } /// builds a new Connection object from an available connection pub unsafe fn from_raw_conn(conn: *mut xcb_connection_t) -> Connection { assert!(!conn.is_null()); #[cfg(not(feature="xlib_xcb"))] return Connection { c: conn, }; #[cfg(feature="xlib_xcb")] return Connection { c: conn, dpy: null_mut(), }; } } impl AsRawFd for Connection { fn as_raw_fd(&self) -> RawFd { unsafe { xcb_get_file_descriptor(self.c) } } } impl Drop for Connection { fn drop(&mut self) { #[cfg(not(feature="xlib_xcb"))] unsafe { xcb_disconnect(self.c); } #[cfg(feature="xlib_xcb")] unsafe { if self.dpy.is_null() { xcb_disconnect(self.c); } else { xlib::XCloseDisplay(self.dpy); } } } } // Mimics xproto::QueryExtensionReply, but without the Drop trait. // Used for Connection::get_extension_data whose returned value // must not be freed. // Named QueryExtensionData to avoid name collision pub struct QueryExtensionData<'a> { ptr: *const xcb_query_extension_reply_t, _marker: PhantomData<&'a ()>, } impl<'a> QueryExtensionData<'a> { pub fn present(&self) -> bool { unsafe { (*self.ptr).present != 0 } } pub fn major_opcode(&self) -> u8 { unsafe { (*self.ptr).major_opcode } } pub fn first_event(&self) -> u8 { unsafe { (*self.ptr).first_event } } pub fn first_error(&self) -> u8 { unsafe { (*self.ptr).first_error } } } pub trait Zero { fn zero() -> Self; } impl Zero for u8 { fn zero() -> u8 {0} } impl Zero for u16 { fn zero() -> u16 {0} } impl Zero for u32 { fn zero() -> u32 {0} } impl Zero for u64 { fn zero() -> u64 {0} } impl Zero for usize { fn zero() -> usize {0} } impl Zero for i8 { fn zero() -> i8 {0} } impl Zero for i16 { fn zero() -> i16 {0} } impl Zero for i32 { fn zero() -> i32 {0} } impl Zero for i64 { fn zero() -> i64 {0} } impl Zero for isize { fn zero() -> isize {0} } impl Zero for f32 { fn zero() -> f32 {0f32} } impl Zero for f64 { fn zero() -> f64 {0f64} } /// pack bitfields tuples into vector usable for FFI requests /// ``` /// let values = [ /// (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS), /// (xcb::CW_BACK_PIXEL, 0xffffffff), /// ]; /// let ffi_values = ( /// xcb::CW_BACK_PIXEL | xcb::CW_EVENT_MASK, /// [ /// Oxffffffff, /// xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS, /// 0 /// ] /// ); /// assert_eq!(pack_bitfield(&mut values), ffi_values); /// ``` pub fn pack_bitfield(bf : &mut Vec<(T,L)>) -> (T, Vec) where T: Ord + Zero + Copy + BitAnd + BitOr, L: Copy { bf.sort_by(|a,b| { let &(a, _) = a; let &(b, _) = b; if a < b { Ordering::Less } else if a > b { Ordering::Greater } else { Ordering::Equal } }); let mut mask = T::zero(); let mut list: Vec = Vec::new(); for el in bf.iter() { let &(f, v) = el; if mask & f > T::zero() { continue; } else { mask = mask|f; list.push(v); } } (mask, list) } xcb-0.9.0/src/ffi/base.rs010064400017500001750000000471541356254422400133520ustar0000000000000000/* * Copyright (C) 2013 James Miller * Copyright (c) 2016 * Remi Thebault * Thomas Bracht Laumann Jespersen * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without * limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software * is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ use ffi::xproto::{xcb_setup_t, xcb_query_extension_reply_t}; use libc::{c_int, c_uint, c_void, c_char}; // Pre-defined constants /// xcb connection errors because of socket, pipe and other stream errors. pub const XCB_CONN_ERROR: c_int = 1; /// xcb connection shutdown because of extension not supported pub const XCB_CONN_CLOSED_EXT_NOTSUPPORTED: c_int = 2; /// malloc(), calloc() and realloc() error upon failure, for eg ENOMEM pub const XCB_CONN_CLOSED_MEM_INSUFFICIENT: c_int = 3; /// Connection closed, exceeding request length that server accepts. pub const XCB_CONN_CLOSED_REQ_LEN_EXCEED: c_int = 4; /// Connection closed, error during parsing display string. pub const XCB_CONN_CLOSED_PARSE_ERR: c_int = 5; /// Connection closed because the server does not have a screen /// matching the display. pub const XCB_CONN_CLOSED_INVALID_SCREEN: c_int = 6; /// Connection closed because some FD passing operation failed pub const XCB_CONN_CLOSED_FDPASSING_FAILED: c_int = 7; /// XCB connection structure /// An opaque structure that contain all data that XCB needs to communicate /// with an X server. pub enum xcb_connection_t {} /// Opaque structure used as key for xcb_get_extension_data_t pub enum xcb_extension_t {} pub enum xcb_special_event_t {} /// Generic iterator #[repr(C)] pub struct xcb_generic_iterator_t { pub data: *mut c_void, pub rem: c_int, pub index: c_int } /// Generic reply #[derive(Copy, Clone)] #[repr(C)] pub struct xcb_generic_reply_t { pub response_type: u8, pad0: u8, pub sequence: u16, pub length: u32 } /// Generic event #[derive(Copy)] #[repr(C)] pub struct xcb_generic_event_t { pub response_type: u8, pub pad0: u8, pub sequence: u16, pub pad: [u32; 7], pub full_sequence: u32 } impl Clone for xcb_generic_event_t { fn clone(&self) -> xcb_generic_event_t { *self } } /// GE event /// /// An event as sent by the XGE extension. The length field specifies the /// number of 4-byte blocks trailing the struct. /// /// Deprecated Since some fields in this struct have unfortunate names, it is /// recommended to use xcb_ge_generic_event_t instead. //#[deprecated] #[derive(Copy)] #[repr(C)] pub struct xcb_ge_event_t { pub response_type: u8, pad0: u8, pub sequence: u16, pub length: u32, pub event_type: u16, pad1: u16, pad: [u32; 5], pub full_sequence: u32 } impl Clone for xcb_ge_event_t { fn clone(&self) -> xcb_ge_event_t { *self } } /// Generic error #[derive(Copy, Debug)] #[repr(C)] pub struct xcb_generic_error_t { pub response_type: u8, pub error_code: u8, pub sequence: u16, pub resource_id: u32, pub minor_code: u16, pub major_code: u8, pad0: u8, pad: [u32; 5], pub full_sequence: u32 } impl Clone for xcb_generic_error_t { fn clone(&self) -> xcb_generic_error_t { *self } } /// Generic cookie #[derive(Copy, Clone)] #[repr(C)] pub struct xcb_void_cookie_t { /// sequence number pub sequence: c_uint } /// XCB_NONE is the universal null resource or null atom parameter value for many core X requests pub const XCB_NONE: u32 = 0; /// XCB_COPY_FROM_PARENT can be used for many xcb_create_window parameters pub const XCB_COPY_FROM_PARENT: u32 = 0; /// XCB_CURRENT_TIME can be used in most requests that take an xcb_timestamp_t pub const XCB_CURRENT_TIME: u32 = 0; /// XCB_NO_SYMBOL fills in unused entries in xcb_keysym_t tables pub const XCB_NO_SYMBOL: u32 = 0; /// Container for authorization information. /// A container for authorization information to be sent to the X server #[repr(C)] pub struct xcb_auth_info_t { /// length of the string name (as returned by strlen) pub namelen: c_int, /// String containing the authentication protocol name, /// such as "MIT-MAGIC-COOKIE-1" or "XDM-AUTHORIZATION-1". pub name: *mut c_char, /// length of the data member pub datalen: c_int, /// data interpreted in a protocol specific manner pub data: *mut c_char } #[link(name="xcb")] extern { /// Forces any buffered output to be written to the server. Blocks /// until the write is complete. /// /// Return > 0 on success, <= 0 otherwise. pub fn xcb_flush(c: *mut xcb_connection_t) -> c_int; /// Returns the maximum request length that this server accepts. /// /// In the absence of the BIG-REQUESTS extension, returns the /// maximum request length field from the connection setup data, which /// may be as much as 65535. If the server supports BIG-REQUESTS, then /// the maximum request length field from the reply to the /// BigRequestsEnable request will be returned instead. /// /// Note that this length is measured in four-byte units, making the /// theoretical maximum lengths roughly 256kB without BIG-REQUESTS and /// 16GB with. /// /// Returns The maximum request length field. pub fn xcb_get_maximum_request_length(c: *mut xcb_connection_t) -> u32; /// Prefetch the maximum request length without blocking. /// /// Without blocking, does as much work as possible toward computing /// the maximum request length accepted by the X server. /// /// Invoking this function may cause a call to xcb_big_requests_enable, /// but will not block waiting for the reply. /// xcb_get_maximum_request_length will return the prefetched data /// after possibly blocking while the reply is retrieved. /// /// Note that in order for this function to be fully non-blocking, the /// application must previously have called /// xcb_prefetch_extension_data(c, &xcb_big_requests_id) and the reply /// must have already arrived. pub fn xcb_prefetch_maximum_request_length(c: *mut xcb_connection_t); /// Returns the next event or error from the server. /// /// Returns the next event or error from the server, or returns null in /// the event of an I/O error. Blocks until either an event or error /// arrive, or an I/O error occurs. pub fn xcb_wait_for_event(c: *mut xcb_connection_t) -> *mut xcb_generic_event_t; /// Returns the next event or error from the server. /// /// Returns the next event or error from the server, if one is /// available, or returns @c NULL otherwise. If no event is available, that /// might be because an I/O error like connection close occurred while /// attempting to read the next event, in which case the connection is /// shut down when this function returns. pub fn xcb_poll_for_event(c: *mut xcb_connection_t) -> *mut xcb_generic_event_t; /// Returns the next event without reading from the connection. /// /// This is a version of xcb_poll_for_event that only examines the /// event queue for new events. The function doesn't try to read new /// events from the connection if no queued events are found. /// /// This function is useful for callers that know in advance that all /// interesting events have already been read from the connection. For /// example, callers might use xcb_wait_for_reply and be interested /// only of events that preceded a specific reply. pub fn xcb_poll_for_queued_event(c: *mut xcb_connection_t) -> *mut xcb_generic_event_t; /// Returns the next event from a special queue pub fn xcb_poll_for_special_event(c: *mut xcb_connection_t, se: *mut xcb_special_event_t) -> *mut xcb_generic_event_t; /// Returns the next event from a special queue, blocking until one arrives pub fn xcb_wait_for_special_event(c: *mut xcb_connection_t, se: *mut xcb_special_event_t) -> *mut xcb_generic_event_t; /// Listen for a special event pub fn xcb_register_for_special_xge(c: *mut xcb_connection_t, ext: *mut xcb_extension_t, eid: u32, stamp: *mut u32) -> *mut xcb_special_event_t; /// Stop listening for a special event pub fn xcb_unregister_for_special_event(c: *mut xcb_connection_t, se: *mut xcb_special_event_t); /// Return the error for a request, or NULL if none can ever arrive. /// /// The xcb_void_cookie_t cookie supplied to this function must have resulted /// from a call to xcb_[request_name]_checked(). This function will block /// until one of two conditions happens. If an error is received, it will be /// returned. If a reply to a subsequent request has already arrived, no error /// can arrive for this request, so this function will return NULL. /// /// Note that this function will perform a sync if needed to ensure that the /// sequence number will advance beyond that provided in cookie; this is a /// convenience to avoid races in determining whether the sync is needed. pub fn xcb_request_check(c: *mut xcb_connection_t, cookie: xcb_void_cookie_t) -> *mut xcb_generic_error_t; /// Discards the reply for a request. /// /// sequence is the request sequence number from a cookie. /// /// Discards the reply for a request. Additionally, any error generated /// by the request is also discarded (unless it was an _unchecked request /// and the error has already arrived). /// /// This function will not block even if the reply is not yet available. /// /// Note that the sequence really does have to come from an xcb cookie; /// this function is not designed to operate on socket-handoff replies. pub fn xcb_discard_reply(c: *mut xcb_connection_t, sequence: c_uint); /// Discards the reply for a request, given by a 64bit sequence number /// /// sequence is the 64-bit sequence number as returned by xcb_send_request64(). /// /// Discards the reply for a request. Additionally, any error generated /// by the request is also discarded (unless it was an _unchecked request /// and the error has already arrived). /// /// This function will not block even if the reply is not yet available. /// /// Note that the sequence really does have to come from xcb_send_request64(); /// the cookie sequence number is defined as "unsigned" int and therefore /// not 64-bit on all platforms. /// This function is not designed to operate on socket-handoff replies. /// /// Unlike its xcb_discard_reply() counterpart, the given sequence number is not /// automatically "widened" to 64-bit. /// pub fn xcb_discard_reply64(c: *mut xcb_connection_t, sequence: u64); /// Caches reply information from QueryExtension requests. /// /// This function is the primary interface to the "extension cache", /// which caches reply information from QueryExtension /// requests. Invoking this function may cause a call to /// xcb_query_extension to retrieve extension information from the /// server, and may block until extension data is received from the /// server. /// /// The result must not be freed. This storage is managed by the cache /// itself. /// /// Returns A pointer to the xcb_query_extension_reply_t for the extension. pub fn xcb_get_extension_data(c: *mut xcb_connection_t, ext: *mut xcb_extension_t) -> *const xcb_query_extension_reply_t; /// Prefetch of extension data into the extension cache /// /// This function allows a "prefetch" of extension data into the /// extension cache. Invoking the function may cause a call to /// xcb_query_extension, but will not block waiting for the /// reply. xcb_get_extension_data will return the prefetched data after /// possibly blocking while it is retrieved. pub fn xcb_prefetch_extension_data(c: *mut xcb_connection_t, ext: *mut xcb_extension_t); /// Access the data returned by the server. /// /// Accessor for the data returned by the server when the xcb_connection_t /// was initialized. This data includes /// - the server's required format for images, /// - a list of available visuals, /// - a list of available screens, /// - the server's maximum request length (in the absence of the /// BIG-REQUESTS extension), /// - and other assorted information. /// /// See the X protocol specification for more details. /// /// Returns A pointer to an xcb_setup_t structure. /// The result must not be freed. pub fn xcb_get_setup(c: *mut xcb_connection_t) -> *const xcb_setup_t; /// Access the file descriptor of the connection. /// /// Accessor for the file descriptor that was passed to the /// xcb_connect_to_fd call that returned @p c. /// /// Returns The file descriptor. pub fn xcb_get_file_descriptor(c: *mut xcb_connection_t) -> c_int; /// Test whether the connection has shut down due to a fatal error. /// /// Some errors that occur in the context of an xcb_connection_t /// are unrecoverable. When such an error occurs, the /// connection is shut down and further operations on the /// xcb_connection_t have no effect, but memory will not be freed until /// xcb_disconnect() is called on the xcb_connection_t. /// /// Returns XCB_CONN_ERROR, because of socket errors, pipe errors or other stream errors. /// Returns XCB_CONN_CLOSED_EXT_NOTSUPPORTED, when extension not supported. /// Returns XCB_CONN_CLOSED_MEM_INSUFFICIENT, when memory not available. /// Returns XCB_CONN_CLOSED_REQ_LEN_EXCEED, exceeding request length that server accepts. /// Returns XCB_CONN_CLOSED_PARSE_ERR, error during parsing display string. /// Returns XCB_CONN_CLOSED_INVALID_SCREEN, because the server does not have a screen matching the display. /// /// Returns > 0 if the connection is in an error state; 0 otherwise. pub fn xcb_connection_has_error(c: *mut xcb_connection_t) -> c_int; /// Connects to the X server. /// /// Connects to an X server, given the open socket @p fd and the /// xcb_auth_info_t @p auth_info. The file descriptor @p fd is /// bidirectionally connected to an X server. If the connection /// should be unauthenticated, @p auth_info must be @c /// NULL. /// /// Always returns a non-NULL pointer to a xcb_connection_t, even on failure. /// Callers need to use xcb_connection_has_error() to check for failure. /// When finished, use xcb_disconnect() to close the connection and free /// the structure. pub fn xcb_connect_to_fd(fd: c_int, auth_info: *mut xcb_auth_info_t) -> *mut xcb_connection_t; /// Closes the connection. /// /// Closes the file descriptor and frees all memory associated with the /// connection @c c. If @p c is @c NULL, nothing is done. pub fn xcb_disconnect(c: *mut xcb_connection_t); /// Parses a display string name in the form documented by X(7x). /// name: The name of the display. /// host: A pointer to a malloc'd copy of the hostname. /// display: A pointer to the display number. /// screen: A pointer to the screen number. /// /// Parses the display string name display_name in the form /// documented by X(7x). Has no side effects on failure. If /// displayname is NULL or empty, it uses the environment /// variable DISPLAY. hostp is a pointer to a newly allocated string /// that contain the host name. displayp is set to the display /// number and screenp to the preferred screen number. screenp /// can be NULL. If displayname does not contain a screen number, /// it is set to 0. /// /// Returns 0 on failure, non 0 otherwise. pub fn xcb_parse_display(name: *const c_char, host: *mut *mut c_char, display: *mut c_int, screen: *mut c_int) -> c_int; /// Connects to the X server. /// displayname: The name of the display. /// screenp: A pointer to a preferred screen number. /// Returns A newly allocated xcb_connection_t structure. /// /// Connects to the X server specified by displayname. If /// displayname is NULL, uses the value of the DISPLAY environment /// variable. If a particular screen on that server is preferred, the /// int pointed to by screenp (if not NULL) will be set to that /// screen; otherwise the screen will be set to 0. /// /// Always returns a non-NULL pointer to a xcb_connection_t, even on failure. /// Callers need to use xcb_connection_has_error() to check for failure. /// When finished, use xcb_disconnect() to close the connection and free /// the structure. pub fn xcb_connect(displayname: *const c_char, screenp: *mut c_int) -> *mut xcb_connection_t; /// Connects to the X server, using an authorization information. /// display: The name of the display. /// auth: The authorization information. /// screen: A pointer to a preferred screen number. /// Returns A newly allocated xcb_connection_t structure. /// /// Connects to the X server specified by displayname, using the /// authorization auth. If a particular screen on that server is /// preferred, the int pointed to by screenp (if not NULL) will /// be set to that screen; otherwise screenp will be set to 0. /// /// Always returns a non-NULL pointer to a xcb_connection_t, even on failure. /// Callers need to use xcb_connection_has_error() to check for failure. /// When finished, use xcb_disconnect() to close the connection and free /// the structure. pub fn xcb_connect_to_display_with_auth_info(display: *const c_char, auth: *mut xcb_auth_info_t, screen: *mut c_int) -> *mut xcb_connection_t; /// Allocates an XID for a new object. /// Returns A newly allocated XID. /// /// Allocates an XID for a new object. Typically used just prior to /// various object creation functions, such as xcb_create_window. pub fn xcb_generate_id(c: *mut xcb_connection_t) -> u32; } xcb-0.9.0/src/ffi/ext.rs010064400017500001750000000077171356037634500132460ustar0000000000000000/* * Copyright (C) 2013 James Miller * Copyright (c) 2016 * Remi Thebault * Thomas Bracht Laumann Jespersen * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without * limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software * is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ use libc::{c_int, c_uint, c_void}; use ffi::base::*; use ffi::xproto; #[repr(C)] pub struct xcb_extension_t { name: *const c_char, global_id: c_int } #[repr(C)] pub struct xcb_protocol_request_t { count: usize, ext: *mut xcb_extension_t, opcode: u8, isvoid: u8 } #[repr(C)] pub enum xcb_send_request_flags_t { XCB_REQUEST_CHECKED = 0x01, XCB_REQUEST_RAW = 0x02, XCB_REQUEST_DISCARD_REPLY = 0x04, XCB_REQUEST_REPLY_FDS = 0x08 } #[link(name="xcb")] extern { pub fn xcb_send_request(c: *mut xcb_connection_t, flags: c_int, vector: *mut iovec, request: *const xcb_protocol_request_t) -> c_uint; pub fn xcb_send_request64(c: *mut xcb_connection_t, flags: c_int, vector: *mut iovec, request: *const xcb_protocol_request_t) -> u64; pub fn xcb_send_fd(c: *mut xcb_connection_t, fd: c_int); pub fn xcb_take_socket(c: *mut xcb_connection_t, return_socket: extern fn(closure: *mut c_void), closure: *mut c_void, flags: c_int, sent: *mut u64) -> c_int; pub fn xcb_writev(c: *mut xcb_connection_t, vector: *mut iovec, count: c_int, requests: u64) -> c_int; pub fn xcb_wait_for_reply(c: *mut xcb_connection_t, request: c_uint, e: *mut *mut xcb_generic_error_t) -> *mut c_void; pub fn xcb_wait_for_reply64(c: *mut xcb_connection_t, request: u64, e: *mut *mut xcb_generic_error_t) -> *mut c_void; pub fn xcb_poll_for_reply(c: *mut xcb_connection_t, request: c_uint, reply: *mut *mut c_void, error: *mut *mut xcb_generic_error_t) -> c_int; pub fn xcb_poll_for_reply64(c: *mut xcb_connection_t, request: u64, reply: *mut *mut c_void, error: *mut *mut xcb_generic_error_t) -> c_int; pub fn xcb_get_reply_fds(c: *mut xcb_connection_t, reply: *mut c_void, replylen: usize) -> *mut c_int; pub fn xcb_popcount(mask: u32) -> c_int; pub fn xcb_sumof(list: *mut u8, len: c_int) -> c_int; } xcb-0.9.0/src/ffi/xlib_xcb.rs010064400017500001750000000033701356253312200142150ustar0000000000000000/* * Copyright (C) 2013 James Miller * Copyright (c) 2016 * Remi Thebault * Thomas Bracht Laumann Jespersen * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without * limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software * is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #![allow(non_upper_case_globals)] #![allow(non_snake_case)] use ffi::xcb_connection_t; use libc::{c_void, c_uint}; use x11::xlib; pub type XEventQueueOwner = c_uint; pub static XlibOwnsEventQueue : XEventQueueOwner = 0; pub static XCBOwnsEventQueue : XEventQueueOwner = 1; #[link(name="X11-xcb")] extern { pub fn XGetXCBConnection(dpy: *mut xlib::Display) -> *mut xcb_connection_t; pub fn XSetEventQueueOwner(dpy: *mut xlib::Display, owner: XEventQueueOwner); } xcb-0.9.0/src/lib.rs010064400017500001750000000237761356254216600124510ustar0000000000000000/* * Copyright (C) 2013 James Miller * Copyright (c) 2016 * Remi Thebault * Thomas Bracht Laumann Jespersen * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without * limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software * is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #![allow(dead_code)] #![allow(unused_imports)] #![allow(non_snake_case)] #![allow(unused_unsafe)] //! Rust bindings to the XCB library. //! //! The X protocol C-language Binding (XCB - https://xcb.freedesktop.org/) is a //! replacement for Xlib featuring a small footprint, latency hiding, //! direct access to the protocol, improved threading support, and extensibility. //! //! The communication is established with the X server by the creation of a //! `Connection` object. //! //! A client communicates with the server by sending requests. There are 2 types //! of requests: //! //! - void requests: requests that do not expect an answer (e.g. `ChangeProperty`) //! - non-void requests: requests that need a `Reply` (e.g. `GetProperty`) //! //! Void requests are normally unchecked. They are issued by the client, that //! will normally not do anything else about it. For each such request, it exists //! a variant with `_checked` suffix (e.g. `change_property` and `change_property_checked`) //! that allows to receive a confirmation reply from the server via //! `Connection::request_check`. //! //! Conversely, non-void requests are normally checked. When the client retrieves //! the `Reply`, it can check for an `Error`. For each such request, it exists a variant //! with `_unchecked` suffix (e.g. `get_property` and `get_property_unchecked`). //! If this variant is used, the `Reply` is retrieved assuming that there was no error. //! //! The server can also communicate with clients by sending `Event`s. //! The client listens to events with calls such as `Connection::wait_for_event` //! (blocking) or `Connection::poll_for_event` (non-blocking). //! //! API documentation is detailed in modules `base` and `xproto`. //! //! - `base`: contains `Connection` and a few utils //! - `xproto`: X protocol requests and events //! //! X protocol extensions are activated with cargo features extern crate libc; #[cfg(feature="xlib_xcb")] extern crate x11; #[macro_use] extern crate log; pub mod base; pub mod xproto { include!(concat!(env!("OUT_DIR"), "/xproto.rs")); } pub mod big_requests { include!(concat!(env!("OUT_DIR"), "/big_requests.rs")); } pub mod xc_misc { include!(concat!(env!("OUT_DIR"), "/xc_misc.rs")); } pub use base::*; pub use xproto::*; #[cfg(feature = "composite")] pub mod composite { include!(concat!(env!("OUT_DIR"), "/composite.rs")); } #[cfg(feature = "damage")] pub mod damage { include!(concat!(env!("OUT_DIR"), "/damage.rs")); } #[cfg(feature = "dpms")] pub mod dpms { include!(concat!(env!("OUT_DIR"), "/dpms.rs")); } #[cfg(feature = "dri2")] pub mod dri2 { include!(concat!(env!("OUT_DIR"), "/dri2.rs")); } #[cfg(feature = "dri3")] pub mod dri3 { include!(concat!(env!("OUT_DIR"), "/dri3.rs")); } #[cfg(feature = "ge")] pub mod genericevent { include!(concat!(env!("OUT_DIR"), "/genericevent.rs")); } #[cfg(feature = "glx")] pub mod glx { include!(concat!(env!("OUT_DIR"), "/glx.rs")); } #[cfg(feature = "xinput")] pub mod input { include!(concat!(env!("OUT_DIR"), "/input.rs")); } #[cfg(feature = "present")] pub mod present { include!(concat!(env!("OUT_DIR"), "/present.rs")); } #[cfg(feature = "randr")] pub mod randr { include!(concat!(env!("OUT_DIR"), "/randr.rs")); } #[cfg(feature = "record")] pub mod record { include!(concat!(env!("OUT_DIR"), "/record.rs")); } #[cfg(feature = "render")] pub mod render { include!(concat!(env!("OUT_DIR"), "/render.rs")); } #[cfg(feature = "res")] pub mod res { include!(concat!(env!("OUT_DIR"), "/res.rs")); } #[cfg(feature = "screensaver")] pub mod screensaver { include!(concat!(env!("OUT_DIR"), "/screensaver.rs")); } #[cfg(feature = "xselinux")] pub mod selinux { include!(concat!(env!("OUT_DIR"), "/selinux.rs")); } #[cfg(feature = "shape")] pub mod shape { include!(concat!(env!("OUT_DIR"), "/shape.rs")); } #[cfg(feature = "shm")] pub mod shm { include!(concat!(env!("OUT_DIR"), "/shm.rs")); } #[cfg(feature = "sync")] pub mod sync { include!(concat!(env!("OUT_DIR"), "/sync.rs")); } #[cfg(feature = "xtest")] pub mod test { include!(concat!(env!("OUT_DIR"), "/test.rs")); } #[cfg(feature = "xprint")] pub mod x_print { include!(concat!(env!("OUT_DIR"), "/x_print.rs")); } #[cfg(feature = "xevie")] pub mod xevie { include!(concat!(env!("OUT_DIR"), "/xevie.rs")); } #[cfg(feature = "xf86dri")] pub mod xf86dri { include!(concat!(env!("OUT_DIR"), "/xf86dri.rs")); } #[cfg(feature = "xf86vidmode")] pub mod xf86vidmode { include!(concat!(env!("OUT_DIR"), "/xf86vidmode.rs")); } #[cfg(feature = "xfixes")] pub mod xfixes { include!(concat!(env!("OUT_DIR"), "/xfixes.rs")); } #[cfg(feature = "xinerama")] pub mod xinerama { include!(concat!(env!("OUT_DIR"), "/xinerama.rs")); } #[cfg(feature = "xkb")] pub mod xkb { include!(concat!(env!("OUT_DIR"), "/xkb.rs")); } #[cfg(feature = "xvmc")] pub mod xvmc { include!(concat!(env!("OUT_DIR"), "/xvmc.rs")); } #[cfg(feature = "xv")] pub mod xv { include!(concat!(env!("OUT_DIR"), "/xv.rs")); } pub mod ffi { #![allow(non_camel_case_types)] #![allow(improper_ctypes)] pub mod base; pub mod xproto { include!(concat!(env!("OUT_DIR"), "/ffi/xproto.rs")); } pub mod big_requests { include!(concat!(env!("OUT_DIR"), "/ffi/big_requests.rs")); } pub mod xc_misc { include!(concat!(env!("OUT_DIR"), "/ffi/xc_misc.rs")); } pub use ffi::base::*; pub use ffi::xproto::*; #[cfg(feature = "xlib_xcb")] pub mod xlib_xcb; #[cfg(feature = "composite")] pub mod composite { include!(concat!(env!("OUT_DIR"), "/ffi/composite.rs")); } #[cfg(feature = "damage")] pub mod damage { include!(concat!(env!("OUT_DIR"), "/ffi/damage.rs")); } #[cfg(feature = "dpms")] pub mod dpms { include!(concat!(env!("OUT_DIR"), "/ffi/dpms.rs")); } #[cfg(feature = "dri2")] pub mod dri2 { include!(concat!(env!("OUT_DIR"), "/ffi/dri2.rs")); } #[cfg(feature = "dri3")] pub mod dri3 { include!(concat!(env!("OUT_DIR"), "/ffi/dri3.rs")); } #[cfg(feature = "ge")] pub mod genericevent { include!(concat!(env!("OUT_DIR"), "/ffi/genericevent.rs")); } #[cfg(feature = "glx")] pub mod glx { include!(concat!(env!("OUT_DIR"), "/ffi/glx.rs")); } #[cfg(feature = "xinput")] pub mod input { include!(concat!(env!("OUT_DIR"), "/ffi/input.rs")); } #[cfg(feature = "present")] pub mod present { include!(concat!(env!("OUT_DIR"), "/ffi/present.rs")); } #[cfg(feature = "randr")] pub mod randr { include!(concat!(env!("OUT_DIR"), "/ffi/randr.rs")); } #[cfg(feature = "record")] pub mod record { include!(concat!(env!("OUT_DIR"), "/ffi/record.rs")); } #[cfg(feature = "render")] pub mod render { include!(concat!(env!("OUT_DIR"), "/ffi/render.rs")); } #[cfg(feature = "res")] pub mod res { include!(concat!(env!("OUT_DIR"), "/ffi/res.rs")); } #[cfg(feature = "screensaver")] pub mod screensaver { include!(concat!(env!("OUT_DIR"), "/ffi/screensaver.rs")); } #[cfg(feature = "xselinux")] pub mod selinux { include!(concat!(env!("OUT_DIR"), "/ffi/selinux.rs")); } #[cfg(feature = "shape")] pub mod shape { include!(concat!(env!("OUT_DIR"), "/ffi/shape.rs")); } #[cfg(feature = "shm")] pub mod shm { include!(concat!(env!("OUT_DIR"), "/ffi/shm.rs")); } #[cfg(feature = "sync")] pub mod sync { include!(concat!(env!("OUT_DIR"), "/ffi/sync.rs")); } #[cfg(feature = "xtest")] pub mod test { include!(concat!(env!("OUT_DIR"), "/ffi/test.rs")); } #[cfg(feature = "xprint")] pub mod x_print { include!(concat!(env!("OUT_DIR"), "/ffi/x_print.rs")); } #[cfg(feature = "xevie")] pub mod xevie { include!(concat!(env!("OUT_DIR"), "/ffi/xevie.rs")); } #[cfg(feature = "xf86dri")] pub mod xf86dri { include!(concat!(env!("OUT_DIR"), "/ffi/xf86dri.rs")); } #[cfg(feature = "xf86vidmode")] pub mod xf86vidmode { include!(concat!(env!("OUT_DIR"), "/ffi/xf86vidmode.rs")); } #[cfg(feature = "xfixes")] pub mod xfixes { include!(concat!(env!("OUT_DIR"), "/ffi/xfixes.rs")); } #[cfg(feature = "xinerama")] pub mod xinerama { include!(concat!(env!("OUT_DIR"), "/ffi/xinerama.rs")); } #[cfg(feature = "xkb")] pub mod xkb { include!(concat!(env!("OUT_DIR"), "/ffi/xkb.rs")); } #[cfg(feature = "xvmc")] pub mod xvmc { include!(concat!(env!("OUT_DIR"), "/ffi/xvmc.rs")); } #[cfg(feature = "xv")] pub mod xv { include!(concat!(env!("OUT_DIR"), "/ffi/xv.rs")); } } xcb-0.9.0/xcbgen/__init__.py010064400017500001750000000000011356037634500140770ustar0000000000000000 xcb-0.9.0/xcbgen/error.py010064400017500001750000000001641356037634500135030ustar0000000000000000class ResolveException(Exception): ''' Gets thrown when a type doesn't resolve in the XML. ''' pass xcb-0.9.0/xcbgen/expr.py010064400017500001750000000111641356037634500133320ustar0000000000000000''' This module contains helper classes for structure fields and length expressions. ''' class Field(object): ''' Represents a field of a structure. type is the datatype object for the field. field_type is the name of the type (string tuple) field_name is the name of the structure field. visible is true iff the field should be in the request API. wire is true iff the field should be in the request structure. auto is true iff the field is on the wire but not in the request API (e.g. opcode) enum is the enum name this field refers to, if any. ''' def __init__(self, type, field_type, field_name, visible, wire, auto, enum=None, isfd=False): self.type = type self.field_type = field_type self.field_name = field_name self.enum = enum self.visible = visible self.wire = wire self.auto = auto self.isfd = isfd class Expression(object): ''' Represents a mathematical expression for a list length or exprfield. Public fields: op is the operation (text +,*,/,<<,~) or None. lhs and rhs are the sub-Expressions if op is set. lenfield_name is the name of the length field, or None for request lists. lenfield is the Field object for the length field, or None. bitfield is True if the length field is a bitmask instead of a number. nmemb is the fixed size (value)of the expression, or None ''' def __init__(self, elt, parent): self.parent = parent self.nmemb = None self.lenfield_name = None self.lenfield_type = None self.lenfield_parent = None self.lenfield = None self.lenwire = False self.bitfield = False self.op = None self.lhs = None self.rhs = None if elt.tag == 'list': # List going into a request, which has no length field (inferred by server) self.lenfield_name = elt.get('name') + '_len' self.lenfield_type = 'CARD32' elif elt.tag == 'fieldref': # Standard list with a fieldref self.lenfield_name = elt.text elif elt.tag == 'valueparam': # Value-mask. The length bitmask is described by attributes. self.lenfield_name = elt.get('value-mask-name') self.lenfield_type = elt.get('value-mask-type') self.lenwire = True self.bitfield = True elif elt.tag == 'op': # Op field. Need to recurse. self.op = elt.get('op') self.lhs = Expression(list(elt)[0], parent) self.rhs = Expression(list(elt)[1], parent) # Hopefully we don't have two separate length fields... self.lenfield_name = self.lhs.lenfield_name if self.lenfield_name == None: self.lenfield_name = self.rhs.lenfield_name elif elt.tag == 'unop': # Op field. Need to recurse. self.op = elt.get('op') self.rhs = Expression(list(elt)[0], parent) self.lenfield_name = self.rhs.lenfield_name elif elt.tag == 'value': # Constant expression self.nmemb = int(elt.text, 0) elif elt.tag == 'popcount': self.op = 'popcount' self.rhs = Expression(list(elt)[0], parent) self.lenfield_name = self.rhs.lenfield_name # xcb_popcount returns 'int' - handle the type in the language-specific part elif elt.tag == 'enumref': self.op = 'enumref' self.lenfield_name = (elt.get('ref'), elt.text) elif elt.tag == 'sumof': self.op = 'sumof' self.lenfield_name = elt.get('ref') else: # Notreached raise Exception("undefined tag '%s'" % elt.tag) def fixed_size(self): return self.nmemb != None def resolve(self, module, parents): if self.op == 'enumref': self.lenfield_type = module.get_type(self.lenfield_name[0]) self.lenfield_name = self.lenfield_name[1] elif self.op == 'sumof': # need to find the field with lenfield_name for p in reversed(parents): fields = dict([(f.field_name, f) for f in p.fields]) if self.lenfield_name in fields.keys(): if p.is_bitcase: # switch is the anchestor self.lenfield_parent = p.parents[-1] else: self.lenfield_parent = p self.lenfield_type = fields[self.lenfield_name].field_type break xcb-0.9.0/xcbgen/matcher.py010064400017500001750000000071561356037634500140050ustar0000000000000000''' XML parser. One function for each top-level element in the schema. Most functions just declare a new object and add it to the module. For typedefs, eventcopies, xidtypes, and other aliases though, we do not create a new type object, we just record the existing one under a new name. ''' from os.path import join from xml.etree.cElementTree import parse from xcbgen.xtypes import * def import_(node, module, namespace): ''' For imports, we load the file, create a new namespace object, execute recursively, then record the import (for header files, etc.) ''' # To avoid circular import error from xcbgen import state module.import_level = module.import_level + 1 new_file = join(namespace.dir, '%s.xml' % node.text) new_root = parse(new_file).getroot() new_namespace = state.Namespace(new_file) execute(module, new_namespace) module.import_level = module.import_level - 1 if not module.has_import(node.text): module.add_import(node.text, new_namespace) def typedef(node, module, namespace): id = node.get('newname') name = namespace.prefix + (id,) type = module.get_type(node.get('oldname')) module.add_type(id, namespace.ns, name, type) def xidtype(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) type = module.get_type('CARD32') module.add_type(id, namespace.ns, name, type) def xidunion(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) type = module.get_type('CARD32') module.add_type(id, namespace.ns, name, type) def enum(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) type = Enum(name, node) module.add_type(id, namespace.ns, name, type) def struct(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) type = Struct(name, node) module.add_type(id, namespace.ns, name, type) def union(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) type = Union(name, node) module.add_type(id, namespace.ns, name, type) def request(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) type = Request(name, node) module.add_request(id, name, type) def event(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) event = Event(name, node) event.add_opcode(node.get('number'), name, True) module.add_event(id, name, event) def eventcopy(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) event = module.get_event(node.get('ref')) event.add_opcode(node.get('number'), name, False) module.add_event(id, name, event) def error(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) error = Error(name, node) error.add_opcode(node.get('number'), name, True) module.add_error(id, name, error) def errorcopy(node, module, namespace): id = node.get('name') name = namespace.prefix + (id,) error = module.get_error(node.get('ref')) error.add_opcode(node.get('number'), name, False) module.add_error(id, name, error) funcs = {'import' : import_, 'typedef' : typedef, 'xidtype' : xidtype, 'xidunion' : xidunion, 'enum' : enum, 'struct' : struct, 'union' : union, 'request' : request, 'event' : event, 'eventcopy' : eventcopy, 'error' : error, 'errorcopy' : errorcopy} def execute(module, namespace): for elt in list(namespace.root): funcs[elt.tag](elt, module, namespace) xcb-0.9.0/xcbgen/state.py010064400017500001750000000124521356037634500134750ustar0000000000000000''' This module contains the namespace class and the singleton module class. ''' from os.path import dirname, basename from xml.etree.cElementTree import parse from xcbgen import matcher from xcbgen.error import * from xcbgen.xtypes import * import __main__ class Namespace(object): ''' Contains the naming information for an extension. Public fields: header is the header attribute ("header file" name). is_ext is true for extensions, false for xproto. major_version and minor_version are extension version info. ext_xname is the X extension name string. ext_name is the XCB extension name prefix. ''' def __init__(self, filename): # Path info self.path = filename self.dir = dirname(filename) self.file = basename(filename) # Parse XML self.root = parse(filename).getroot() self.header = self.root.get('header') self.ns = self.header + ':' # Get root element attributes if self.root.get('extension-xname', False): self.is_ext = True self.major_version = self.root.get('major-version') self.minor_version = self.root.get('minor-version') self.ext_xname = self.root.get('extension-xname') self.ext_name = self.root.get('extension-name') self.prefix = ('xcb', self.ext_name) else: self.is_ext = False self.ext_name = '' self.prefix = ('xcb',) class Module(object): ''' This is the grand, encompassing class that represents an entire XCB specification. Only gets instantiated once, in the main() routine. Don't need to worry about this much except to declare it and to get the namespace. Public fields: namespace contains the namespace info for the spec. ''' open = __main__.output['open'] close = __main__.output['close'] def __init__(self, filename, output): self.namespace = Namespace(filename) self.output = output self.imports = [] self.direct_imports = [] self.import_level = 0 self.types = {} self.events = {} self.errors = {} self.all = [] # Register some common types self.add_type('CARD8', '', ('u8',), tcard8) self.add_type('CARD16', '', ('u16',), tcard16) self.add_type('CARD32', '', ('u32',), tcard32) self.add_type('CARD64', '', ('u64',), tcard64) self.add_type('INT8', '', ('i8',), tint8) self.add_type('INT16', '', ('i16',), tint16) self.add_type('INT32', '', ('i32',), tint32) self.add_type('INT64', '', ('i64',), tint64) self.add_type('BYTE', '', ('u8',), tcard8) self.add_type('BOOL', '', ('BOOL',), tbool) self.add_type('char', '', ('c_char',), tchar) self.add_type('float', '', ('f32',), tfloat) self.add_type('double', '', ('f64',), tdouble) self.add_type('void', '', ('c_void',), tcard8) # This goes out and parses the rest of the XML def register(self): matcher.execute(self, self.namespace) # Recursively resolve all types def resolve(self): for (name, item) in self.all: self.pads = 0 item.resolve(self) # Call all the output methods def generate(self): self.open() for (name, item) in self.all: item.out(name) self.close() # Keeps track of what's been imported so far. def add_import(self, name, namespace): if self.import_level == 0: self.direct_imports.append((name, namespace.header)) self.imports.append((name, namespace.header)) def has_import(self, name): for (name_, header) in self.imports: if name_ == name: return True return False # Keeps track of non-request/event/error datatypes def add_type(self, id, ns, name, item): key = ns + id if key in self.types: return self.types[key] = (name, item) if name[:-1] == self.namespace.prefix: self.all.append((name, item)) def get_type_impl(self, id, idx): key = id if key in self.types: return self.types[key][idx] key = self.namespace.ns + id if key in self.types: return self.types[key][idx] for key in self.types.keys(): if key.rpartition(':')[2] == id: return self.types[key][idx] raise ResolveException('Type %s not found' % id) def get_type(self, id): return self.get_type_impl(id, 1) def get_type_name(self, id): return self.get_type_impl(id, 0) # Keeps track of request datatypes def add_request(self, id, name, item): if name[:-1] == self.namespace.prefix: self.all.append((name, item)) # Keeps track of event datatypes def add_event(self, id, name, item): self.events[id] = (name, item) if name[:-1] == self.namespace.prefix: self.all.append((name, item)) def get_event(self, id): return self.events[id][1] # Keeps track of error datatypes def add_error(self, id, name, item): self.errors[id] = (name, item) if name[:-1] == self.namespace.prefix: self.all.append((name, item)) def get_error(self, id): return self.errors[id][1] xcb-0.9.0/xcbgen/xtypes.py010064400017500001750000000612141356037634500137110ustar0000000000000000''' This module contains the classes which represent XCB data types. ''' from xcbgen.expr import Field, Expression import __main__ class Type(object): ''' Abstract base class for all XCB data types. Contains default fields, and some abstract methods. ''' def __init__(self, name): ''' Default structure initializer. Sets up default fields. Public fields: name is a tuple of strings specifying the full type name. size is the size of the datatype in bytes, or None if variable-sized. nmemb is 1 for non-list types, None for variable-sized lists, otherwise number of elts. booleans for identifying subclasses, because I can't figure out isinstance(). ''' self.name = name self.size = None self.nmemb = None self.resolved = False # Screw isinstance(). self.is_simple = False self.is_list = False self.is_expr = False self.is_container = False self.is_reply = False self.is_union = False self.is_pad = False self.is_switch = False self.is_bitcase = False def resolve(self, module): ''' Abstract method for resolving a type. This should make sure any referenced types are already declared. ''' raise Exception('abstract resolve method not overridden!') def out(self, name): ''' Abstract method for outputting code. These are declared in the language-specific modules, and there must be a dictionary containing them declared when this module is imported! ''' raise Exception('abstract out method not overridden!') def fixed_size(self): ''' Abstract method for determining if the data type is fixed-size. ''' raise Exception('abstract fixed_size method not overridden!') def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None): ''' Default method for making a data type a member of a structure. Extend this if the data type needs to add an additional length field or something. module is the global module object. complex_type is the structure object. see Field for the meaning of the other parameters. ''' new_field = Field(self, field_type, field_name, visible, wire, auto, enum) # We dump the _placeholder_byte if any fields are added. for (idx, field) in enumerate(complex_type.fields): if field == _placeholder_byte: complex_type.fields[idx] = new_field return complex_type.fields.append(new_field) def make_fd_of(self, module, complex_type, fd_name): ''' Method for making a fd member of a structure. ''' new_fd = Field(self, module.get_type_name('INT32'), fd_name, True, False, False, None, True) # We dump the _placeholder_byte if any fields are added. for (idx, field) in enumerate(complex_type.fields): if field == _placeholder_byte: complex_type.fields[idx] = new_fd return complex_type.fields.append(new_fd) class SimpleType(Type): ''' Derived class which represents a cardinal type like CARD32 or char. Any type which is typedef'ed to cardinal will be one of these. Public fields added: none ''' def __init__(self, name, size): Type.__init__(self, name) self.is_simple = True self.size = size self.nmemb = 1 def resolve(self, module): self.resolved = True def fixed_size(self): return True out = __main__.output['simple'] # Cardinal datatype globals. See module __init__ method. tcard8 = SimpleType(('u8',), 1) tcard16 = SimpleType(('u16',), 2) tcard32 = SimpleType(('u32',), 4) tcard64 = SimpleType(('u64',), 8) tint8 = SimpleType(('i8',), 1) tint16 = SimpleType(('i16',), 2) tint32 = SimpleType(('i32',), 4) tint64 = SimpleType(('i64',), 8) tbool = SimpleType(('BOOL',), 1) tchar = SimpleType(('c_char',), 1) tfloat = SimpleType(('f32',), 4) tdouble = SimpleType(('f64',), 8) class Enum(SimpleType): ''' Derived class which represents an enum. Fixed-size. Public fields added: values contains a list of (name, value) tuples. value is empty, or a number. bits contains a list of (name, bitnum) tuples. items only appear if specified as a bit. bitnum is a number. ''' def __init__(self, name, elt): SimpleType.__init__(self, name, 4) self.values = [] self.bits = [] self.doc = None for item in list(elt): if item.tag == 'doc': self.doc = Doc(name, item) # First check if we're using a default value if len(list(item)) == 0: self.values.append((item.get('name'), '')) continue # An explicit value or bit was specified. value = list(item)[0] if value.tag == 'value': self.values.append((item.get('name'), value.text)) elif value.tag == 'bit': self.values.append((item.get('name'), '%u' % (1 << int(value.text, 0)))) self.bits.append((item.get('name'), value.text)) def resolve(self, module): self.resolved = True def fixed_size(self): return True out = __main__.output['enum'] class ListType(Type): ''' Derived class which represents a list of some other datatype. Fixed- or variable-sized. Public fields added: member is the datatype of the list elements. parent is the structure type containing the list. expr is an Expression object containing the length information, for variable-sized lists. ''' def __init__(self, elt, member, *parent): Type.__init__(self, member.name) self.is_list = True self.member = member self.parents = list(parent) if elt.tag == 'list': elts = list(elt) self.expr = Expression(elts[0] if len(elts) else elt, self) elif elt.tag == 'valueparam': self.expr = Expression(elt, self) self.size = member.size if member.fixed_size() else None self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None): if not self.fixed_size(): # We need a length field. # Ask our Expression object for it's name, type, and whether it's on the wire. lenfid = self.expr.lenfield_type lenfield_name = self.expr.lenfield_name lenwire = self.expr.lenwire needlen = True # See if the length field is already in the structure. for parent in self.parents: for field in parent.fields: if field.field_name == lenfield_name: needlen = False # It isn't, so we need to add it to the structure ourself. if needlen: type = module.get_type(lenfid) lenfield_type = module.get_type_name(lenfid) type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum) # Add ourself to the structure by calling our original method. Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum) def resolve(self, module): if self.resolved: return self.member.resolve(module) self.expr.resolve(module, self.parents) # Find my length field again. We need the actual Field object in the expr. # This is needed because we might have added it ourself above. if not self.fixed_size(): for parent in self.parents: for field in parent.fields: if field.field_name == self.expr.lenfield_name and field.wire: self.expr.lenfield = field break self.resolved = True def fixed_size(self): return self.member.fixed_size() and self.expr.fixed_size() class ExprType(Type): ''' Derived class which represents an exprfield. Fixed size. Public fields added: expr is an Expression object containing the value of the field. ''' def __init__(self, elt, member, *parents): Type.__init__(self, member.name) self.is_expr = True self.member = member self.parents = parents self.expr = Expression(list(elt)[0], self) self.size = member.size self.nmemb = 1 def resolve(self, module): if self.resolved: return self.member.resolve(module) self.resolved = True def fixed_size(self): return True class PadType(Type): ''' Derived class which represents a padding field. ''' def __init__(self, elt): Type.__init__(self, tcard8.name) self.is_pad = True self.size = 1 self.nmemb = 1 self.align = 1 if elt != None: self.nmemb = int(elt.get('bytes', "1"), 0) self.align = int(elt.get('align', "1"), 0) def resolve(self, module): self.resolved = True def fixed_size(self): return self.align <= 1 class ComplexType(Type): ''' Derived class which represents a structure. Base type for all structure types. Public fields added: fields is an array of Field objects describing the structure fields. ''' def __init__(self, name, elt): Type.__init__(self, name) self.is_container = True self.elt = elt self.fields = [] self.nmemb = 1 self.size = 0 self.lenfield_parent = [self] self.fds = [] def resolve(self, module): if self.resolved: return enum = None # Resolve all of our field datatypes. for child in list(self.elt): if child.tag == 'pad': field_name = 'pad' + str(module.pads) fkey = 'CARD8' type = PadType(child) module.pads = module.pads + 1 visible = False elif child.tag == 'field': field_name = child.get('name') enum = child.get('enum') fkey = child.get('type') type = module.get_type(fkey) visible = True elif child.tag == 'exprfield': field_name = child.get('name') fkey = child.get('type') type = ExprType(child, module.get_type(fkey), *self.lenfield_parent) visible = False elif child.tag == 'list': field_name = child.get('name') fkey = child.get('type') type = ListType(child, module.get_type(fkey), *self.lenfield_parent) visible = True elif child.tag == 'valueparam': field_name = child.get('value-list-name') fkey = 'CARD32' type = ListType(child, module.get_type(fkey), *self.lenfield_parent) visible = True elif child.tag == 'switch': field_name = child.get('name') # construct the switch type name from the parent type and the field name field_type = self.name + (field_name,) type = SwitchType(field_type, child, *self.lenfield_parent) visible = True type.make_member_of(module, self, field_type, field_name, visible, True, False) type.resolve(module) continue elif child.tag == 'fd': fd_name = child.get('name') type = module.get_type('INT32') type.make_fd_of(module, self, fd_name) continue else: # Hit this on Reply continue # Get the full type name for the field field_type = module.get_type_name(fkey) # Add the field to ourself type.make_member_of(module, self, field_type, field_name, visible, True, False, enum) # Recursively resolve the type (could be another structure, list) type.resolve(module) self.calc_size() # Figure out how big we are self.resolved = True def calc_size(self): self.size = 0 for m in self.fields: if not m.wire: continue if m.type.fixed_size(): self.size = self.size + (m.type.size * m.type.nmemb) else: self.size = None break def fixed_size(self): for m in self.fields: if not m.type.fixed_size(): return False return True class SwitchType(ComplexType): ''' Derived class which represents a List of Items. Public fields added: bitcases is an array of Bitcase objects describing the list items ''' def __init__(self, name, elt, *parents): ComplexType.__init__(self, name, elt) self.parents = parents # FIXME: switch cannot store lenfields, so it should just delegate the parents self.lenfield_parent = list(parents) + [self] # self.fields contains all possible fields collected from the Bitcase objects, # whereas self.items contains the Bitcase objects themselves self.bitcases = [] self.is_switch = True elts = list(elt) self.expr = Expression(elts[0] if len(elts) else elt, self) def resolve(self, module): if self.resolved: return parents = list(self.parents) + [self] # Resolve all of our field datatypes. for index, child in enumerate(list(self.elt)): if child.tag == 'bitcase': field_name = child.get('name') if field_name is None: field_type = self.name + ('bitcase%d' % index,) else: field_type = self.name + (field_name,) # use self.parent to indicate anchestor, # as switch does not contain named fields itself type = BitcaseType(index, field_type, child, *parents) # construct the switch type name from the parent type and the field name if field_name is None: type.has_name = False # Get the full type name for the field field_type = type.name visible = True # add the field to ourself type.make_member_of(module, self, field_type, field_name, visible, True, False) # recursively resolve the type (could be another structure, list) type.resolve(module) inserted = False for new_field in type.fields: # We dump the _placeholder_byte if any fields are added. for (idx, field) in enumerate(self.fields): if field == _placeholder_byte: self.fields[idx] = new_field inserted = True break if False == inserted: self.fields.append(new_field) self.calc_size() # Figure out how big we are self.resolved = True def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None): if not self.fixed_size(): # We need a length field. # Ask our Expression object for it's name, type, and whether it's on the wire. lenfid = self.expr.lenfield_type lenfield_name = self.expr.lenfield_name lenwire = self.expr.lenwire needlen = True # See if the length field is already in the structure. for parent in self.parents: for field in parent.fields: if field.field_name == lenfield_name: needlen = False # It isn't, so we need to add it to the structure ourself. if needlen: type = module.get_type(lenfid) lenfield_type = module.get_type_name(lenfid) type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum) # Add ourself to the structure by calling our original method. Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum) # size for switch can only be calculated at runtime def calc_size(self): pass # note: switch is _always_ of variable size, but we indicate here wether # it contains elements that are variable-sized themselves def fixed_size(self): return False # for m in self.fields: # if not m.type.fixed_size(): # return False # return True class Struct(ComplexType): ''' Derived class representing a struct data type. ''' out = __main__.output['struct'] class Union(ComplexType): ''' Derived class representing a union data type. ''' def __init__(self, name, elt): ComplexType.__init__(self, name, elt) self.is_union = True out = __main__.output['union'] class BitcaseType(ComplexType): ''' Derived class representing a struct data type. ''' def __init__(self, index, name, elt, *parent): elts = list(elt) self.expr = [] fields = [] for elt in elts: if elt.tag == 'enumref': self.expr.append(Expression(elt, self)) else: fields.append(elt) ComplexType.__init__(self, name, fields) self.has_name = True self.index = 1 self.lenfield_parent = list(parent) + [self] self.parents = list(parent) self.is_bitcase = True def make_member_of(self, module, switch_type, field_type, field_name, visible, wire, auto, enum=None): ''' register BitcaseType with the corresponding SwitchType module is the global module object. complex_type is the structure object. see Field for the meaning of the other parameters. ''' new_field = Field(self, field_type, field_name, visible, wire, auto, enum) # We dump the _placeholder_byte if any bitcases are added. for (idx, field) in enumerate(switch_type.bitcases): if field == _placeholder_byte: switch_type.bitcases[idx] = new_field return switch_type.bitcases.append(new_field) def resolve(self, module): if self.resolved: return for e in self.expr: e.resolve(module, self.parents+[self]) # Resolve the bitcase expression ComplexType.resolve(self, module) class Reply(ComplexType): ''' Derived class representing a reply. Only found as a field of Request. ''' def __init__(self, name, elt): ComplexType.__init__(self, name, elt) self.is_reply = True self.doc = None for child in list(elt): if child.tag == 'doc': self.doc = Doc(name, child) def resolve(self, module): if self.resolved: return # Reset pads count module.pads = 0 # Add the automatic protocol fields self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True)) self.fields.append(_placeholder_byte) self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True)) self.fields.append(Field(tcard32, tcard32.name, 'length', False, True, True)) ComplexType.resolve(self, module) class Request(ComplexType): ''' Derived class representing a request. Public fields added: reply contains the reply datatype or None for void requests. opcode contains the request number. ''' def __init__(self, name, elt): ComplexType.__init__(self, name, elt) self.reply = None self.doc = None self.opcode = elt.get('opcode') for child in list(elt): if child.tag == 'reply': self.reply = Reply(name, child) if child.tag == 'doc': self.doc = Doc(name, child) def resolve(self, module): if self.resolved: return # Add the automatic protocol fields if module.namespace.is_ext: self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True)) self.fields.append(Field(tcard8, tcard8.name, 'minor_opcode', False, True, True)) self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True)) ComplexType.resolve(self, module) else: self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True)) self.fields.append(_placeholder_byte) self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True)) ComplexType.resolve(self, module) if self.reply: self.reply.resolve(module) out = __main__.output['request'] class Event(ComplexType): ''' Derived class representing an event data type. Public fields added: opcodes is a dictionary of name -> opcode number, for eventcopies. ''' def __init__(self, name, elt): ComplexType.__init__(self, name, elt) self.opcodes = {} self.has_seq = not bool(elt.get('no-sequence-number')) self.is_ge_event = bool(elt.get('xge')) self.doc = None for item in list(elt): if item.tag == 'doc': self.doc = Doc(name, item) def add_opcode(self, opcode, name, main): self.opcodes[name] = opcode if main: self.name = name def resolve(self, module): def add_event_header(): self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True)) if self.has_seq: self.fields.append(_placeholder_byte) self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True)) def add_ge_event_header(): self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True)) self.fields.append(Field(tcard8, tcard8.name, 'extension', False, True, True)) self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True)) self.fields.append(Field(tcard32, tcard32.name, 'length', False, True, True)) self.fields.append(Field(tcard16, tcard16.name, 'event_type', False, True, True)) if self.resolved: return # Add the automatic protocol fields if self.is_ge_event: add_ge_event_header() else: add_event_header() ComplexType.resolve(self, module) out = __main__.output['event'] class Error(ComplexType): ''' Derived class representing an error data type. Public fields added: opcodes is a dictionary of name -> opcode number, for errorcopies. ''' def __init__(self, name, elt): ComplexType.__init__(self, name, elt) self.opcodes = {} def add_opcode(self, opcode, name, main): self.opcodes[name] = opcode if main: self.name = name def resolve(self, module): if self.resolved: return # Add the automatic protocol fields self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True)) self.fields.append(Field(tcard8, tcard8.name, 'error_code', False, True, True)) self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True)) ComplexType.resolve(self, module) out = __main__.output['error'] class Doc(object): ''' Class representing a tag. ''' def __init__(self, name, elt): self.name = name self.description = None self.brief = None self.fields = {} self.errors = {} self.see = {} self.example = None for child in list(elt): text = child.text if child.text else '' if child.tag == 'description': self.description = text.strip() if child.tag == 'brief': self.brief = text.strip() if child.tag == 'field': self.fields[child.get('name')] = text.strip() if child.tag == 'error': self.errors[child.get('type')] = text.strip() if child.tag == 'see': self.see[child.get('name')] = child.get('type') if child.tag == 'example': self.example = text.strip() _placeholder_byte = Field(PadType(None), tcard8.name, 'pad0', False, True, False) xcb-0.9.0/xml/bigreq.xml010064400017500001750000000032511356037634500133250ustar0000000000000000 xcb-0.9.0/xml/composite.xml010064400017500001750000000066211356037634500140620ustar0000000000000000 xproto xfixes 0 1 xcb-0.9.0/xml/damage.xml010064400017500001750000000063431356037634500132770ustar0000000000000000 xproto xfixes 0 1 2 3 xcb-0.9.0/xml/dpms.xml010064400017500001750000000061231356037634500130200ustar0000000000000000 0 1 2 3 xcb-0.9.0/xml/dri2.xml010064400017500001750000000224201356037634500127130ustar0000000000000000 xproto 0 1 2 3 4 5 6 7 8 9 10 0 1 1 2 3 driver_name_length driver_name_length 3 3 driver_name_length device_name_length count count xcb-0.9.0/xml/dri3.xml010064400017500001750000000063611356037634500127220ustar0000000000000000 xproto xcb-0.9.0/xml/ge.xml010064400017500001750000000035071356037634500124530ustar0000000000000000 xcb-0.9.0/xml/glx.xml010064400017500001750000001276461356037634500126650ustar0000000000000000 xproto xproto:WINDOW PBUFFER glx:PIXMAP glx:WINDOW 32791 32792 32793 32794 data_len 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 16777215 length 24 length 4 str_len str_len length num_attribs 2 num_attribs 2 num_attribs 2 num_attribs 2 num_attribs 2 num_attribs 2 num_versions 2 gl_str_len glx_str_len num_attribs 2 num_versions 3 gl_str_len glx_str_len n 7168 7169 7170 length 4 n length 2 n n n n n n n n n n n n n length 4 n n n n n n length 4 n n n n n length 4 n length length 4 n n length 4 n n length 4 length 4 n n length 4 n n length 4 n length n n n xcb-0.9.0/xml/present.xml010064400017500001750000000156421356037634500135430ustar0000000000000000 xproto randr xfixes sync 0 1 2 3 0 0 1 2 3 0 0 1 2 0 0 1 2 0 1 0 1 2 xcb-0.9.0/xml/randr.xml010064400017500001750000000664331356037634500131750ustar0000000000000000 xproto render 0 1 2 3 4 5 nRates 0 1 2 3 0 1 2 3 4 5 6 nSizes nInfo nSizes 0 1 2 3 4 5 6 7 8 9 10 11 12 13 num_crtcs num_outputs num_modes names_len 0 1 2 num_crtcs num_modes num_clones name_len num_atoms length num_units format 8 num_items format 8 num_outputs num_possible_outputs size size size size size size num_crtcs num_outputs num_modes names_len 0 1 2 3 filter_len pending_len pending_nparams current_len current_nparams num_providers 0 1 2 3 num_crtcs num_outputs num_associated_providers num_associated_providers name_len num_atoms length num_items format 8 num_items format 8 0 1 2 3 4 5 xcb-0.9.0/xml/record.xml010064400017500001750000000134441356037634500133370ustar0000000000000000 0 1 2 1 2 3 num_ranges num_client_specs num_ranges num_client_specs num_ranges num_client_specs num_intercepted_clients length 4 xcb-0.9.0/xml/render.xml010064400017500001750000000472731356037634500133470ustar0000000000000000 xproto 0 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 16 17 18 19 20 21 22 23 24 25 26 27 32 33 34 35 36 37 38 39 40 41 42 43 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 0 1 0 1 0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 3 4 5 0 1 2 3 num_visuals num_depths num_formats num_screens num_subpixel num_values glyphs_len glyphs_len num_aliases num_filters filter_len num_stops num_stops num_stops num_stops num_stops num_stops xcb-0.9.0/xml/res.xml010064400017500001750000000124761356037634500126560ustar0000000000000000 xproto 0 1 length num_cross_references num_clients num_types num_specs num_ids num_specs num_sizes xcb-0.9.0/xml/screensaver.xml010064400017500001750000000103301356037634500143700ustar0000000000000000 xproto 0 1 2 0 1 0 1 2 3 xcb-0.9.0/xml/shape.xml010064400017500001750000000136271356037634500131640ustar0000000000000000 xproto 0 1 2 3 4 0 1 2 rectangles_len xcb-0.9.0/xml/shm.xml010064400017500001750000000112531356037634500126440ustar0000000000000000 xproto xcb-0.9.0/xml/sync.xml010064400017500001750000000202601356037634500130270ustar0000000000000000 xproto 0 1 2 0 1 2 3 0 1 0 1 2 3 4 5 name_len counters_len value_mask Counter ValueType Value TestType Delta Events value_mask Counter ValueType Value TestType Delta Events xcb-0.9.0/xml/xc_misc.xml010064400017500001750000000022121356037634500134750ustar0000000000000000 ids_len xcb-0.9.0/xml/xcb.xsd010064400017500001750000000346711356037634500126400ustar0000000000000000 xcb-0.9.0/xml/xevie.xml010064400017500001750000000056161356037634500132030ustar0000000000000000 0 1 xcb-0.9.0/xml/xf86dri.xml010064400017500001750000000134141356037634500133500ustar0000000000000000 bus_id_len client_driver_name_len num_clip_rects num_back_clip_rects device_private_size xcb-0.9.0/xml/xf86vidmode.xml010064400017500001750000000345211356037634500142230ustar0000000000000000 0 1 2 3 4 5 6 7 8 9 10 11 12 0 0 1 privsize privsize num_hsync num_vsync vendor_length vendor_length 3 3 vendor_length model_length modecount privsize privsize privsize privsize 1 flags 1 clocks size 1 1 size 1 1 size 1 1 size 1 1 size 1 1 size 1 1 xcb-0.9.0/xml/xfixes.xml010064400017500001750000000274521356037634500133730ustar0000000000000000 xproto render shape 0 1 0 1 0 1 0 1 2 0 1 2 0 0 width height 0 length 2 nbytes nbytes nbytes width height nbytes 0 1 2 3 num_devices xcb-0.9.0/xml/xinerama.xml010064400017500001750000000065751356037634500136740ustar0000000000000000 xproto number xcb-0.9.0/xml/xinput.xml010064400017500001750000002475641356037634500134240ustar0000000000000000 xfixes xproto name_len 0 1 2 3 4 0 1 2 3 4 5 6 0 1 axes_len len devices_len num_classes num_classes num_this_classes num_all_classes 0 1 num_classes num_classes num_classes num_classes num_classes 0 1 2 3 4 5 0 1 2 3 4 5 32 num_keysyms len 4 num_feedbacks num_keysyms len 4 length keycode_count keysyms_per_keycode keycodes_per_modifier 8 keycodes_per_modifier 8 map_size map_size 32 32 num_valuators len 4 num_classes num_events 32 num_classes num_valuators 1 2 3 4 5 num_valuators num_valuators num_valuators len 4 num_valuators len 4 num_atoms 8 16 32 format 8Bits num_items 16Bits num_items 32Bits num_items format 8Bits num_items 16Bits num_items 32Bits num_items 0 1 buttons_len 1 2 3 4 1 2 name_len len 4 4 num_changes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 mask_len num_mask 0 1 2 3 8 1 2 3 4 5 0 1 1 2 1 2 num_buttons 31 32 num_buttons num_keys len 4 8 name_len 3 4 4 num_classes num_infos 0 1 mask_len 0 1 2 3 4 5 6 7 0 1 2 0 1 2 3 4 31 mask_len num_modifiers num_modifiers num_modifiers num_properties format 8Bits num_items 16Bits num_items 32Bits num_items format 8Bits num_items 16Bits num_items 32Bits num_items num_masks num_barriers 6 4 4 3 28 28 0 1 2 3 4 5 1 2 num_classes 16 buttons_len valuators_len 16 buttons_len valuators_len 0 1 2 3 4 5 0 1 2 3 4 5 6 7 buttons_len 0 1 2 3 4 5 6 7 num_infos 0 1 2 valuators_len valuators_len 16 17 buttons_len valuators_len 0 valuators_len xcb-0.9.0/xml/xkb.xml010064400017500001750000002634031356037634500126470ustar0000000000000000 xproto 255 32 4 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 0 1 2 3 4 5 6 0 1 2 3 4 5 6 7 0 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5 6 7 8 9 10 11 12 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 0 4 0 4 768 1280 0 5 0 5 768 256 512 768 1024 1280 1536 65280 0 1 2 3 254 255 0 1 2 3 7 0 6 7 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 0 1 2 3 4 7 127 7 6 5 4 3 2 1 0 4 3 2 1 0 0 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5 6 7 0 1 2 3 4 0 1 2 3 4 4 4 4 length length 5 3 length 2 nMapEntries hasPreserve nMapEntries 4 nSyms 0 1 2 3 4 129 130 131 132 nMapEntries preserve nMapEntries nPoints nOutlines 4 4 4 nKeys nRows nKeys 1 2 3 4 5 length namesPresent mapsPresent 255 254 253 0 1 2 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 0 1 2 2 0 0 1 2 2 3 3 4 5 6 0 2 0 1 2 3 4 0 1 2 3 4 5 6 7 0 1 2 6 0 1 0 1 2 3 4 5 7 affectWhich clear selectAll NewKeyboardNotify StateNotify ControlsNotify IndicatorStateNotify IndicatorMapNotify NamesNotify CompatMapNotify BellNotify ActionMessage AccessXNotify ExtensionDeviceNotify 32 32 present KeyTypes nTypes KeySyms nKeySyms KeyActions nKeyActions totalActions KeyBehaviors totalKeyBehaviors VirtualMods virtualMods ExplicitComponents totalKeyExplicit ModifierMap totalModMapKeys VirtualModMap totalVModMapKeys present KeyTypes nTypes KeySyms nKeySyms KeyActions nKeyActions totalActions KeyBehaviors totalKeyBehaviors VirtualMods virtualMods ExplicitComponents totalKeyExplicit ModifierMap totalModMapKeys VirtualModMap totalVModMapKeys nSIRtrn groupsRtrn nSI groups which which which Keycodes Geometry Symbols PhysSymbols Types Compat KeyTypeNames nTypes KTLevelNames nTypes nTypes 3 3 nTypes IndicatorNames indicators VirtualModNames virtualMods GroupNames groupNames KeyNames nKeys KeyAliases nKeyAliases RGNames nRadioGroups which Keycodes Geometry Symbols PhysSymbols Types Compat KeyTypeNames nTypes KTLevelNames nTypes IndicatorNames indicators VirtualModNames virtualMods GroupNames groupNames KeyNames nKeys KeyAliases nKeyAliases RGNames nRadioGroups nKeymaps nKeycodes nTypes nCompatMaps nSymbols nGeometries reported Types ClientSymbols ServerSymbols present KeyTypes nTypes KeySyms nKeySyms KeyActions nKeyActions totalActions KeyBehaviors totalKeyBehaviors VirtualMods virtualMods ExplicitComponents totalKeyExplicit ModifierMap totalModMapKeys VirtualModMap totalVModMapKeys CompatMap nSIRtrn groupsRtrn IndicatorMaps nIndicators KeyNames OtherNames which Keycodes Geometry Symbols PhysSymbols Types Compat KeyTypeNames nTypes KTLevelNames nTypes IndicatorNames indicators VirtualModNames virtualMods GroupNames groupNames KeyNames nKeys KeyAliases nKeyAliases RGNames nRadioGroups Geometry nameLen nBtnsRtrn nDeviceLedFBs nBtns nDeviceLedFBs msgLength 8 xcb-0.9.0/xml/xprint.xml010064400017500001750000000261271356037634500134070ustar0000000000000000 xproto nameLen descLen 0 1 0 0 1 1 2 3 4 5 6 1 2 3 4 5 6 7 printerNameLen localeLen listCount printerNameLen localeLen len_data dataLen stringLen nameLen valueLen listCount xcb-0.9.0/xml/xproto.xml010064400017500001750000005701551356037634500134230ustar0000000000000000 WINDOW PIXMAP FONT GCONTEXT 0 1 2 3 4 5 visuals_len 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 0 1 2 allowed_depths_len authorization_protocol_name_len authorization_protocol_data_len reason_len length 4 0 1 vendor_len pixmap_formats_len roots_len 0 1 2 3 4 5 6 7 15 0 1 2 3 4 5 6 7 8 9 10 11 12 0 a key was pressed/released 8 9 10 11 12 15 a mouse button was pressed/released 0 1 a key was pressed 0 1 2 3 4 5 6 7 0 1 2 3 the pointer is in a different window NOT YET DOCUMENTED 31 NOT YET DOCUMENTED 0 1 2 a window is destroyed a window is unmapped a window was mapped window wants to be mapped NOT YET DOCUMENTED 0 1 NOT YET DOCUMENTED 0 1 a window property changed 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 0 1 0 the colormap for some window changed 20 10 5 NOT YET DOCUMENTED 0 1 2 keyboard mapping changed generic event (with length) 0 1 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 1 0 0 1 2 3 4 5 6 7 8 9 10 Creates a window change window attributes 0 1 2 Gets window attributes Destroys a window 0 1 Changes a client's save set Reparents a window Makes a window visible Makes a window invisible 0 1 2 3 4 5 6 0 1 2 3 4 Configures window attributes 0 1 Change window stacking order Get current window geometry x, reply->y); } free(reply); } ]]> children_len query the window tree root); printf("parent = 0x%08x\\n", reply->parent); xcb_window_t *children = xcb_query_tree_children(reply); for (int i = 0; i < xcb_query_tree_children_length(reply); i++) printf("child window = 0x%08x\\n", children[i]); free(reply); } } ]]> name_len Get atom identifier by name atom); free(reply); } } ]]> name_len 0 1 2 data_len format 8 Changes a window property 0 value_len format 8 Gets a window property atoms_len Sets the owner of a selection Gets the owner of a selection 0 1 32 send an event event = window; event->window = window; event->response_type = XCB_CONFIGURE_NOTIFY; event->x = 0; event->y = 0; event->width = 800; event->height = 600; event->border_width = 0; event->above_sibling = XCB_NONE; event->override_redirect = false; xcb_send_event(conn, false, window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)event); xcb_flush(conn); free(event); } ]]> 0 1 0 1 2 3 4 0 Grab the pointer root, /* grab the root window */ XCB_NONE, /* which events to let through */ XCB_GRAB_MODE_ASYNC, /* pointer events should continue as normal */ XCB_GRAB_MODE_ASYNC, /* keyboard mode */ XCB_NONE, /* confine_to = in which window should the cursor stay */ cursor, /* we change the cursor to whatever the user wanted */ XCB_CURRENT_TIME ); if ((reply = xcb_grab_pointer_reply(conn, cookie, NULL))) { if (reply->status == XCB_GRAB_STATUS_SUCCESS) printf("successfully grabbed the pointer\\n"); free(preply); } } ]]> release the pointer 0 1 2 3 4 5 Grab pointer button(s) Grab the keyboard root, /* grab the root window */ XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, /* process events as normal, do not require sync */ XCB_GRAB_MODE_ASYNC ); if ((reply = xcb_grab_keyboard_reply(conn, cookie, NULL))) { if (reply->status == XCB_GRAB_STATUS_SUCCESS) printf("successfully grabbed the keyboard\\n"); free(reply); } } ]]> 0 Grab keyboard key(s) release a key combination 0 1 2 3 4 5 6 7 release queued events get pointer coordinates events_len move mouse pointer 0 1 2 3 Sets input focus 32 name_len opens a font 0 1 properties_len char_infos_len query font metrics string_len1 get text extents name_len pattern_len names_len get matching font names pattern_len properties_len name_len get matching font names and information font_qty path_len Creates a pixmap Destroys a pixmap 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 0 1 2 3 0 1 2 0 1 2 3 0 1 0 1 0 1 Creates a graphics context change graphics context components dashes_len 0 1 2 3 Destroys a graphics context copy areas 0 1 draw lines draw lines 0 1 2 Fills rectangles 0 1 2 length 4 string_len Draws text string_len Draws text 0 1 cmaps_len Allocate a color name_len pixels_len masks_len pixels_len 0 1 2 name_len colors_len name_len 0 0 create cursor Deletes a cursor 0 1 2 name_len check if extension is present names_len keycode_count keysyms_per_keycode length 0 1 2 3 4 5 6 7 0 1 0 1 2 32 0 1 2 0 1 2 0 1 0 1 2 5 6 address_len address_len hosts_len 0 1 0 1 2 0 kills a client atoms_len 0 1 0 1 2 map_len map_len 0 1 2 3 4 5 6 7 keycodes_per_modifier 8 keycodes_per_modifier 8 xcb-0.9.0/xml/xselinux.xml010064400017500001750000000200301356037634500137250ustar0000000000000000 xproto context_len context_len context_len context_len context_len context_len context_len object_context_len data_context_len context_len context_len context_len context_len context_len context_len properties_len context_len context_len context_len context_len context_len context_len selections_len context_len xcb-0.9.0/xml/xtest.xml010064400017500001750000000076001356037634500132250ustar0000000000000000 xproto 0 1 xcb-0.9.0/xml/xv.xml010064400017500001750000000372111356037634500125140ustar0000000000000000 xproto shm 0 1 2 3 4 0 1 0 1 0 1 0 1 2 3 4 0 1 0 1 2 3 4 5 name_size num_formats name_size num_planes num_planes data_size size 16 32 num_adaptors num_encodings num_attributes num_formats num_planes num_planes xcb-0.9.0/xml/xvmc.xml010064400017500001750000000123631356037634500130350ustar0000000000000000 xv num length length 4 length num xcb-0.9.0/.cargo_vcs_info.json0000644000000001120000000000000116470ustar00{ "git": { "sha1": "8d16116665674f4f515dcc619bd294178109a1fd" } }