├── .github └── workflows │ ├── branch_doc.yml │ ├── build_test.yml │ ├── doc.yml │ └── lint.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── EXCEPTION_LIST.txt ├── LICENSE ├── README.md ├── TODO_v1.md ├── build ├── cg │ ├── doc.rs │ ├── enum.rs │ ├── error.rs │ ├── event.rs │ ├── expr.rs │ ├── mod.rs │ ├── request.rs │ ├── struct.rs │ ├── switch.rs │ ├── union.rs │ ├── util.rs │ └── xid.rs ├── ir.rs ├── main.rs ├── output.rs └── parse.rs ├── examples ├── basic_window.rs ├── connect.rs ├── connect_str.rs ├── draw_root_window.rs ├── drawing.rs ├── get_all_windows.rs ├── get_keyboard_names.rs ├── opengl_window.rs ├── present_special_event.rs ├── print_setup.rs ├── randr_crtc_info.rs ├── randr_crtc_listen.rs ├── randr_screen_info.rs ├── randr_screen_modes.rs ├── screen_info.rs ├── screenshot.rs ├── threaded_window.rs ├── xinput_stylus_events.rs ├── xkb_init.rs └── xkb_keyboard_mouse_event.rs ├── gen.sh ├── gen └── diff.sh ├── src ├── base.rs ├── error.rs ├── event.rs ├── ext.rs ├── ffi │ ├── base.rs │ ├── ext.rs │ └── xlib_xcb.rs ├── lat1_str.rs ├── lib.rs └── test.rs └── xml ├── bigreq.xml ├── composite.xml ├── damage.xml ├── dpms.xml ├── dri2.xml ├── dri3.xml ├── ge.xml ├── glx.xml ├── present.xml ├── randr.xml ├── record.xml ├── render.xml ├── res.xml ├── screensaver.xml ├── shape.xml ├── shm.xml ├── sync.xml ├── upstream ├── bigreq.xml ├── composite.xml ├── damage.xml ├── dpms.xml ├── dri2.xml ├── dri3.xml ├── ge.xml ├── glx.xml ├── present.xml ├── randr.xml ├── record.xml ├── render.xml ├── res.xml ├── screensaver.xml ├── shape.xml ├── shm.xml ├── sync.xml ├── xc_misc.xml ├── xevie.xml ├── xf86dri.xml ├── xf86vidmode.xml ├── xfixes.xml ├── xinerama.xml ├── xinput.xml ├── xkb.xml ├── xprint.xml ├── xproto.xml ├── xselinux.xml ├── xtest.xml ├── xv.xml └── xvmc.xml ├── upstream_normalized ├── bigreq.xml ├── composite.xml ├── damage.xml ├── dpms.xml ├── dri2.xml ├── dri3.xml ├── ge.xml ├── glx.xml ├── present.xml ├── randr.xml ├── record.xml ├── render.xml ├── res.xml ├── screensaver.xml ├── shape.xml ├── shm.xml ├── sync.xml ├── xc_misc.xml ├── xevie.xml ├── xf86dri.xml ├── xf86vidmode.xml ├── xfixes.xml ├── xinerama.xml ├── xinput.xml ├── xkb.xml ├── xprint.xml ├── xproto.xml ├── xselinux.xml ├── xtest.xml ├── xv.xml └── xvmc.xml ├── xc_misc.xml ├── xcb.xsd ├── xevie.xml ├── xf86dri.xml ├── xf86vidmode.xml ├── xfixes.xml ├── xinerama.xml ├── xinput.xml ├── xkb.xml ├── xml-xcb.txt ├── xprint.xml ├── xproto.xml ├── xselinux.xml ├── xtest.xml ├── xv.xml └── xvmc.xml /.github/workflows/branch_doc.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - '*' 5 | - '!main' 6 | 7 | name: Build Branch documentation 8 | 9 | jobs: 10 | build: 11 | name: Build Branch documentation and deploy to gh-pages 12 | runs-on: ubuntu-latest 13 | env: 14 | RXCB_RUSTFMT: 1 15 | RUSTDOCFLAGS: -Dwarnings 16 | steps: 17 | - name: Checkout sources 18 | uses: actions/checkout@v2 19 | 20 | - name: Install stable toolchain 21 | uses: actions-rs/toolchain@v1 22 | with: 23 | profile: minimal 24 | toolchain: stable 25 | override: true 26 | components: rustfmt 27 | 28 | - name: Install dependencies 29 | run: | 30 | sudo apt-get update 31 | sudo apt-get install \ 32 | libgl1-mesa-dev \ 33 | libxcb-composite0-dev \ 34 | libxcb-damage0-dev \ 35 | libxcb-dpms0-dev \ 36 | libxcb-dri2-0-dev \ 37 | libxcb-dri3-dev \ 38 | libxcb-glx0-dev \ 39 | libxcb-present-dev \ 40 | libxcb-randr0-dev \ 41 | libxcb-record0-dev \ 42 | libxcb-render0-dev \ 43 | libxcb-res0-dev \ 44 | libxcb-screensaver0-dev \ 45 | libxcb-shape0-dev \ 46 | libxcb-shm0-dev \ 47 | libxcb-sync-dev \ 48 | libxcb-xf86dri0-dev \ 49 | libxcb-xfixes0-dev \ 50 | libxcb-xinerama0-dev \ 51 | libxcb-xkb-dev \ 52 | libxcb-xtest0-dev \ 53 | libxcb-xv0-dev \ 54 | libxcb-xvmc0-dev \ 55 | libx11-xcb-dev 56 | 57 | - name: Run cargo doc 58 | uses: actions-rs/cargo@v1 59 | with: 60 | command: doc 61 | args: --all-features 62 | 63 | - name: Get branch name 64 | id: branch-name 65 | uses: tj-actions/branch-names@v5 66 | 67 | - name: Push on gh-pages 68 | uses: JamesIves/github-pages-deploy-action@4.1.5 69 | with: 70 | branch: gh-pages 71 | folder: target/doc 72 | target-folder: branches/${{ steps.branch-name.outputs.current_branch }} 73 | -------------------------------------------------------------------------------- /.github/workflows/build_test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous Integration 4 | 5 | jobs: 6 | check: 7 | name: Build and Test 8 | runs-on: ubuntu-latest 9 | env: 10 | RUSTDOCFLAGS: -Dwarnings 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v2 14 | 15 | - name: Install stable toolchain 16 | uses: actions-rs/toolchain@v1 17 | with: 18 | profile: minimal 19 | toolchain: stable 20 | override: true 21 | 22 | - name: Install dependencies 23 | run: | 24 | sudo apt-get update 25 | sudo apt-get install \ 26 | libgl1-mesa-dev \ 27 | libxcb-composite0-dev \ 28 | libxcb-damage0-dev \ 29 | libxcb-dpms0-dev \ 30 | libxcb-dri2-0-dev \ 31 | libxcb-dri3-dev \ 32 | libxcb-glx0-dev \ 33 | libxcb-present-dev \ 34 | libxcb-randr0-dev \ 35 | libxcb-record0-dev \ 36 | libxcb-render0-dev \ 37 | libxcb-res0-dev \ 38 | libxcb-screensaver0-dev \ 39 | libxcb-shape0-dev \ 40 | libxcb-shm0-dev \ 41 | libxcb-sync-dev \ 42 | libxcb-xf86dri0-dev \ 43 | libxcb-xfixes0-dev \ 44 | libxcb-xinerama0-dev \ 45 | libxcb-xkb-dev \ 46 | libxcb-xtest0-dev \ 47 | libxcb-xv0-dev \ 48 | libxcb-xvmc0-dev \ 49 | libx11-xcb-dev 50 | 51 | - name: Run cargo build 52 | uses: actions-rs/cargo@v1 53 | with: 54 | command: build 55 | args: --all-features 56 | 57 | - name: Run cargo test 58 | uses: actions-rs/cargo@v1 59 | with: 60 | command: test 61 | args: --all-features 62 | 63 | - name: Run cargo doc 64 | uses: actions-rs/cargo@v1 65 | with: 66 | command: doc 67 | args: --all-features 68 | -------------------------------------------------------------------------------- /.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | name: Build documentation 7 | 8 | jobs: 9 | build: 10 | name: Build main documentation and upload to gh-pages 11 | runs-on: ubuntu-latest 12 | env: 13 | RXCB_RUSTFMT: 1 14 | RUSTDOCFLAGS: -Dwarnings 15 | steps: 16 | - name: Checkout sources 17 | uses: actions/checkout@v2 18 | 19 | - name: Install stable toolchain 20 | uses: actions-rs/toolchain@v1 21 | with: 22 | profile: minimal 23 | toolchain: stable 24 | override: true 25 | components: rustfmt 26 | 27 | - name: Install dependencies 28 | run: | 29 | sudo apt-get update 30 | sudo apt-get install \ 31 | libgl1-mesa-dev \ 32 | libxcb-composite0-dev \ 33 | libxcb-damage0-dev \ 34 | libxcb-dpms0-dev \ 35 | libxcb-dri2-0-dev \ 36 | libxcb-dri3-dev \ 37 | libxcb-glx0-dev \ 38 | libxcb-present-dev \ 39 | libxcb-randr0-dev \ 40 | libxcb-record0-dev \ 41 | libxcb-render0-dev \ 42 | libxcb-res0-dev \ 43 | libxcb-screensaver0-dev \ 44 | libxcb-shape0-dev \ 45 | libxcb-shm0-dev \ 46 | libxcb-sync-dev \ 47 | libxcb-xf86dri0-dev \ 48 | libxcb-xfixes0-dev \ 49 | libxcb-xinerama0-dev \ 50 | libxcb-xkb-dev \ 51 | libxcb-xtest0-dev \ 52 | libxcb-xv0-dev \ 53 | libxcb-xvmc0-dev \ 54 | libx11-xcb-dev 55 | 56 | - name: Run cargo doc 57 | uses: actions-rs/cargo@v1 58 | with: 59 | command: doc 60 | args: --all-features 61 | 62 | - name: Push on gh-pages 63 | uses: JamesIves/github-pages-deploy-action@4.1.5 64 | with: 65 | branch: gh-pages 66 | folder: target/doc -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous Integration 4 | 5 | jobs: 6 | check: 7 | name: Lint 8 | runs-on: ubuntu-latest 9 | env: 10 | RUSTDOCFLAGS: -Dwarnings 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v2 14 | 15 | - name: Install stable toolchain 16 | uses: actions-rs/toolchain@v1 17 | with: 18 | profile: minimal 19 | toolchain: stable 20 | override: true 21 | 22 | - name: Run cargo fmt 23 | uses: actions-rs/cargo@v1 24 | with: 25 | command: fmt 26 | args: --all -- --check 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | .*.sw* 4 | *.pyc 5 | target/ 6 | Cargo.lock 7 | .vscode/ 8 | gen/* 9 | !gen/diff.sh 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guide 2 | 3 | All PRs are welcome. 4 | 5 | When issueing a pull-request, make sure that the repo is formatted with `cargo fmt` 6 | and that `cargo test --all-features` return no error. 7 | 8 | The source code is organize as follow: 9 | 10 | ## `build/` 11 | 12 | The code generation program (aka. the build script). 13 | This program scans the XML definition to produce the Rust source code of the protocol implementation. 14 | 15 | Sometimes, you have to hardcode exceptions in the code generation (e.g. generated different code for a specific request or event). 16 | If you do this (it is better if you don't), add an entry to the `EXCEPTION_LIST.txt` file. 17 | 18 | If you need to write unit test for the generated code, you can add them under `src/test.rs`. 19 | There are also a few generated unit tests in the protocol modules. 20 | 21 | It is often tedious to understand changes of the Rust generated code only by looking at the code generation source code. 22 | There is utility to observe the changes to the generated code 23 | - run `./gen.sh previous` before starting your PR 24 | - run `./gen.sh current` when you think your work is ready. 25 | - generate a diff: 26 | - In VsCode you can open a diff editor by running `gen/diff.sh [module name]`. 27 | - Otherwise run `diff -ur gen/previous gen/current` to generate a textual diff 28 | 29 | ## `examples/` 30 | 31 | Every example is welcome, especially if it covers requests, events or extensions not covered by the current set of examples. 32 | If adding an example, add the corresponding entry in `Cargo.toml`. 33 | The Github workflows ensure that every example compiles. 34 | 35 | ## `gen/` 36 | 37 | Working directory to observe the generated code. The content is not under version control. A sub-directory can be populated by running `./gen.sh [dirname]`. 38 | 39 | ## `src/` 40 | 41 | Base library source code. 42 | 43 | ## `xml/` 44 | 45 | The XML definitions from the XCB project. 46 | These defintions were slightly modified compared to the upstream definitions to ease a part of the code generation. 47 | The unmodified upstream XML definitions are kept in the `xml/upstream` folder. 48 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xcb" 3 | version = "1.5.0" 4 | authors = [ "Remi Thebault " ] 5 | description = "Rust safe bindings for XCB" 6 | repository = "https://github.com/rust-x-bindings/rust-xcb" 7 | documentation = "https://rust-x-bindings.github.io/rust-xcb/xcb/" 8 | readme = "README.md" 9 | keywords = ["xcb", "window", "xlib", "x11", "opengl"] 10 | license = "MIT" 11 | build = "build/main.rs" 12 | exclude = [".github", "examples/todo/*", "gen", "xml/upstream", "xml/upstream_normalized"] 13 | autoexamples = false 14 | edition = "2018" 15 | 16 | [package.metadata.docs.rs] 17 | all-features = true 18 | 19 | [build-dependencies] 20 | quick-xml = "0.30.0" 21 | 22 | [dependencies] 23 | libc = "0.2.102" 24 | bitflags = "1.3.2" 25 | as-raw-xcb-connection = { version = "1.0", optional = true } 26 | 27 | [dependencies.x11] 28 | version = "2.19.0" 29 | optional = true 30 | features = ["xlib"] 31 | 32 | [features] 33 | default = ["libxcb_v1_14"] 34 | debug_atom_names = [] 35 | xlib_xcb = ["x11/xlib"] 36 | libxcb_v1_14 = [] 37 | 38 | composite = [ "xfixes" ] 39 | damage = [ "xfixes" ] 40 | dpms = [] 41 | dri2 = [] 42 | dri3 = [] 43 | ge = [] 44 | glx = [] 45 | present = [ "render", "xfixes", "sync" ] 46 | randr = [ "render" ] 47 | record = [] 48 | render = [] 49 | res = [] 50 | screensaver = [] 51 | shape = [] 52 | shm = [] 53 | sync = [] 54 | xevie = [] 55 | xf86dri = [] 56 | xf86vidmode = [] 57 | xfixes = [ "render", "shape" ] 58 | xinerama = [] 59 | xinput = [ "xfixes" ] 60 | xkb = [] 61 | xprint = [] 62 | xselinux = [] 63 | xtest = [] 64 | xv = [ "shm" ] 65 | xvmc = [ "xv" ] 66 | 67 | [dev-dependencies] 68 | gl = "0.14.0" 69 | png = "0.17.5" 70 | 71 | [dev-dependencies.x11] 72 | version = "2.19.1" 73 | features = ["xlib", "glx"] 74 | 75 | [[example]] 76 | name = "basic_window" 77 | 78 | [[example]] 79 | name = "connect_str" 80 | 81 | [[example]] 82 | name = "connect" 83 | 84 | [[example]] 85 | name = "draw_root_window" 86 | 87 | [[example]] 88 | name = "drawing" 89 | 90 | [[example]] 91 | name = "get_keyboard_names" 92 | required-features = ["xkb", "xinput", "xlib_xcb"] 93 | 94 | [[example]] 95 | name = "get_all_windows" 96 | 97 | [[example]] 98 | name = "opengl_window" 99 | required-features = ["glx", "xlib_xcb", "dri2"] 100 | 101 | [[example]] 102 | name = "present_special_event" 103 | required-features = ["present", "randr"] 104 | 105 | [[example]] 106 | name = "randr_crtc_info" 107 | required-features = ["randr"] 108 | 109 | [[example]] 110 | name = "print_setup" 111 | 112 | [[example]] 113 | name = "randr_crtc_listen" 114 | required-features = ["randr"] 115 | 116 | [[example]] 117 | name = "randr_screen_info" 118 | required-features = ["randr"] 119 | 120 | [[example]] 121 | name = "randr_screen_modes" 122 | required-features = ["randr"] 123 | 124 | [[example]] 125 | name = "screen_info" 126 | 127 | [[example]] 128 | name = "threaded_window" 129 | 130 | [[example]] 131 | name = "xinput_stylus_events" 132 | required-features = ["xinput"] 133 | 134 | [[example]] 135 | name = "screenshot" 136 | 137 | [[example]] 138 | name = "xkb_init" 139 | required-features = ["xkb"] 140 | 141 | [[example]] 142 | name = "xkb_keyboard_mouse_event" 143 | required-features = ["xkb"] 144 | -------------------------------------------------------------------------------- /EXCEPTION_LIST.txt: -------------------------------------------------------------------------------- 1 | This file is an attempt of keeping track of all exceptions introduced in the code generation. 2 | An exception is a difference of code generation based on hard-coded name. 3 | 4 | - switch_exceptions (cg/mod.rs) 5 | - mask_exceptions (cg/mod.rs) 6 | - enum exceptions (x::SendEventDest in cg/enum.rs) 7 | - requests that receive event in parameters (cg/request.rs) 8 | - ClientMessageEvent::new: format is inferred from data (cg/event.rs) 9 | - ClientMessageEvent::data: variant inferred from format (handle_client_message_data in cg/struct.rs) 10 | - randr::NotifyEvent::new: sub_code is inferred from u variant (cg/event.rs) 11 | - randr::NotifyEvent::u: variant inferred from sub_code (handle_randr_notify_data in cg/struct.rs) 12 | - xkb unions have a special treatment, the variant is inferred from a type field, hidden to the user (cg/union.rs) 13 | - xinput::Device is faked from DeviceId and is defined in lib.rs (search for "xinput" in cg folder) 14 | - specific documentation for xinput::InputInfoInfo::Button (cg/switch.rs) 15 | - A small part of the XML definitions is hand edited to make the code generation a lot easier. 16 | and to improve the documentation. 17 | To check what has been edited, a copy of the upstream definitions is kept under 18 | - xml/upstream 19 | - xml/upstream_normalized 20 | The normalized copy is simply a normalization of indentation to 4 spaces. 21 | The hand edition is the diff from xml/upstream_normalized to xml. 22 | Run `diff -ur xml/upstream_normalized xml` to print the diff. 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 James Miller 2 | Copyright (c) 2016-2023 Rémi Thebault <@rtbo> and many others 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust XCB 2 | 3 | Rust-XCB is a safe Rust interface to [XCB](http://xcb.freedesktop.org). 4 | Rust-XCB uses under the hood the core XCB functions to connect and communicate 5 | with the X server. 6 | 7 | __Documentation__: 8 | https://rust-x-bindings.github.io/rust-xcb/xcb/ 9 | 10 | Rust-XCB is constituted of the following components: 11 | - the core library 12 | - the X protocol and its extensions (generated from XML) 13 | 14 | See [CONTRIBUTING.md](https://github.com/rust-x-bindings/rust-xcb/blob/main/CONTRIBUTING.md) for contributions. 15 | 16 | ## The core library 17 | 18 | The main component is the `Connection` class which is used to connect and 19 | communicate to the X server. The `Connection` class wraps calls to the C XCB 20 | functions in a safe to use interface. 21 | 22 | In the new API (`v1.0+`), Rust-XCB takes care of all the heavy lifting of event 23 | and error resolution, including the handling of the different kinds of event 24 | (regular events, "GeGeneric" events, the specifics about Xkb ...) and present 25 | them under a unified and safe to use `enum` instead of requesting the user to 26 | perform unsafe cast as in the C library. 27 | 28 | The core library also provides many traits that are used in the protocol 29 | implementation. e.g. the `BaseEvent` and `BaseError` traits, the `Reply` trait... 30 | The `Raw` trait is also provided to convert into and from C event or error types. 31 | 32 | ## The protocol implementation 33 | 34 | The core X protocol and all the extensions present in XCB are generated from (almost exactly) the same XML 35 | as the XCB C bindings. 36 | The generation is done by the build scripts, entirely written in Rust. 37 | The build script do not generate bindings to the C protocol extensions, it 38 | generates directly a safe Rust implementation of the protocol: 39 | - Simple structures that have the same memory layout than C are translated in 40 | Rust directly (e.g. points etc.) 41 | - More complex structures wrap a slice of raw data and provide accessor methods 42 | (`Debug` will still print all the members correctly) 43 | - The masks use the `bitflags` crate macro 44 | - The enums are enums! 45 | - The unions are also enums that carry data 46 | - The Xids (handles to windows, pixmaps etc.) are type-safe implementations of the `Xid` trait. 47 | - The requests are structures that serialize themselves when passed to the 48 | `Connection`. 49 | - Each request has two type of cookie, for checked and unchecked requests. 50 | This allows type safe reply fetching and error checking 51 | - The protocol and each extension provide an `Event` and an `Error` enum, 52 | which are unified by the core library. 53 | 54 | ## API 55 | 56 | Here are some highlights of the API. 57 | 58 | ### Modules 59 | 60 | Directly under the `xcb` crate is the hand-written core library. 61 | The core protocol is generated in the `x` module and each extension protocol is also generated in its own module. 62 | 63 | ### Window creation request 64 | 65 | ```rust 66 | let window: x::Window = conn.generate_id(); 67 | 68 | conn.send_request(&x::CreateWindow { 69 | depth: x::COPY_FROM_PARENT as u8, 70 | wid: window, 71 | parent: screen.root(), 72 | x: 0, 73 | y: 0, 74 | width: 150, 75 | height: 150, 76 | border_width: 10, 77 | class: x::WindowClass::InputOutput, 78 | visual: screen.root_visual(), 79 | value_list: &[ 80 | x::Cw::BackPixel(screen.white_pixel()), 81 | x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS), 82 | ], 83 | }); 84 | ``` 85 | 86 | ### Checked void request 87 | ```rust 88 | // specific cookie type for the checked request 89 | // code would not compile with `conn.send_request(..)` 90 | let cookie = conn.send_request_checked(&x::MapWindow {window}); 91 | // reports `Ok` or a resolved error enum (e.g. x::Error::Drawable(..)) 92 | conn.check_request(cookie)?; 93 | ``` 94 | 95 | ### Event and error handling 96 | 97 | Events of the core protocol and each activated extension are unified in the `xcb::Event` enum. 98 | Therefore, all events can be handled in a single match expression. 99 | Many functions (such as `wait_for_event`) return a `xcb::Result` which allows idiomatic error handling. 100 | 101 | ```rust 102 | fn main() -> xcb::Result<()> { 103 | // ... 104 | loop { 105 | match conn.wait_for_event()? { 106 | xcb::Event::X(x::Event::KeyPress(key_press)) => { 107 | // do stuff 108 | } 109 | xcb::Event::Xkb(xkb::Event::MapNotify(ev)) => { 110 | // do other stuff (pass data to xkbcommon for example) 111 | } 112 | _ => {} 113 | } 114 | } 115 | } 116 | ``` 117 | 118 | ### Debugging 119 | 120 | All types in Rust XCB implement `Debug` in a way that allows recursive debug print. 121 | E.g. iterators will not print a useless pointer value, but will recurse down to each element. 122 | 123 | There is in addition the optional `"debug_atom_names"` cargo feature under which each atom 124 | will print its name for easier debugging in some situations. 125 | For example, Xinput provide some information about input devices with atom identifiers. 126 | This allows you to quickly look-up which atoms you need to intern and seek for. 127 | E.g. the feature would turn: 128 | ``` 129 | Atom { 130 | res_id: 303, 131 | } 132 | ``` 133 | into 134 | ``` 135 | Atom("Abs Pressure" ; 303) 136 | ``` 137 | 138 | The feature sets global variable to have access to the connection in the `Debug::fmt` call, 139 | so it should be activated only when needed. 140 | -------------------------------------------------------------------------------- /TODO_v1.md: -------------------------------------------------------------------------------- 1 | # TODO list for v1.0 2 | 3 | - [x] Implementation of the new API 4 | - [x] Xid 5 | - [x] Xid unions 6 | - [x] Structs 7 | - [x] Accessors 8 | - [x] Constructor 9 | - [x] Switches 10 | - [x] Constructors 11 | - [x] Expressions 12 | - [x] Enums / Masks 13 | - [x] Unions 14 | - [x] Errors 15 | - [x] Requests 16 | - [x] Events 17 | - [x] Porting examples 18 | - [x] Porting XML examples 19 | - [x] Documentation 20 | - [x] link to reply in request 21 | - [x] Finalize switches naming (e.g. x::CreateWindowValueList -> x::Cw) 22 | - [x] Report request name in protocol errors 23 | - [x] Support of xinput::SendExtensionEvent 24 | - [ ] Examples 25 | - [x] Port old examples 26 | - [x] Create example with XInput (pen tablet?) 27 | - [ ] Update with valuator classes 28 | - [ ] Create example with Vulkan 29 | - [ ] Create example with wgpu 30 | - [ ] Create example using an Fd API 31 | - Missing API tweaks / fixes: 32 | - [x] Cw::EventMask should take an EventMask 33 | - [x] fix xkb::GetMapReplyMap::VirtualMods takes ModMask 34 | - [x] use altenum in xinput for Device (All, Master or Id (or slave?)) 35 | - [x] xinput::ListInputDevice has incomplete InputInfo 36 | - [x] remove fieldrefs in switches 37 | - [x] Debug props should match format 38 | - [x] Fix Fd API 39 | - [x] Reply impl Send and Sync 40 | - [x] Fix the wire_len calculation (32 + 4 * length) 41 | - [x] Porting toy-xcb 42 | - [x] Porting xkbcommon-rs 43 | - [x] Porting x11-clipboard 44 | -------------------------------------------------------------------------------- /build/cg/doc.rs: -------------------------------------------------------------------------------- 1 | use super::CodeGen; 2 | use crate::cg; 3 | use crate::ir; 4 | 5 | use std::io::{self, Write}; 6 | 7 | #[derive(Debug, Clone)] 8 | pub struct DocField { 9 | pub name: String, 10 | pub text: String, 11 | } 12 | 13 | impl DocField { 14 | pub(super) fn emit(&self, out: &mut O, ind: u32) -> io::Result<()> { 15 | emit_doc_text(out, ind, &self.text)?; 16 | Ok(()) 17 | } 18 | } 19 | 20 | #[allow(dead_code)] 21 | #[derive(Debug, Clone)] 22 | pub struct DocError { 23 | pub typ: String, 24 | pub text: String, 25 | } 26 | 27 | #[allow(dead_code)] 28 | #[derive(Debug, Clone)] 29 | pub struct DocSee { 30 | pub typ: String, 31 | pub name: String, 32 | } 33 | 34 | #[allow(dead_code)] 35 | #[derive(Debug, Clone)] 36 | pub struct Doc { 37 | pub brief: Option, 38 | pub description: Option, 39 | pub example: Option, 40 | pub fields: Vec, 41 | pub errors: Vec, 42 | pub sees: Vec, 43 | } 44 | 45 | impl Doc { 46 | pub(super) fn lookup_field(&self, name: &str) -> Option<&DocField> { 47 | self.fields.iter().find(|df| df.name == name) 48 | } 49 | 50 | pub(super) fn emit(&self, out: &mut O, ind: u32) -> io::Result<()> { 51 | let mut empty = true; 52 | if let Some(brief) = &self.brief { 53 | emit_doc_text(out, ind, brief)?; 54 | empty = false; 55 | } 56 | if let Some(desc) = &self.description { 57 | if !empty { 58 | emit_doc_text(out, ind, "")?; 59 | } 60 | emit_doc_text(out, ind, desc)?; 61 | empty = false; 62 | } 63 | if let Some(example) = &self.example { 64 | if example.contains("fn main") { 65 | if !empty { 66 | emit_doc_text(out, ind, "")?; 67 | } 68 | emit_doc_text(out, ind, "# Example")?; 69 | emit_doc_text(out, ind, "```no_run")?; 70 | emit_doc_text(out, ind, example)?; 71 | emit_doc_text(out, ind, "```")?; 72 | } 73 | } 74 | Ok(()) 75 | } 76 | } 77 | 78 | pub(super) fn emit_doc_text(out: &mut O, ind: u32, text: &str) -> io::Result<()> { 79 | for s in text.split('\n') { 80 | let s = s.trim_end(); 81 | if !s.is_empty() { 82 | writeln!(out, "{}/// {}", cg::ind(ind), s.trim_end())?; 83 | } else { 84 | writeln!(out, "{}///", cg::ind(ind))?; 85 | } 86 | } 87 | Ok(()) 88 | } 89 | 90 | impl CodeGen { 91 | pub(super) fn resolve_doc(&self, doc: Option) -> Option { 92 | doc.map(|doc| Doc { 93 | brief: doc.brief, 94 | description: doc.description, 95 | example: doc.example, 96 | fields: doc 97 | .fields 98 | .into_iter() 99 | .map(|df| DocField { 100 | name: cg::rust_field_name(&df.name), 101 | text: df.text, 102 | }) 103 | .collect(), 104 | errors: doc 105 | .errors 106 | .into_iter() 107 | .map(|de| DocError { 108 | typ: de.typ, 109 | text: de.text, 110 | }) 111 | .collect(), 112 | sees: doc 113 | .sees 114 | .into_iter() 115 | .map(|de| DocSee { 116 | typ: de.typ, 117 | name: de.name, 118 | }) 119 | .collect(), 120 | }) 121 | } 122 | 123 | pub(super) fn doc_lookup_field(&self, doc: Option<&Doc>, name: &str) -> Option { 124 | if let Some(doc) = doc { 125 | doc.lookup_field(name).cloned() 126 | } else { 127 | None 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /build/cg/util.rs: -------------------------------------------------------------------------------- 1 | // capitalize each substring beginning by uppercase 2 | // said otherwise: every upper preceded by another upper and followed by a upper is turned to lower 3 | pub(super) fn tit_cap(name: &str) -> String { 4 | if name.len() <= 1 { 5 | return name.into(); 6 | } 7 | 8 | let is_high = |c: char| c.is_ascii_uppercase() | c.is_ascii_digit(); 9 | 10 | let mut res = String::new(); 11 | let mut ch = name.chars(); 12 | let mut prev = ch.next().unwrap(); 13 | res.push(prev.to_ascii_uppercase()); 14 | let mut c = ch.next().unwrap(); 15 | 16 | for next in ch { 17 | if c != '_' { 18 | if is_high(c) && is_high(prev) && (is_high(next) || next == '_') { 19 | res.push(c.to_ascii_lowercase()) 20 | } else if prev == '_' && c != '_' { 21 | res.push(c.to_ascii_uppercase()) 22 | } else { 23 | res.push(c) 24 | } 25 | } 26 | prev = c; 27 | c = next; 28 | } 29 | if is_high(c) && is_high(prev) { 30 | res.push(c.to_ascii_lowercase()); 31 | } else { 32 | res.push(c); 33 | } 34 | 35 | res 36 | } 37 | 38 | #[test] 39 | fn test_tit_cap() { 40 | assert!(tit_cap("SomeString") == "SomeString"); 41 | assert!(tit_cap("WINDOW") == "Window"); 42 | assert!(tit_cap("CONTEXT_TAG") == "ContextTag"); 43 | assert!(tit_cap("value_list") == "ValueList"); 44 | assert!(tit_cap("GContext") == "GContext"); 45 | assert!(tit_cap("IDChoice") == "IdChoice"); 46 | } 47 | 48 | // insert a underscore before each uppercase/digit preceded or follwed by lowercase 49 | // do not apply to the first char 50 | pub(super) fn tit_split(name: &str) -> String { 51 | if name.len() <= 1 { 52 | return name.into(); 53 | } 54 | 55 | let is_high = |c: char| c.is_ascii_uppercase(); 56 | let is_low = |c: char| c.is_ascii_lowercase(); 57 | 58 | let mut res = String::new(); 59 | let mut ch = name.chars(); 60 | let mut prev = ch.next().unwrap(); 61 | res.push(prev); 62 | let mut c = ch.next().unwrap(); 63 | 64 | for next in ch { 65 | if (is_low(prev) && is_high(c) || is_high(c) && is_low(next)) && prev != '_' { 66 | res.push('_'); 67 | } 68 | res.push(c); 69 | prev = c; 70 | c = next; 71 | } 72 | if is_low(prev) && is_high(c) && prev != '_' { 73 | res.push('_'); 74 | } 75 | res.push(c); 76 | 77 | res 78 | } 79 | 80 | #[test] 81 | fn test_tit_split() { 82 | assert_eq!(tit_dig("SomeString"), "Some_String"); 83 | assert_eq!(tit_dig("WINDOW"), "WINDOW"); 84 | } 85 | 86 | pub(super) fn to_snake_case(name: &str) -> String { 87 | tit_split(name).to_ascii_lowercase() 88 | } 89 | 90 | pub(super) fn extract_module(typ: &str) -> (Option<&str>, &str) { 91 | let len = typ.len(); 92 | let colon = typ.as_bytes().iter().position(|b| *b == b':'); 93 | if let Some(colon) = colon { 94 | (Some(&typ[0..colon]), &typ[colon + 1..len]) 95 | } else { 96 | (None, typ) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /build/ir.rs: -------------------------------------------------------------------------------- 1 | //! Intermediate representation module 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct ExtInfo { 5 | pub name: String, 6 | pub xname: String, 7 | pub major_version: u32, 8 | pub minor_version: u32, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct DocField { 13 | pub name: String, 14 | pub text: String, 15 | } 16 | 17 | #[derive(Debug, Clone)] 18 | pub struct DocError { 19 | pub typ: String, 20 | pub text: String, 21 | } 22 | 23 | #[derive(Debug, Clone)] 24 | pub struct DocSee { 25 | pub typ: String, 26 | pub name: String, 27 | } 28 | 29 | #[derive(Debug, Clone)] 30 | pub struct Doc { 31 | pub brief: Option, 32 | pub description: Option, 33 | pub example: Option, 34 | pub fields: Vec, 35 | pub errors: Vec, 36 | pub sees: Vec, 37 | } 38 | 39 | #[derive(Debug, Clone)] 40 | pub enum Expr { 41 | FieldRef(String), 42 | ParamRef(String), 43 | EnumRef { name: String, item: String }, 44 | Value(usize), 45 | Op(String, Box, Box), 46 | Unop(String, Box), 47 | Popcount(Box), 48 | SumOf(String, Option>), 49 | ListElementRef, 50 | } 51 | 52 | #[derive(Debug, Clone)] 53 | pub enum EnumItem { 54 | Bit(String, u32), 55 | Value(String, u32), 56 | } 57 | 58 | #[derive(Debug, Clone)] 59 | pub struct SwitchCase { 60 | pub bit: bool, 61 | pub name: Option, 62 | pub exprs: Vec, 63 | pub fields: Vec, 64 | } 65 | 66 | #[allow(clippy::enum_variant_names)] 67 | #[derive(Debug, Clone)] 68 | pub enum Field { 69 | Pad(usize), 70 | AlignPad(usize), 71 | Field { 72 | name: String, 73 | typ: String, 74 | r#enum: Option, 75 | mask: Option, 76 | altenum: Option, 77 | altmask: Option, 78 | }, 79 | List { 80 | name: String, 81 | typ: String, 82 | len_expr: Expr, 83 | r#enum: Option, 84 | mask: Option, 85 | }, 86 | ListNoLen { 87 | name: String, 88 | typ: String, 89 | r#enum: Option, 90 | mask: Option, 91 | }, 92 | Expr { 93 | name: String, 94 | typ: String, 95 | expr: Expr, 96 | }, 97 | ValueParam { 98 | mask_typ: String, 99 | mask_name: String, 100 | list_name: String, 101 | }, 102 | Fd(String), 103 | Switch(String, Expr, Vec), 104 | } 105 | 106 | #[derive(Debug, Clone)] 107 | pub struct Reply { 108 | pub fields: Vec, 109 | pub doc: Option, 110 | } 111 | 112 | #[derive(Debug, Clone)] 113 | pub struct EventSelector { 114 | pub extension: String, 115 | pub xge: bool, 116 | pub opcode_range: (u32, u32), 117 | } 118 | 119 | #[derive(Debug, Clone)] 120 | pub enum Item { 121 | Error { 122 | name: String, 123 | number: i32, 124 | fields: Vec, 125 | doc: Option, 126 | }, 127 | ErrorCopy { 128 | name: String, 129 | number: i32, 130 | r#ref: String, 131 | }, 132 | Typedef { 133 | old_typ: String, 134 | new_typ: String, 135 | }, 136 | XidType { 137 | typ: String, 138 | }, 139 | XidUnion { 140 | typ: String, 141 | xidtypes: Vec, 142 | }, 143 | Enum { 144 | typ: String, 145 | items: Vec, 146 | doc: Option, 147 | }, 148 | Struct { 149 | typ: String, 150 | fields: Vec, 151 | doc: Option, 152 | }, 153 | Union { 154 | typ: String, 155 | fields: Vec, 156 | doc: Option, 157 | }, 158 | Event { 159 | number: i32, 160 | name: String, 161 | fields: Vec, 162 | no_seq_number: bool, 163 | xge: bool, 164 | doc: Option, 165 | }, 166 | EventCopy { 167 | name: String, 168 | number: i32, 169 | r#ref: String, 170 | }, 171 | EventStruct { 172 | typ: String, 173 | selectors: Vec, 174 | }, 175 | Request { 176 | name: String, 177 | opcode: u32, 178 | params: Vec, 179 | reply: Option, 180 | doc: Option, 181 | }, 182 | } 183 | -------------------------------------------------------------------------------- /build/output.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{self, File}; 2 | use std::io::{self, Write}; 3 | use std::path::{Path, PathBuf}; 4 | use std::process::{Child, Command, Stdio}; 5 | 6 | #[derive(Debug)] 7 | pub enum Output { 8 | Fmt(Child), 9 | Direct(File), 10 | } 11 | 12 | impl Output { 13 | pub fn new(rustfmt: &Option, out: &Path) -> io::Result { 14 | fs::create_dir_all(out.parent().unwrap())?; 15 | let output = File::create(&out)?; 16 | 17 | Ok(match rustfmt { 18 | Some(rustfmt) => Output::Fmt( 19 | Command::new(rustfmt) 20 | .arg("--emit=stdout") 21 | .arg("--edition=2018") 22 | .stdin(Stdio::piped()) 23 | .stdout(output) 24 | .spawn()?, 25 | ), 26 | 27 | None => Output::Direct(output), 28 | }) 29 | } 30 | } 31 | 32 | impl Write for Output { 33 | fn write(&mut self, buf: &[u8]) -> io::Result { 34 | match self { 35 | Output::Fmt(child) => child.stdin.as_ref().unwrap().write(buf), 36 | Output::Direct(file) => file.write(buf), 37 | } 38 | } 39 | 40 | fn flush(&mut self) -> io::Result<()> { 41 | match self { 42 | Output::Fmt(child) => child.stdin.as_ref().unwrap().flush(), 43 | Output::Direct(file) => file.flush(), 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/basic_window.rs: -------------------------------------------------------------------------------- 1 | use xcb::{x, Xid}; 2 | 3 | xcb::atoms_struct! { 4 | #[derive(Debug)] 5 | struct Atoms { 6 | wm_protocols => b"WM_PROTOCOLS", 7 | wm_del_window => b"WM_DELETE_WINDOW", 8 | wm_state => b"_NET_WM_STATE", 9 | wm_state_maxv => b"_NET_WM_STATE_MAXIMIZED_VERT", 10 | wm_state_maxh => b"_NET_WM_STATE_MAXIMIZED_HORZ", 11 | } 12 | } 13 | 14 | fn main() -> xcb::Result<()> { 15 | let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); 16 | let setup = conn.get_setup(); 17 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 18 | 19 | let window: x::Window = conn.generate_id(); 20 | 21 | println!("window: {}", window.resource_id()); 22 | println!("root: {}", screen.root().resource_id()); 23 | println!("root_visual: {}", screen.root_visual()); 24 | 25 | conn.send_request(&x::CreateWindow { 26 | depth: x::COPY_FROM_PARENT as u8, 27 | wid: window, 28 | parent: screen.root(), 29 | x: 0, 30 | y: 0, 31 | width: 150, 32 | height: 150, 33 | border_width: 10, 34 | class: x::WindowClass::InputOutput, 35 | visual: screen.root_visual(), 36 | value_list: &[ 37 | x::Cw::BackPixel(screen.white_pixel()), 38 | x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS), 39 | ], 40 | }); 41 | 42 | conn.send_request(&x::MapWindow { window }); 43 | 44 | let title = "Basic Window"; 45 | 46 | conn.send_request(&x::ChangeProperty { 47 | mode: x::PropMode::Replace, 48 | window, 49 | property: x::ATOM_WM_NAME, 50 | r#type: x::ATOM_STRING, 51 | data: title.as_bytes(), 52 | }); 53 | 54 | conn.flush()?; 55 | 56 | // retrieving title 57 | let cookie = conn.send_request(&x::GetProperty { 58 | delete: false, 59 | window, 60 | property: x::ATOM_WM_NAME, 61 | r#type: x::ATOM_STRING, 62 | long_offset: 0, 63 | long_length: 1024, 64 | }); 65 | let reply = conn.wait_for_reply(cookie)?; 66 | assert_eq!(reply.value::(), title.as_bytes()); 67 | 68 | // retrieving a few atoms 69 | let atoms = Atoms::intern_all(&conn)?; 70 | println!("atoms = {:#?}", atoms); 71 | 72 | // activate the sending of close event through `x::Event::ClientMessage` 73 | // either the request must be checked as follow, or conn.flush() must be called before entering the loop 74 | conn.send_and_check_request(&x::ChangeProperty { 75 | mode: x::PropMode::Replace, 76 | window, 77 | property: atoms.wm_protocols, 78 | r#type: x::ATOM_ATOM, 79 | data: &[atoms.wm_del_window], 80 | })?; 81 | 82 | let mut maximized = false; 83 | 84 | loop { 85 | let event = match conn.wait_for_event() { 86 | Err(xcb::Error::Connection(err)) => { 87 | panic!("unexpected I/O error: {}", err); 88 | } 89 | Err(xcb::Error::Protocol(err)) => { 90 | panic!("unexpected protocol error: {:#?}", err); 91 | } 92 | Ok(event) => event, 93 | }; 94 | 95 | println!("Received event {:#?}", event); 96 | match event { 97 | xcb::Event::X(x::Event::KeyPress(ev)) => { 98 | println!("Key '{}' pressed", ev.detail()); 99 | 100 | if ev.detail() == 0x3a { 101 | // M (on qwerty) 102 | 103 | // toggle maximized 104 | 105 | let data = x::ClientMessageData::Data32([ 106 | if maximized { 0 } else { 1 }, 107 | atoms.wm_state_maxv.resource_id(), 108 | atoms.wm_state_maxh.resource_id(), 109 | 0, 110 | 0, 111 | ]); 112 | 113 | let event = x::ClientMessageEvent::new(window, atoms.wm_state, data); 114 | 115 | conn.send_request(&x::SendEvent { 116 | propagate: false, 117 | destination: x::SendEventDest::Window(screen.root()), 118 | event_mask: x::EventMask::STRUCTURE_NOTIFY, 119 | event: &event, 120 | }); 121 | 122 | conn.flush()?; 123 | 124 | maximized = !maximized; 125 | } else if ev.detail() == 0x18 { 126 | // Q (on qwerty) 127 | break Ok(()); 128 | } 129 | } 130 | xcb::Event::X(x::Event::ClientMessage(ev)) => { 131 | if let x::ClientMessageData::Data32([atom, ..]) = ev.data() { 132 | if atom == atoms.wm_del_window.resource_id() { 133 | // window "x" button clicked by user, we gracefully exit 134 | break Ok(()); 135 | } 136 | } 137 | } 138 | _ => {} 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /examples/connect.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Ok((_, screen_num)) = xcb::Connection::connect(None) { 3 | println!("Connected to X on screen \"{}\"!", screen_num); 4 | } else { 5 | println!("Could not connect to X!"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/connect_str.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let dpy = ":0"; 3 | if let Ok((_, _)) = xcb::Connection::connect(Some(&dpy)) { 4 | println!("Connected to X on display \"{}\"!", dpy); 5 | } else { 6 | println!("Could not connect to X!"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/draw_root_window.rs: -------------------------------------------------------------------------------- 1 | use xcb::x; 2 | 3 | fn main() -> xcb::Result<()> { 4 | let rectangles: &[x::Rectangle] = &[x::Rectangle { 5 | x: 200, 6 | y: 200, 7 | width: 400, 8 | height: 400, 9 | }]; 10 | let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); 11 | let setup = conn.get_setup(); 12 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 13 | 14 | /* get the root window of the screen */ 15 | let window = screen.root(); 16 | 17 | /* Request modification of the root window attributes: background color and 18 | * event mask */ 19 | conn.send_request(&x::ChangeWindowAttributes { 20 | window, 21 | value_list: &[ 22 | x::Cw::BackPixel(screen.white_pixel()), 23 | // events that will be waited for 24 | x::Cw::EventMask(x::EventMask::EXPOSURE), 25 | ], 26 | }); 27 | 28 | let gc: x::Gcontext = conn.generate_id(); 29 | /* Request the creation of the graphical context */ 30 | conn.send_request(&x::CreateGc { 31 | cid: gc, 32 | drawable: x::Drawable::Window(window), 33 | value_list: &[ 34 | x::Gc::Foreground(screen.black_pixel()), 35 | x::Gc::Background(screen.white_pixel()), 36 | x::Gc::LineWidth(1), 37 | x::Gc::LineStyle(x::LineStyle::OnOffDash), 38 | x::Gc::SubwindowMode(x::SubwindowMode::IncludeInferiors), 39 | ], 40 | }); 41 | 42 | conn.send_request(&x::MapWindow { window }); 43 | 44 | /* Flush the requests */ 45 | conn.flush()?; 46 | loop { 47 | let event = match conn.wait_for_event() { 48 | Err(xcb::Error::Connection(xcb::ConnError::Connection)) => { 49 | // graceful shutdown, likely "x" close button clicked in title bar 50 | break Ok(()); 51 | } 52 | Err(err) => { 53 | panic!("unexpected error: {:#?}", err); 54 | } 55 | Ok(event) => event, 56 | }; 57 | match event { 58 | xcb::Event::X(x::Event::Expose(_ev)) => { 59 | let drawable = x::Drawable::Window(window); 60 | 61 | /* Draw a rectangle on screen using the graphical context */ 62 | conn.send_request(&x::PolyRectangle { 63 | drawable, 64 | gc, 65 | rectangles, 66 | }); 67 | 68 | /* We flush the request */ 69 | conn.flush()?; 70 | } 71 | _ => {} 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /examples/drawing.rs: -------------------------------------------------------------------------------- 1 | use xcb::x; 2 | 3 | fn main() -> xcb::Result<()> { 4 | let points: &[x::Point] = &[ 5 | x::Point { x: 10, y: 10 }, 6 | x::Point { x: 10, y: 20 }, 7 | x::Point { x: 20, y: 10 }, 8 | x::Point { x: 20, y: 20 }, 9 | ]; 10 | let polyline: &[x::Point] = &[ 11 | x::Point { x: 50, y: 10 }, 12 | x::Point { x: 5, y: 20 }, 13 | x::Point { x: 25, y: -20 }, /* rest of points are relative */ 14 | x::Point { x: 10, y: 10 }, 15 | ]; 16 | let segments: &[x::Segment] = &[ 17 | x::Segment { 18 | x1: 100, 19 | y1: 10, 20 | x2: 140, 21 | y2: 30, 22 | }, 23 | x::Segment { 24 | x1: 110, 25 | y1: 25, 26 | x2: 130, 27 | y2: 60, 28 | }, 29 | ]; 30 | let rectangles: &[x::Rectangle] = &[ 31 | x::Rectangle { 32 | x: 10, 33 | y: 50, 34 | width: 40, 35 | height: 20, 36 | }, 37 | x::Rectangle { 38 | x: 80, 39 | y: 50, 40 | width: 10, 41 | height: 40, 42 | }, 43 | ]; 44 | let arcs: &[x::Arc] = &[ 45 | x::Arc { 46 | x: 10, 47 | y: 100, 48 | width: 60, 49 | height: 40, 50 | angle1: 0, 51 | angle2: 90 << 6, 52 | }, 53 | x::Arc { 54 | x: 90, 55 | y: 100, 56 | width: 55, 57 | height: 40, 58 | angle1: 0, 59 | angle2: 270 << 6, 60 | }, 61 | ]; 62 | 63 | let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); 64 | let setup = conn.get_setup(); 65 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 66 | 67 | let gc: x::Gcontext = conn.generate_id(); 68 | 69 | let window: x::Window = conn.generate_id(); 70 | conn.send_request(&x::CreateWindow { 71 | depth: x::COPY_FROM_PARENT as u8, 72 | wid: window, 73 | parent: screen.root(), 74 | x: 0, 75 | y: 0, 76 | width: 150, 77 | height: 150, 78 | border_width: 10, 79 | class: x::WindowClass::InputOutput, 80 | visual: screen.root_visual(), 81 | value_list: &[ 82 | x::Cw::BackPixel(screen.white_pixel()), 83 | x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS), 84 | ], 85 | }); 86 | 87 | conn.send_request(&x::MapWindow { window }); 88 | 89 | conn.send_request(&x::CreateGc { 90 | cid: gc, 91 | drawable: x::Drawable::Window(window), 92 | value_list: &[ 93 | x::Gc::Foreground(screen.black_pixel()), 94 | x::Gc::GraphicsExposures(false), 95 | ], 96 | }); 97 | 98 | conn.flush()?; 99 | 100 | loop { 101 | let event = match conn.wait_for_event() { 102 | Err(xcb::Error::Connection(xcb::ConnError::Connection)) => { 103 | // graceful shutdown, likely "x" close button clicked in title bar 104 | break Ok(()); 105 | } 106 | Err(err) => { 107 | panic!("unexpected error: {:#?}", err); 108 | } 109 | Ok(event) => event, 110 | }; 111 | match event { 112 | xcb::Event::X(x::Event::Expose(_ev)) => { 113 | let drawable = x::Drawable::Window(window); 114 | 115 | /* We draw the points */ 116 | conn.send_request(&x::PolyPoint { 117 | coordinate_mode: x::CoordMode::Origin, 118 | drawable, 119 | gc, 120 | points, 121 | }); 122 | 123 | /* We draw the polygonal line */ 124 | conn.send_request(&x::PolyLine { 125 | coordinate_mode: x::CoordMode::Previous, 126 | drawable, 127 | gc, 128 | points: &polyline, 129 | }); 130 | 131 | /* We draw the segements */ 132 | conn.send_request(&x::PolySegment { 133 | drawable, 134 | gc, 135 | segments, 136 | }); 137 | 138 | /* We draw the rectangles */ 139 | conn.send_request(&x::PolyRectangle { 140 | drawable, 141 | gc, 142 | rectangles, 143 | }); 144 | 145 | /* We draw the arcs */ 146 | conn.send_request(&x::PolyArc { drawable, gc, arcs }); 147 | 148 | /* We flush the request */ 149 | conn.flush()?; 150 | } 151 | 152 | xcb::Event::X(x::Event::KeyPress(key_press)) => { 153 | println!("Key '{}' pressed", key_press.detail()); 154 | if key_press.detail() == 0x18 { 155 | // Q (on qwerty) 156 | break Ok(()); 157 | } 158 | } 159 | _ => {} 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /examples/get_all_windows.rs: -------------------------------------------------------------------------------- 1 | use std::str; 2 | use xcb::x; 3 | 4 | fn main() -> xcb::Result<()> { 5 | let (conn, _) = xcb::Connection::connect(None).unwrap(); 6 | let setup = conn.get_setup(); 7 | 8 | let wm_client_list = conn.send_request(&x::InternAtom { 9 | only_if_exists: true, 10 | name: "_NET_CLIENT_LIST".as_bytes(), 11 | }); 12 | let wm_client_list = conn.wait_for_reply(wm_client_list)?.atom(); 13 | assert!(wm_client_list != x::ATOM_NONE, "EWMH not supported"); 14 | 15 | for screen in setup.roots() { 16 | let window = screen.root(); 17 | 18 | let pointer = conn.send_request(&x::QueryPointer { window }); 19 | let pointer = conn.wait_for_reply(pointer)?; 20 | 21 | if pointer.same_screen() { 22 | let list = conn.send_request(&x::GetProperty { 23 | delete: false, 24 | window, 25 | property: wm_client_list, 26 | r#type: x::ATOM_NONE, 27 | long_offset: 0, 28 | long_length: 100, 29 | }); 30 | let list = conn.wait_for_reply(list)?; 31 | 32 | for client in list.value::() { 33 | let cookie = conn.send_request(&x::GetProperty { 34 | delete: false, 35 | window: *client, 36 | property: x::ATOM_WM_NAME, 37 | r#type: x::ATOM_STRING, 38 | long_offset: 0, 39 | long_length: 1024, 40 | }); 41 | let reply = conn.wait_for_reply(cookie)?; 42 | let title = reply.value(); 43 | let title = str::from_utf8(title).expect("invalid UTF-8"); 44 | println!("{}", title); 45 | } 46 | } 47 | } 48 | 49 | Ok(()) 50 | } 51 | -------------------------------------------------------------------------------- /examples/get_keyboard_names.rs: -------------------------------------------------------------------------------- 1 | use xcb::{self, xinput, xkb}; 2 | use xcb::{Connection, Extension}; 3 | 4 | fn main() -> xcb::Result<()> { 5 | let (conn, _screen_num) = Connection::connect_with_xlib_display_and_extensions( 6 | &[Extension::Input, Extension::Xkb], 7 | &[], 8 | )?; 9 | 10 | let cookie = conn.send_request(&xinput::ListInputDevices {}); 11 | let devices = conn.wait_for_reply(cookie)?; 12 | devices 13 | .devices() 14 | .iter() 15 | .filter(|device| { 16 | device.device_use() == xinput::DeviceUse::IsXExtensionKeyboard 17 | || device.device_use() == xinput::DeviceUse::IsXKeyboard 18 | }) 19 | .try_for_each::<_, xcb::Result<()>>(|device| { 20 | let device_spec = device.device_id() as xkb::DeviceSpec; 21 | let cookie = conn.send_request(&xcb::xkb::GetNames { 22 | device_spec, 23 | which: xkb::NameDetail::SYMBOLS, 24 | }); 25 | let components = conn.wait_for_reply(cookie)?; 26 | println!( 27 | "Get components for device {} got result {:?}", 28 | device_spec, 29 | components.value_list() 30 | ); 31 | Ok(()) 32 | })?; 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /examples/present_special_event.rs: -------------------------------------------------------------------------------- 1 | use xcb::{present, x, Xid}; 2 | 3 | use std::{ 4 | sync::{mpsc, Arc}, 5 | thread, 6 | time::Duration, 7 | }; 8 | 9 | xcb::atoms_struct! { 10 | #[derive(Debug)] 11 | struct Atoms { 12 | wm_protocols => b"WM_PROTOCOLS", 13 | wm_del_window => b"WM_DELETE_WINDOW", 14 | } 15 | } 16 | 17 | struct Example { 18 | conn: xcb::Connection, 19 | window: x::Window, 20 | atoms: Atoms, 21 | } 22 | 23 | impl Example { 24 | fn build() -> xcb::Result { 25 | let (conn, screen_num) = 26 | xcb::Connection::connect_with_extensions(None, &[xcb::Extension::Present], &[])?; 27 | let setup = conn.get_setup(); 28 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 29 | 30 | let window: x::Window = conn.generate_id(); 31 | 32 | conn.send_request(&x::CreateWindow { 33 | depth: x::COPY_FROM_PARENT as u8, 34 | wid: window, 35 | parent: screen.root(), 36 | x: 0, 37 | y: 0, 38 | width: 800, 39 | height: 600, 40 | border_width: 10, 41 | class: x::WindowClass::InputOutput, 42 | visual: screen.root_visual(), 43 | value_list: &[ 44 | x::Cw::BackPixel(screen.white_pixel()), 45 | x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS), 46 | ], 47 | }); 48 | 49 | conn.send_and_check_request(&x::MapWindow { window })?; 50 | 51 | // retrieving a few atoms 52 | let atoms = Atoms::intern_all(&conn)?; 53 | 54 | // activate the sending of close event through `x::Event::ClientMessage` 55 | // either the request must be checked as follow, or conn.flush() must be called before entering the loop 56 | conn.send_and_check_request(&x::ChangeProperty { 57 | mode: x::PropMode::Replace, 58 | window, 59 | property: atoms.wm_protocols, 60 | r#type: x::ATOM_ATOM, 61 | data: &[atoms.wm_del_window], 62 | })?; 63 | 64 | conn.flush()?; 65 | 66 | Ok(Self { 67 | conn, 68 | window, 69 | atoms, 70 | }) 71 | } 72 | 73 | fn main_event_loop(&self) -> xcb::Result<()> { 74 | loop { 75 | let ev = self.conn.wait_for_event()?; 76 | println!("Received regular event {:#?}", ev); 77 | match ev { 78 | xcb::Event::X(x::Event::KeyPress(ev)) => { 79 | if ev.detail() == 0x18 { 80 | // Q (on qwerty) 81 | break Ok(()); 82 | } 83 | } 84 | xcb::Event::X(x::Event::ClientMessage(ev)) => { 85 | if let x::ClientMessageData::Data32([atom, ..]) = ev.data() { 86 | if atom == self.atoms.wm_del_window.resource_id() { 87 | // window "x" button clicked by user, we gracefully exit 88 | break Ok(()); 89 | } 90 | } 91 | } 92 | _ => {} 93 | } 94 | } 95 | } 96 | 97 | fn special_event_loop(&self, rx: mpsc::Receiver) -> xcb::Result<()> { 98 | let eid = self.conn.generate_id(); 99 | 100 | self.conn.send_request(&present::SelectInput { 101 | eid, 102 | window: self.window, 103 | event_mask: present::EventMask::CONFIGURE_NOTIFY 104 | | present::EventMask::COMPLETE_NOTIFY 105 | | present::EventMask::IDLE_NOTIFY, 106 | }); 107 | 108 | let special_event = self 109 | .conn 110 | .register_for_special_event(xcb::Extension::Present, eid); 111 | 112 | self.conn.flush()?; 113 | 114 | loop { 115 | let ev = self.conn.poll_for_special_event2(&special_event)?; 116 | if let Some(ev) = ev { 117 | println!("Received special event {:#?}", ev); 118 | } 119 | 120 | if let Ok(msg) = rx.recv_timeout(Duration::from_millis(100)) { 121 | match msg { 122 | Msg::Quit => break, 123 | } 124 | } 125 | } 126 | 127 | self.conn.unregister_for_special_event(special_event); 128 | 129 | Ok(()) 130 | } 131 | } 132 | 133 | enum Msg { 134 | Quit, 135 | } 136 | 137 | fn main() -> xcb::Result<()> { 138 | let example = Example::build()?; 139 | let example = Arc::new(example); 140 | 141 | let (tx, rx) = mpsc::channel(); 142 | 143 | let special_event_thread = { 144 | let example = example.clone(); 145 | thread::spawn(move || example.special_event_loop(rx)) 146 | }; 147 | example.main_event_loop()?; 148 | 149 | tx.send(Msg::Quit).unwrap(); 150 | special_event_thread.join().unwrap()?; 151 | 152 | Ok(()) 153 | } 154 | -------------------------------------------------------------------------------- /examples/print_setup.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let (conn, _) = xcb::Connection::connect(None).unwrap(); 3 | let setup = conn.get_setup(); 4 | println!("{:#?}", setup); 5 | } 6 | -------------------------------------------------------------------------------- /examples/randr_crtc_info.rs: -------------------------------------------------------------------------------- 1 | use xcb::{randr, x}; 2 | 3 | fn main() -> xcb::Result<()> { 4 | let (conn, screen_num) = xcb::Connection::connect(None)?; 5 | let setup = conn.get_setup(); 6 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 7 | let window_dummy: x::Window = conn.generate_id(); 8 | 9 | conn.send_request(&x::CreateWindow { 10 | depth: 0, 11 | wid: window_dummy, 12 | parent: screen.root(), 13 | x: 0, 14 | y: 0, 15 | width: 1, 16 | height: 1, 17 | border_width: 0, 18 | class: x::WindowClass::InputOutput, 19 | visual: screen.root_visual(), 20 | value_list: &[], 21 | }); 22 | 23 | conn.flush()?; 24 | 25 | let screen_res = conn.wait_for_reply(conn.send_request(&randr::GetScreenResources { 26 | window: window_dummy, 27 | }))?; 28 | 29 | let crtc_cookies = screen_res 30 | .crtcs() 31 | .iter() 32 | .map(|crtc| { 33 | conn.send_request(&randr::GetCrtcInfo { 34 | crtc: *crtc, 35 | config_timestamp: 0, 36 | }) 37 | }) 38 | .collect::>(); 39 | 40 | for (i, cookie) in crtc_cookies.into_iter().enumerate() { 41 | let reply = conn.wait_for_reply(cookie)?; 42 | if i != 0 { 43 | println!(""); 44 | } 45 | println!("CRTC[{}] INFO:", i); 46 | println!(" x-off\t: {}", reply.x()); 47 | println!(" y-off\t: {}", reply.y()); 48 | println!(" width\t: {}", reply.width()); 49 | println!(" height\t: {}", reply.height()); 50 | } 51 | 52 | Ok(()) 53 | } 54 | -------------------------------------------------------------------------------- /examples/randr_crtc_listen.rs: -------------------------------------------------------------------------------- 1 | use xcb::randr; 2 | 3 | fn main() -> xcb::Result<()> { 4 | let (conn, screen_num) = 5 | xcb::Connection::connect_with_extensions(None, &[xcb::Extension::RandR], &[]).unwrap(); 6 | let screen = conn.get_setup().roots().nth(screen_num as usize).unwrap(); 7 | 8 | conn.check_request(conn.send_request_checked(&randr::SelectInput { 9 | window: screen.root(), 10 | enable: randr::NotifyMask::CRTC_CHANGE, 11 | }))?; 12 | 13 | loop { 14 | conn.flush()?; 15 | 16 | let event = match conn.wait_for_event() { 17 | Err(xcb::Error::Connection(err)) => { 18 | panic!("unexpected I/O error: {}", err); 19 | } 20 | Err(xcb::Error::Protocol(err)) => { 21 | panic!("unexpected protocol error: {:#?}", err); 22 | } 23 | Ok(event) => event, 24 | }; 25 | 26 | match event { 27 | xcb::Event::RandR(randr::Event::Notify(ev)) => match ev.u() { 28 | randr::NotifyData::Cc(cc) => { 29 | println!( 30 | "received CRTC_CHANGE event:\n\ 31 | \ttimestamp: {}, window: {:?}, crtc: {:?}, mode: {:?}, rotation: {:?}\n\ 32 | \tx: {}, y: {}, width: {}, height: {}", 33 | cc.timestamp(), 34 | cc.window(), 35 | cc.crtc(), 36 | cc.mode(), 37 | cc.rotation(), 38 | cc.x(), 39 | cc.y(), 40 | cc.width(), 41 | cc.height() 42 | ); 43 | } 44 | _ => {} 45 | }, 46 | _ => {} 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/randr_screen_info.rs: -------------------------------------------------------------------------------- 1 | use xcb::{randr, x}; 2 | 3 | fn main() -> xcb::Result<()> { 4 | let (conn, screen_num) = xcb::Connection::connect(None)?; 5 | let setup = conn.get_setup(); 6 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 7 | let window_dummy: x::Window = conn.generate_id(); 8 | 9 | conn.send_request(&x::CreateWindow { 10 | depth: 0, 11 | wid: window_dummy, 12 | parent: screen.root(), 13 | x: 0, 14 | y: 0, 15 | width: 1, 16 | height: 1, 17 | border_width: 0, 18 | class: x::WindowClass::InputOutput, 19 | visual: screen.root_visual(), 20 | value_list: &[], 21 | }); 22 | 23 | conn.flush()?; 24 | 25 | let reply = conn.wait_for_reply(conn.send_request(&randr::GetScreenInfo { 26 | window: window_dummy, 27 | }))?; 28 | 29 | for (i, size) in reply.sizes().iter().enumerate() { 30 | if i != 0 { 31 | println!(""); 32 | } 33 | println!("size of screen {}:", i + 1); 34 | println!( 35 | " {} x {} ({}mm x {}mm)", 36 | size.width, size.height, size.mwidth, size.mheight, 37 | ); 38 | } 39 | 40 | Ok(()) 41 | } 42 | -------------------------------------------------------------------------------- /examples/randr_screen_modes.rs: -------------------------------------------------------------------------------- 1 | use xcb::{randr, x}; 2 | 3 | // per https://gitlab.freedesktop.org/xorg/app/xrandr/-/blob/master/xrandr.c#L576 4 | fn mode_refresh(mode_info: &randr::ModeInfo) -> f64 { 5 | let vtotal = { 6 | let mut val = mode_info.vtotal; 7 | if mode_info.mode_flags.contains(randr::ModeFlag::DOUBLE_SCAN) { 8 | val *= 2; 9 | } 10 | if mode_info.mode_flags.contains(randr::ModeFlag::INTERLACE) { 11 | val /= 2; 12 | } 13 | val 14 | }; 15 | 16 | if vtotal != 0 && mode_info.htotal != 0 { 17 | (mode_info.dot_clock as f64) / (vtotal as f64 * mode_info.htotal as f64) 18 | } else { 19 | 0.0 20 | } 21 | } 22 | 23 | fn main() -> xcb::Result<()> { 24 | let (conn, screen_num) = xcb::Connection::connect(None)?; 25 | let setup = conn.get_setup(); 26 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 27 | let window_dummy: x::Window = conn.generate_id(); 28 | 29 | conn.send_request(&x::CreateWindow { 30 | depth: 0, 31 | wid: window_dummy, 32 | parent: screen.root(), 33 | x: 0, 34 | y: 0, 35 | width: 1, 36 | height: 1, 37 | border_width: 0, 38 | class: x::WindowClass::InputOutput, 39 | visual: screen.root_visual(), 40 | value_list: &[], 41 | }); 42 | 43 | conn.flush()?; 44 | 45 | let reply = conn.wait_for_reply(conn.send_request(&randr::GetScreenResources { 46 | window: window_dummy, 47 | }))?; 48 | 49 | for (i, mode) in reply.modes().iter().enumerate() { 50 | println!("mode {}", i + 1); 51 | println!("\tresolution = {}x{}", mode.width, mode.height); 52 | println!("\trefresh rate = {:.1}Hz", mode_refresh(mode)); 53 | } 54 | 55 | Ok(()) 56 | } 57 | -------------------------------------------------------------------------------- /examples/screen_info.rs: -------------------------------------------------------------------------------- 1 | fn main() -> xcb::Result<()> { 2 | let (conn, screen_num) = xcb::Connection::connect(None)?; 3 | 4 | let setup = conn.get_setup(); 5 | 6 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 7 | 8 | println!(""); 9 | println!("Informations of screen {}:", screen_num); 10 | println!(" width..........: {}", screen.width_in_pixels()); 11 | println!(" height.........: {}", screen.height_in_pixels()); 12 | println!(" white pixel....: {:x}", screen.white_pixel()); 13 | println!(" black pixel....: {:x}", screen.black_pixel()); 14 | 15 | Ok(()) 16 | } 17 | -------------------------------------------------------------------------------- /examples/screenshot.rs: -------------------------------------------------------------------------------- 1 | extern crate xcb; 2 | 3 | use std::{fs::File, io::BufWriter}; 4 | use xcb::x; 5 | 6 | fn main() { 7 | let (conn, screen_num) = xcb::Connection::connect(None).unwrap(); 8 | let setup = conn.get_setup(); 9 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 10 | 11 | let width = screen.width_in_pixels(); 12 | let height = screen.height_in_pixels(); 13 | 14 | let cookie = conn.send_request(&x::GetImage { 15 | format: x::ImageFormat::ZPixmap, 16 | drawable: x::Drawable::Window(screen.root()), 17 | x: 0, 18 | y: 0, 19 | width, 20 | height, 21 | plane_mask: u32::MAX, 22 | }); 23 | 24 | let file = File::create("screenshot.png").unwrap(); 25 | let writer = BufWriter::new(file); 26 | let mut encoder = png::Encoder::new(writer, width as _, height as _); 27 | encoder.set_color(png::ColorType::Rgb); 28 | encoder.set_depth(png::BitDepth::Eight); 29 | let mut writer = encoder 30 | .write_header() 31 | .expect("Failed to write image header"); 32 | 33 | let reply = conn.wait_for_reply(cookie).unwrap(); 34 | 35 | let src = reply.data(); 36 | let mut data = vec![0; width as usize * height as usize * 3]; 37 | for (src, dest) in src.chunks(4).zip(data.chunks_mut(3)) { 38 | // Captured image stores orders pixels as BGR, so we need to 39 | // reorder them. 40 | dest[0] = src[2]; 41 | dest[1] = src[1]; 42 | dest[2] = src[0]; 43 | } 44 | writer 45 | .write_image_data(&data) 46 | .expect("Failed to write image data"); 47 | } 48 | -------------------------------------------------------------------------------- /examples/threaded_window.rs: -------------------------------------------------------------------------------- 1 | extern crate xcb; 2 | 3 | use std::iter::Iterator; 4 | use std::sync::Arc; 5 | use std::{thread, time}; 6 | 7 | use xcb::x; 8 | 9 | fn main() -> xcb::Result<()> { 10 | let (conn, screen_num) = { 11 | let (conn, screen_num) = xcb::Connection::connect(None)?; 12 | (Arc::new(conn), screen_num) 13 | }; 14 | let setup = conn.get_setup(); 15 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 16 | 17 | let window = conn.generate_id(); 18 | 19 | let values = [ 20 | x::Cw::BackPixel(screen.white_pixel()), 21 | x::Cw::EventMask( 22 | x::EventMask::EXPOSURE 23 | | x::EventMask::KEY_PRESS 24 | | x::EventMask::STRUCTURE_NOTIFY 25 | | x::EventMask::PROPERTY_CHANGE, 26 | ), 27 | ]; 28 | 29 | let create_window_cookie = conn.send_request_checked(&x::CreateWindow { 30 | depth: x::COPY_FROM_PARENT as u8, 31 | wid: window, 32 | parent: screen.root(), 33 | x: 0, 34 | y: 0, 35 | width: 320, 36 | height: 240, 37 | border_width: 10, 38 | class: x::WindowClass::InputOutput, 39 | visual: screen.root_visual(), 40 | value_list: &values, 41 | }); 42 | conn.check_request(create_window_cookie)?; 43 | 44 | let map_window_cookie = conn.send_request_checked(&x::MapWindow { window }); 45 | conn.check_request(map_window_cookie)?; 46 | 47 | { 48 | let conn = conn.clone(); 49 | thread::spawn(move || { 50 | let mut blink = false; 51 | loop { 52 | let title = if blink { 53 | "Basic Threaded Window ;-)" 54 | } else { 55 | "Basic Threaded Window :-)" 56 | }; 57 | 58 | let cookie = conn.send_request_checked(&x::ChangeProperty { 59 | mode: x::PropMode::Replace, 60 | window, 61 | property: x::ATOM_WM_NAME, 62 | r#type: x::ATOM_STRING, 63 | data: title.as_bytes(), 64 | }); 65 | 66 | if conn.has_error().is_err() || conn.check_request(cookie).is_err() { 67 | break; 68 | } 69 | 70 | blink = !blink; 71 | thread::sleep(time::Duration::from_millis(500)); 72 | } 73 | }); 74 | } 75 | 76 | loop { 77 | let event = conn.wait_for_event(); 78 | match event { 79 | Ok(xcb::Event::X(x::Event::PropertyNotify(ev))) => { 80 | if ev.atom() == x::ATOM_WM_NAME { 81 | // retrieving title 82 | let cookie = conn.send_request(&x::GetProperty { 83 | delete: false, 84 | window, 85 | property: x::ATOM_WM_NAME, 86 | r#type: x::ATOM_STRING, 87 | long_offset: 0, 88 | long_length: 1024, 89 | }); 90 | let title = conn.wait_for_reply(cookie)?; 91 | 92 | println!( 93 | "title changed to \"{}\"", 94 | std::str::from_utf8(title.value()).unwrap() 95 | ); 96 | } 97 | } 98 | Ok(xcb::Event::X(x::Event::KeyPress(ev))) => { 99 | println!("Key '{}' pressed", ev.detail()); 100 | 101 | if ev.detail() == 0x18 { 102 | // Q (on qwerty) 103 | break; 104 | } 105 | } 106 | Ok(_) => { 107 | continue; 108 | } 109 | Err(_) => { 110 | break; 111 | } 112 | } 113 | } 114 | 115 | Ok(()) 116 | } 117 | -------------------------------------------------------------------------------- /examples/xinput_stylus_events.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use xcb::{x, xinput}; 3 | 4 | #[derive(Debug)] 5 | struct StylusDevice { 6 | dev: xinput::Device, 7 | name: String, 8 | } 9 | 10 | fn main() -> xcb::Result<()> { 11 | // if none, will list devices and exit 12 | let find_device = { 13 | let mut args = env::args(); 14 | if args.len() <= 1 { 15 | eprintln!(r#"warning: no argument, will default to find a "stylus" device"#); 16 | Some("stylus".to_string()) 17 | } else { 18 | let arg = args.nth(1).unwrap(); 19 | if arg == "--list" || arg == "-l" { 20 | None 21 | } else { 22 | Some(arg) 23 | } 24 | } 25 | }; 26 | 27 | let (conn, screen_num) = 28 | xcb::Connection::connect_with_extensions(None, &[xcb::Extension::Input], &[]).unwrap(); 29 | 30 | // Check if XI2 is supported 31 | conn.wait_for_reply(conn.send_request(&xinput::XiQueryVersion { 32 | major_version: 2, 33 | minor_version: 0, 34 | })) 35 | .expect("XI2 not supported"); 36 | 37 | let cookie = conn.send_request(&xinput::ListInputDevices {}); 38 | let device_list = conn.wait_for_reply(cookie)?; 39 | 40 | println!("{:#?}", device_list); 41 | 42 | if find_device.is_none() { 43 | println!("{:#?}", device_list); 44 | return Ok(()); 45 | } 46 | 47 | let find_device = find_device.unwrap(); 48 | 49 | let device = { 50 | let mut device: Option = None; 51 | for (i, dev) in device_list.devices().iter().enumerate() { 52 | let name = device_list.names().nth(i).unwrap().name().to_utf8(); 53 | if name.contains(&find_device) { 54 | device = Some(StylusDevice { 55 | dev: xinput::Device::from_id(dev.device_id() as _), 56 | name: name.to_string(), 57 | }); 58 | break; 59 | } 60 | } 61 | device.expect("could not find a stylus device") 62 | }; 63 | 64 | println!("found device \"{}\" ({:?})", device.name, device.dev); 65 | 66 | let cookie = conn.send_request(&xinput::OpenDevice { 67 | device_id: device.dev.id() as u8, 68 | }); 69 | conn.wait_for_reply(cookie)?; 70 | 71 | let setup = conn.get_setup(); 72 | let screen = setup.roots().nth(screen_num as usize).unwrap(); 73 | let window: x::Window = conn.generate_id(); 74 | 75 | conn.send_request(&x::CreateWindow { 76 | depth: x::COPY_FROM_PARENT as u8, 77 | wid: window, 78 | parent: screen.root(), 79 | x: 0, 80 | y: 0, 81 | width: 500, 82 | height: 500, 83 | border_width: 10, 84 | class: x::WindowClass::InputOutput, 85 | visual: screen.root_visual(), 86 | value_list: &[ 87 | x::Cw::BackPixel(screen.white_pixel()), 88 | x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS), 89 | ], 90 | }); 91 | 92 | conn.send_request(&x::MapWindow { window }); 93 | 94 | let title = "Stylus Window"; 95 | 96 | conn.send_request(&x::ChangeProperty { 97 | mode: x::PropMode::Replace, 98 | window, 99 | property: x::ATOM_WM_NAME, 100 | r#type: x::ATOM_STRING, 101 | data: title.as_bytes(), 102 | }); 103 | 104 | let info = 105 | conn.wait_for_reply(conn.send_request(&xinput::XiQueryDevice { device: device.dev })); 106 | 107 | println!("{:#?}", info); 108 | 109 | conn.send_request(&xinput::XiSelectEvents { 110 | window, 111 | masks: &[xinput::EventMaskBuf::new( 112 | device.dev, 113 | &[xinput::XiEventMask::MOTION 114 | | xinput::XiEventMask::BUTTON_PRESS 115 | | xinput::XiEventMask::BUTTON_RELEASE], 116 | )], 117 | }); 118 | 119 | conn.flush()?; 120 | 121 | loop { 122 | let ev = conn.wait_for_event()?; 123 | match ev { 124 | xcb::Event::Input(xinput::Event::Motion(ev)) => { 125 | // TODO, query valuator infos to ensure on which axis is the pressure 126 | // This works for me with a Wacom One, but could be different with another device/config 127 | println!("received stylus motion event"); 128 | println!(" event_x = {}", fp1616_to_f64(ev.event_x())); 129 | println!(" event_y = {}", fp1616_to_f64(ev.event_y())); 130 | println!(" pressure = {}", ev.axisvalues()[2].integral); 131 | println!(); 132 | } 133 | xcb::Event::Input(xinput::Event::ButtonPress(_ev)) => { 134 | println!("received stylus press"); 135 | } 136 | xcb::Event::Input(xinput::Event::ButtonRelease(_ev)) => { 137 | println!("received stylus release"); 138 | } 139 | _ => {} 140 | } 141 | } 142 | 143 | //Ok(()) 144 | } 145 | 146 | fn fp1616_to_f64(val: xinput::Fp1616) -> f64 { 147 | (val as f64) / (u16::MAX as f64) 148 | } 149 | -------------------------------------------------------------------------------- /examples/xkb_init.rs: -------------------------------------------------------------------------------- 1 | use xcb::xkb; 2 | 3 | fn main() -> xcb::Result<()> { 4 | let (conn, _) = xcb::Connection::connect_with_extensions(None, &[xcb::Extension::Xkb], &[])?; 5 | 6 | // we need at least xkb-1.0 to be available on client 7 | // machine 8 | { 9 | let xkb_ver = conn.wait_for_reply(conn.send_request(&xkb::UseExtension { 10 | wanted_major: 1, 11 | wanted_minor: 0, 12 | }))?; 13 | 14 | assert!(xkb_ver.supported(), "xkb-1.0 support is required"); 15 | } 16 | 17 | // we now select what events we want to receive 18 | // such as map change, keyboard hotplug ... 19 | // note that key strokes are given directly by 20 | // the x::Event::KeyPress, not by xkb 21 | { 22 | let events = xkb::EventType::NEW_KEYBOARD_NOTIFY 23 | | xkb::EventType::MAP_NOTIFY 24 | | xkb::EventType::STATE_NOTIFY; 25 | 26 | let map_parts = xkb::MapPart::KEY_TYPES 27 | | xkb::MapPart::KEY_SYMS 28 | | xkb::MapPart::MODIFIER_MAP 29 | | xkb::MapPart::EXPLICIT_COMPONENTS 30 | | xkb::MapPart::KEY_ACTIONS 31 | | xkb::MapPart::KEY_BEHAVIORS 32 | | xkb::MapPart::VIRTUAL_MODS 33 | | xkb::MapPart::VIRTUAL_MOD_MAP; 34 | 35 | let cookie = conn.send_request_checked(&xkb::SelectEvents { 36 | device_spec: xkb::Id::UseCoreKbd as xkb::DeviceSpec, 37 | affect_which: events, 38 | clear: xkb::EventType::empty(), 39 | select_all: events, 40 | affect_map: map_parts, 41 | map: map_parts, 42 | details: &[], 43 | }); 44 | 45 | conn.check_request(cookie)?; 46 | } 47 | 48 | // proceed with create_window and event loop... 49 | 50 | Ok(()) 51 | } 52 | -------------------------------------------------------------------------------- /gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This is a script that runs the code generation and export a copy of it under gen/$1. 4 | # This is NOT the main code generation script, but a tool to help looking at the generated code 5 | # (which is otherwise lost somewhere under target/) and performing diffs with previous versions. 6 | 7 | if [ -z "$1" ] 8 | then 9 | echo -e "Error: a subfolder in gen/ must be supplied as argument" 10 | exit 1 11 | fi 12 | 13 | # trigger rebuild 14 | touch build/cg/mod.rs 15 | # rebuild and export code 16 | RXCB_EXPORT=gen/$1 RUST_BACKTRACE=1 cargo build --all-features 17 | # format exported code 18 | for file in gen/$1/*.rs 19 | do 20 | rustfmt $file --edition=2018 21 | done 22 | -------------------------------------------------------------------------------- /gen/diff.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if [ -z "$1" ] 4 | then 5 | echo -e "Error: a module name must be supplied as argument" 6 | exit 1 7 | fi 8 | 9 | code --diff gen/previous/$1.rs gen/current/$1.rs 10 | -------------------------------------------------------------------------------- /src/ffi/xlib_xcb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 James Miller 3 | * Copyright (c) 2016 4 | * Remi Thebault 5 | * Thomas Bracht Laumann Jespersen 6 | * 7 | * Permission is hereby granted, free of charge, to any 8 | * person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the 10 | * Software without restriction, including without 11 | * limitation the rights to use, copy, modify, merge, 12 | * publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software 14 | * is furnished to do so, subject to the following 15 | * conditions: 16 | * 17 | * The above copyright notice and this permission notice 18 | * shall be included in all copies or substantial portions 19 | * of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 22 | * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 23 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 24 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 25 | * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 26 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 28 | * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | * DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | #![allow(non_upper_case_globals)] 33 | #![allow(non_snake_case)] 34 | 35 | use crate::ffi::xcb_connection_t; 36 | use libc::c_uint; 37 | 38 | use x11::xlib; 39 | 40 | /// Type for [XSetEventQueueOwner] owner parameter 41 | /// 42 | /// This item is behind the `xlib_xcb` cargo feature. 43 | pub type XEventQueueOwner = c_uint; 44 | 45 | /// Xlib owns the event queue 46 | /// 47 | /// This item is behind the `xlib_xcb` cargo feature. 48 | pub const XlibOwnsEventQueue: XEventQueueOwner = 0; 49 | 50 | /// XCB owns the event queue 51 | /// 52 | /// This item is behind the `xlib_xcb` cargo feature. 53 | pub const XCBOwnsEventQueue: XEventQueueOwner = 1; 54 | 55 | #[link(name = "X11-xcb")] 56 | extern "C" { 57 | /// Get an XCB connection from the `xlib::Display`. 58 | /// 59 | /// This function is behind the `xlib_xcb` cargo feature. 60 | pub fn XGetXCBConnection(dpy: *mut xlib::Display) -> *mut xcb_connection_t; 61 | /// Set the owner of the X client event queue. 62 | /// 63 | /// This function is behind the `xlib_xcb` cargo feature. 64 | pub fn XSetEventQueueOwner(dpy: *mut xlib::Display, owner: XEventQueueOwner); 65 | } 66 | -------------------------------------------------------------------------------- /xml/bigreq.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /xml/composite.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | xproto 31 | xfixes 32 | 33 | 34 | 35 | 0 36 | 37 | 38 | 1 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /xml/damage.xml: -------------------------------------------------------------------------------- 1 | 2 | 29 | 30 | 31 | xproto 32 | xfixes 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 40 | 41 | 1 42 | 43 | 44 | 2 45 | 46 | 47 | 3 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /xml/dpms.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 69 | 0 70 | 71 | 72 | 1 73 | 74 | 75 | 2 76 | 77 | 78 | 3 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /xml/ge.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /xml/res.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | xproto 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 47 | 48 | 1 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 66 | 67 | length 68 | 4 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | num_cross_references 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | num_clients 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | num_types 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | num_specs 141 | 142 | 143 | 144 | 145 | 146 | 147 | num_ids 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | num_specs 157 | 158 | 159 | 160 | 161 | 162 | 163 | num_sizes 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /xml/shm.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /xml/upstream/bigreq.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /xml/upstream/composite.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 30 | 31 | xproto 32 | xfixes 33 | 34 | 35 | 0 36 | 1 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /xml/upstream/damage.xml: -------------------------------------------------------------------------------- 1 | 2 | 29 | 30 | 32 | xproto 33 | xfixes 34 | 35 | 36 | 37 | 38 | 0 39 | 1 40 | 2 41 | 3 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /xml/upstream/dpms.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 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 | 69 | 0 70 | 1 71 | 2 72 | 3 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /xml/upstream/dri3.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 27 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | num_window_modifiers 111 | 112 | 113 | num_screen_modifiers 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | num_buffers 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | nfd 157 | 158 | 159 | nfd 160 | 161 | 162 | nfd 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /xml/upstream/ge.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /xml/upstream/res.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 30 | xproto 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 1 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 63 | 64 | length 65 | 4 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | num_cross_references 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | num_clients 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | num_types 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | num_specs 138 | 139 | 140 | 141 | 142 | 143 | 144 | num_ids 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | num_specs 154 | 155 | 156 | 157 | 158 | 159 | 160 | num_sizes 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /xml/upstream/shm.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 30 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /xml/upstream/xc_misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 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 | ids_len 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /xml/upstream/xevie.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 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 | 0 59 | 1 60 | 61 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /xml/upstream/xf86dri.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 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 | 69 | 70 | bus_id_len 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | client_driver_name_len 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | num_clip_rects 140 | 141 | 142 | num_back_clip_rects 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | device_private_size 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /xml/upstream/xinerama.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 31 | 32 | 33 | 34 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | number 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /xml/upstream/xtest.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 31 | 32 | xproto 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 0 47 | 1 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /xml/upstream/xvmc.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | xv 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 | num 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | length 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | length 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 4 121 | 122 | 123 | 124 | length 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | num 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /xml/upstream_normalized/bigreq.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /xml/upstream_normalized/composite.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | xproto 31 | xfixes 32 | 33 | 34 | 35 | 0 36 | 37 | 38 | 1 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /xml/upstream_normalized/damage.xml: -------------------------------------------------------------------------------- 1 | 2 | 29 | 30 | 31 | xproto 32 | xfixes 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 40 | 41 | 1 42 | 43 | 44 | 2 45 | 46 | 47 | 3 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /xml/upstream_normalized/dpms.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 69 | 0 70 | 71 | 72 | 1 73 | 74 | 75 | 2 76 | 77 | 78 | 3 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /xml/upstream_normalized/ge.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /xml/upstream_normalized/shm.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /xml/upstream_normalized/xc_misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | ids_len 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /xml/upstream_normalized/xevie.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 0 59 | 60 | 61 | 1 62 | 63 | 64 | 65 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /xml/upstream_normalized/xinerama.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | 32 | 33 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | number 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /xml/upstream_normalized/xtest.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | xproto 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 0 47 | 48 | 49 | 1 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /xml/upstream_normalized/xvmc.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | xv 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 | num 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | length 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | length 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 4 121 | 122 | 123 | 124 | length 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | num 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /xml/xc_misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | ids_len 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /xml/xevie.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 0 59 | 60 | 61 | 1 62 | 63 | 64 | 65 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /xml/xinerama.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | 32 | 33 | xproto 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | number 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /xml/xtest.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | xproto 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 0 47 | 48 | 49 | 1 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /xml/xvmc.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | xv 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 | num 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | length 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | length 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 4 121 | 122 | 123 | 124 | length 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | num 142 | 143 | 144 | 145 | 146 | --------------------------------------------------------------------------------